标签:
缓冲区报告bufbombbufferoverflow |
分类: 学术讨论 |
UCLA CS33 Bomb
Lab (LAB3)
Overview
本次lab利用getbuf()方程不检查读取string长度的漏洞破坏该方程的return
address从而达到对主题程序造成破坏的目的
从getbuf() 的assembly
code我们可以看到
位于<0x8048c0a> 为预读的string
在stack创建了0x28(40)个Byte 的空间。具体位置可以通过gdb在下一行设置breakpoint 查找 eax
的值得到。
创建完毕后,此时stack frame
如下图
为了覆盖被存在Return Address上的值(4 Bytes
for m32 machine) 我们需要读入超过系统默认40Bytes大小的string 由于Saved ebp 占据了4
Bytes 所以当我们的input string 为48 Bytes时,最后4位Bytes 刚好覆盖我们的目标Return
address.
Notes:
由于我们在输入文件下写入的都是character(字符)因此我们需要利用hex2raw这个小程序帮助我们将我们写入的character转换成所对应的二进制数列
Phase 0:
此Phase 目标在getbuf()结束后跳入方程smoke()
而非按照设计return 回test()
我们只需要找到smoke()的地址,用该地址覆盖getbuf()原方程上的return
address
经过查找
smoke()地址为0x080490aa
攻击文件如下:
需要注意的是由于服务器系统为 Little Endian
我们需要将地址以Byte为单位相应颠倒变为aa 90 04 08
Phase 1:
Phase1 和 Phase0
大同小异,唯一的区别是本次要求跳入方程 fizz(int) 且该方程有一个argument
(要求用所给cookie作argument)
我们知道在执行完ret指令后stack pointer %esp
会自动增加4以清空原方程
通过查找fizz()得知
1.
fizz()地址为0x0804905f
2. 由于第一步push ebp 导致%esp 减4 并将ebp
= 该位置(此位置即为getbuf()中 ret address)我们看到argument 为ebp+8
因此argument的位置即在getbuf() ret address往上的第二行
攻击文件如下:
argument 同样需要reverse order
以适应little endian系统(我的cookie是0x4195b522)
Phase 2:
phase 2的难度开始增加,除了需要跳转至目标方程bang()
地址为0x08049012
我们还需要执行一些自行设计的指令
该phase我们需要将global_value
改成我们的cookie
通过objdump -D bufbomb | less
(注意D要大写我们才能看到header的代码 -d不会显示)
global_value的地址是0x0804c1ec
目前该位置的值为 0
cookie
的地址是0x0804c1e4 目前该位置的值为
0,程序运行后会变为cookie的值
攻击指令如下:
由于是Assembly code 不需要考虑 little
endian的问题
先将global value 用move 变为cookie
(0x0804c1ec 前不加$ 表示地址)
然后将bang() 方程地址
0x8049012写给esp,再执行ret指令时,程序自动跳入bang
指令 gcc -m32 -c p2.s 将assembly
code写成machine code -->p2.o
再用objdump -d p2.o 读取machine
code
将指令代码抄入攻击文件
除此之外我们还需要找到input
string存放的位置作为第一次ret 指令的目标位置(corrupted ret address)
方法见Overview
经过查找我的位置是0x55683608
攻击文件如下:
Phase 3:
不同于之前跳入其他方程,在本phase中我们希望getbuf() 回到原本的位置(即call
getbuf()后的下一行)
我们注意到getbuf()
在0x8048c8e被执行因此正确的跳转地址为 0x8048c93

只是我们需要更改getbuf的return value
(将cookie mov 进eax)攻击指令如下:
为了使攻击更加具有迷惑性我们还希望saved
ebp被复原,这样一来原程序就完全不会因为外部攻击而出错崩溃
在getbuf()中stack内所存放的saved
ebp正是test()的ebp的值
因此可以通过在0x8048c8e设置breakpoint查看ebp获取,方法如下
可以看到saved ebp的值为 0x55683660
所以我们需要将它写入正确的位置,使得overflow的覆盖对该位置无效
攻击文件如下:
需要注意ebp存放的是一个4 Byte
的地址值因此在被写入stack的时候 需要按照little endian reverse order
Phase 4 (Extra
Credit):
phase 4和phase 3 大体目标一致。只是这一次我们再call 主方程时加入 - n
flag 进入Nitroglycerin
模式,执行testn()方程而非test()方程,而且重复执行五次,因此每次在stack为input
string预留的位置呈现动态分布,而且saved ebp的值也因为每次执行位置的不同而变化。
因此要想像Phase 3那样强行保留old ebp 并直接ret
至machine
code的位置是不可能的。
解决方法就是
1. 用assembly instruction —— nop
(machine code:90)填充我们的Input string。
这样一来在一定范围内无论在哪里进入我们的攻击程序执行指令最终都会滑到我们的攻击方程。
2.
虽然ebp的值每次变化,无法直接赋值,但是在getbufn()程序中
ebp和esp值差是一定的通过gdp查找我们可以查到这样的关系,笔者的情况是相差0x28
3. 通过空input运行主程序发现五次input
string的存储位置在0x556835e4 到0x55683684之间,因此如果我们将第一次ret address
定为最高的0x55683684那么就可以保证五次运行执行命令都不会在运行攻击程序之前遇到除nop(90)之外的其他指令
攻击文件如下
最坏情况就是0x55683478指向红色箭头位置,最好情况指向input string
的开头
需要注意的是因为在Nitro模式下主方程需要读五次input以满足执行五次的需要
因此在执行./hex2raw程序是请注意添加 -n
flag以保证input string 被复制五次每次以\n结尾以结束每次的gets() function
call
Good Luck!
5/9/2013
后一篇:从一道数学题说起
后一篇 >从一道数学题说起