1. 实验内容
(1)对pwn1文件,直接人工修改其可执行文件,使其从main函数提转到getshell函数而不是foo函数
(2)发现foo函数的漏洞,使用一个新的攻击字符串,覆盖foo函数的返回地址,使getshell函数能被执行
(3)自己制作一个shellcode,将其注入foo函数中,使得shellcode被运行
2. 实验目的
(1)掌握常用汇编指令的机器码、反汇编和十六进制编程器
(2)掌握GDB调试,能正确修改机器指令改变程序执行流程
(3)能正确构造payload进行bof攻击
3. 实验过程
3.1 实验环境准备
- 我在本次实验使用了linux系统,所以下载了老师提供的64位kali镜像,并挂载在VMware虚拟机上

- 在本地主机中,复制pwn1文件,直接粘贴在kali中即可

3.2 实验内容一:直接修改程序机器指令运行getshell
-
3.2.1 使用objdump反汇编pwn1文件,查看函数调用的具体指令

-
3.2.2 在其中找到关于main函数调用foo函数的指令如下

- 其中"call 8048491 "是汇编指令,说这条指令将调用位于地址8048491处的foo函数,其对应机器指令为“e8 d7ffffff”,e8即表示跳转,d7ffffff
表示foo函数的入口地址,所以我们只将getshell的入口地址替换到这里,即可跳转到getshell函数。
- 想要跳转到getshell,需要计算"getShell-80484ba"对应的补码,其中80484ba是正常下一指令的地址,所以计算47d-4ba,得到目标地址由
d7ffffff变为c3ffffff,最后直接修改可执行文件即可。
-
3.2.3 将pwn1备份为pwn20232405_1,修改pwn20232405_1文件中返回地址

- 检验是否修改成功,再次反汇编

- 修改成功后,运行pwn20232405_1文件,成功进入getshell!

3.3 实验内容二:构造输入参数,造成BOF攻击,改变程序执行流
-
3.3.1 通过反汇编,了解程序基本功能
- 我们发现foo函数在图中位置只留出来了28字节(0x1c)大小的缓冲区读取字符串,这很容易造成缓冲区溢出的攻击

- 通过gdb调试,向缓冲区中输入1111111122222222333333334444444412345678,如图观察到数据1234(0x34333231)会覆盖到EIP中,即1234会覆盖返回地址,所以我们只需要将1234的位置替换为getshell的入口地址,在输入到pwn20232405_2中,即可造成缓冲区溢出,执行getshell函数

- 由反汇编结果得,getshell地址为0x0804847d,我们没法通过键盘输入\x7d\x84\x04\x08这样的16进制值,所以先生成包括这样字符串的一个文件,通过perl,将输入的数据重定向到input文件中,用xxd检查是否写入

- 最后用cat将input20232405中的数据通过管道传入pwn20232405_2的输入,并运行后成功进入shell!

3.4 实验内容三:shellcode注入并执行
-
3.4.1 准备条件
-
(1)准备一段shellcode:\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\
-
(2)安装execstack:直接通过命令行apt install execstack安装即可

-
(3)设置堆栈可执行;关闭地址随机化
-
输入命令execstack -s pwn20232405_2设置堆栈可执行
-
输入命令execstack -q pwn20232405_2查看堆栈状态,输出X说明堆栈可执行设置成功

- 输入命令more /proc/sys/kernel/randomize_va_space后,若返回2说明地址随机化开启,若返回1说明地址随机化部分开启(堆、堆栈、库等),若返回0说明地址随机化关闭
- 如下图返回2,所以输入命令echo "0" > /proc/sys/kernel/randomize_va_space,将0写入文件中,进而关闭地址随机化

-
3.4.2 构造注入的payload
-
虽然缓冲区有28字节足够大了,payload应该采取nop+shellcode+retaddr的结构,但是根据实际操作发现,最后栈顶指针会把代码部分覆盖掉,导致注入失败,所以我选择了另一种结构retaddr+nop+shellcode
-
完善payload的内容并重定向到文件input_shellcode20232405中如下,其中\x4\x3\x2\x1代表返回地址,最后将替换为shellcode的起始地址

- 打开一个新终端作为攻击者,进行如图攻击(注意只需点一次回车)

- 再打开另外一个终端进行gdb调试pwn20232405_2
(1)找到pwn20232405_2的PID(第一行)

(2)启动gdb并使用attach+PID控制该进程

(3)查看foo函数内存并在ret设置断点,在攻击终端中再按一次回车,在gdb中输入c运行到断点,找到此时esp中的值为0xffffcfdc

(4)使用命令x/16x来可视化从esp开始的部分16进制的数据,观察结果发现了我们开始输入的payload数据,从\x4\x3\x2\x1开始的,这也证明了\x4\x3\x2\x1是正确的返回地址占位符,其后就是nop+shellcode,现在只需要找到shellcode的起始地址

(5)易得,从esp地址向后加4个字节即得到shellcode的起始地址(nop可以忽略,最后会滑到shellcode)即0xffffcde0

- 将上面input_shellcode20232405中输入的返回地址部分替换为(5)找到的shellcode起始地址,并再次重定向到该文件并检查

- 再次发动攻击,发现成功进入shell!

4. 问题及解决方案
-
问题1:在内容三中寻找返回地址时,攻击者输入攻击代码后,在另一个终端中找不到对应的进程
-
解决1:输入攻击代码后,只能按一次回车,不然会结束进程,就会导致无法找到目标进程
-
问题2:shellcode和retaddr两种结构都尝试后,都无法得到shell
-
解决2:使用shellcode+retaddr结构时,发现esp会覆盖到代码部分,导致运行错误;使用retaddr+shellcode结构时,发现同时在两个终端中开启了两个一样的进程,导致找到了不对应的esp,进而导致没找到shellcode,修改后即可
5. 学习感悟、思考等
这次实验让我收获了很多新知识、新技能,比如能够看懂常用的汇编指令和机器指令、学会反汇编和使用十六进制编程器查看十六进制的文件、对于管道和重定向的应用也更加熟练、掌握了如何找到返回地址以及对于栈的结构和缓冲区溢出的原理更加熟悉,在一次一次的失败与尝试中,我对于缓冲区溢出的知识愈发熟练,实际操作也能得心应手,可以说受益匪浅。
在实验过程中我也积累了很多经验,比如要细致入微,每一步都不能有一点差错,在内存中有一点差错,就可能会有成百上千的问题;还有做实验一定要理解实验的原理即为什么要这么做,这样才能够有所收获,同时也有助于遇到错误及时纠错,要抱有不懂就问的态度去做实验。
最后,对于我们以后的工作也很有帮助,在网络攻防实验中,我们学习了怎么攻击,同时我们也间接的学习了怎么防御,能够让我们在工作中避免被攻击。

浙公网安备 33010602011771号