1.实验内容
1. 本周学习内容
- 缓冲区溢出
- 缓冲区溢出原理:本质是数组的生长方向与栈的生长方向相反,且数组调用没有进行越界检查。
- 返回地址覆盖:掌握如何通过缓冲区溢出覆盖栈上的返回地址,以控制程序的执行路径。
- 返回地址位置:明确在函数调用过程中,返回地址是如何被存储在堆栈上的。
- 程序汇编与反汇编
- 汇编语言基础:能看懂简单的汇编代码,如指令调用call、数据移动mov等。
- EIP与指令地址:理解EIP(指令指针寄存器)的作用,以及EIP如何操作才能变成call需要的地址。
- Shellcode相关知识
- Shellcode编写:了解如何编写或获取一段用于执行特定操作的机器码Shellcode。
- Shellcode注入:掌握将Shellcode注入到目标程序中的方法,以实现特定的攻击效果。
- 地址随机化关闭:掌握如何关闭地址随机化技术,以稳定地找到目标程序的地址空间。
2. 实验目标
本次实践的对象是一个名为pwn1的linux可执行文件。
该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。
该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。我们将学习两种方法运行这个代码片段,然后学习如何注入运行任何Shellcode。
3. 实践内容
- 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
- 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
- 注入一个自己制作的shellcode并运行这段shellcode。
2.实验过程
1.实践一
- 下载文件pwn1并通过MobaXterm将其传入虚拟机,并将其重命名为pwn20232308
2. 反汇编
使用“objdump -d pwn1 | more”命令,反汇编并找到函数调用的相关指令。可以看到main中80484b5位置是跳转到foo函数的指令。
跳转指令中,e8是跳转的意思,d7ffffff为补码,表示当前地址+(-41),所以要调用getShell函数,需要改变后面四个字节。根据计算,应该是-61,即-0x3d,补码为c3ffffff。按照计算结果需将该条指令改为e8c3ffffff
3. 修改main函数中这一步调用函数地址
输入 :%!xxd转为16进制,/e8 d7查找(注意中间空格),切换到插入模式更改,:%!xxd -r转为原格式,:wq保存退出
再用反汇编命令objdump -d pwn20222318 | more查看,修改成功
4. 执行pwn文件,检验是否成功
2.实践二
- 反汇编,了解程序的基本功能
由上图可见foo函数只预留了56字节的缓冲区(0x38=3*16+8=56) - 确认输入字符串哪几个字符会覆盖到返回地址
考虑到此处需要用到编译、断点功能,顾需要下载编译器gdb。使用sudo apt-get update && sudo apt-get upgrade升级下载服务包,再用sudo apt-get install gdb下载gdb。下图为下载完后使用gdb --version查看是否下载完成
复制一份pwn文件,之后进行编译。使用字符串“8个1,8个2,8个3,8个4,8个5”作为输入,使用如图命令查看各寄存器的值。
可以看到EBP=0x34343434,0x34是ASCII码中的4,又EIP=0x35353535,是ASCII码中的5,可以确定最终覆盖在RET上的数字为5555
3. 确认如何输入才能将Shell的地址正确覆盖在返回地址上
使用字符串“8个1,8个2,8个3,8个4,12345678”作为输入
可以看到,EIP=0x34333231,即4321,确认为倒序
4. 构造输入字符串
不能通过键盘直接输入,所以先利用perl软件生成包括这样字符串的一个文件。
用“xxd input”命令查看文件内容,可以发现内容正确。
执行文件后可以看到出现了命令行,输入指令,任务二完成。
3.实践三
- 准备工作
需要用到execstack,但是我还没有下载,也没有找到相应的安装包。在同学的帮助下我知道可以使用sudo apt install patchelf启用栈执行(相当于 execstack -s)
patchelf --set-execstack pwn1验证是否成功
readelf -l pwn1 | grep GNU_STACK如果输出包含 RWE(Read-Write-Execute),说明栈可执行。如果只有 RW,说明栈不可执行(NX 保护开启)。
2. 构造Payload
这是一段用于攻击的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\。
这段shellcode是启动一个新的/bin/sh shell的机器码,用于后续的攻击操作。
做准备工作,设置堆栈可执行,关闭地址随机化
再打开另一个终端,先用ps -ef | grep pwn20222318-3查看进程号
用gdb调试这一进程。
通过反汇编foo,可以发现foo的结束地址是0x080484ae,在这里设置一个断点。
用“c”让程序继续后,在原本的终端中按下回车,让程序运行到断点,发现esp寄存器的内容为0xffffd3bc。以16进制格式显示从地址0xffffd3bc开始的一部分数据,发现此处便有注入的输入0x04030201,说明这个地址正是需要的地址。将栈顶指针地址再加4字节,就是shellcode应该处于的地址,即0xffffd3bc+4=0xffffd3c0。根据机器存储的方式,可以知道应当将“\x1\x2\x3\x4”更换为“\xc0\xd3\xff\xff”,将分析得到的shellcode保存至文件input_shellcode_6。
将input_shellcode_6作为pwn的输入,成功注入shellcode,获取到了shell。
3. nc模拟远程攻击
我用的是本机上的两个虚拟机,靶机为kali,攻击机为openEuler。二者互ping可通
靶机输入以下命令
nc -lvnp 1324 -e ./pwn20232308_5
攻击机
3.问题及解决方案
- 问题1:MobaXterm 无法连接上Kali虚拟机,无法传输pwn文件
- 问题1解决方案:通过询问ai以及联系操作系统实验中所学内容,使用sudo vi /etc/ssh/sshd_config命令修改ssh配置文件,将#TcpForwarding yes这一行以及以下四行的“#”都删去,然后将Gateway改成yes,再用sudo systemctl restart sshd重启ssh服务,再与MobaXterm建立连接即可。
- 问题2:需要用到execstack,没有找到相应的安装包
- 问题2解决方案:在同学的帮助下我知道可以使用sudo apt install patchelf启用栈执行(相当于 execstack -s)
patchelf --set-execstack pwn1验证是否成功
readelf -l pwn1 | grep GNU_STACK如果输出包含 RWE(Read-Write-Execute),说明栈可执行。如果只有 RW,说明栈不可执行(NX 保护开启)。 - 问题3:在进行nc远程模拟攻击的时候一直报错
- 问题3解决方案:通过询问同学以及在ai的帮助下换了一种方式来进行并最终顺利的解决了问题
4.学习感悟、思考等
经过本次实验我收获颇丰。首先这次试验是对我课内所学知识点的一个大考验,很多内容多要从底层去理解每一个字符表示什么含义,对我来说这是一项具有很大挑战的任务。实验分为三个层次,难度逐级递增,直接修改机器指令、进行bof攻击改变程序执行流、注入shellcode三种方式,重点考察了反汇编,机器码的阅读,缓冲区溢出攻击,shellcode的含义、作用与使用方式等等。其次本次实验很好的提高了我的动手实践能力,不仅仅体现在做实验的过程中会遇到与实验指导书不完全相同的情况,更体现在我需要借助互联网以及ai去搜集更多的资料来帮助我更好的理解题目、解决问题。
总而言之,通过本次实验,体验到了三种攻击方式,给了我很大的启发,也让我对网络攻防这门课有了更大的兴趣,我也更愿意投入时间与精力来解决一个又一个的问题。期待下一次的实验。
参考资料
- 实验指导书
- 一位优秀学姐的实验报告