计算机系统实验-BufLab

news2025/4/18 9:59:17

一.实验题目及目的

1.实验题目

       程序运行在linux环境中,从输入获得一个字符串,将这个字符串放入指定的buf处,buf的大小为32,需要分析栈帧、buf位置等信息,通过输入字符串使缓冲区溢出,完成指定的函数调用等目标。

2.实验目的

       通过缓冲区溢出,熟悉函数调用的过程和栈帧结构的建立等。

二.实验内容

1.实验文件及实验准备

       实验文件共有三个,bufbomb,hex2raw,makecookie。bufbomb是需要进行缓冲区溢出攻击的文件。实验过程需要用到userid和对应的cookie,cookie使用makecookie生成,hex2raw用于将16进制数据转换为字符串输入。

       在实验中使用学号202004061409作为userid,cookie为0x73b099ff,并将bufbomb反汇编保存到文件中进行分析。

2.实验过程

       getbuf函数如下,缓冲区大小为32,调用了Gets()。

(1)Level0:Candle

       要求输入字符串使getbuf()不正常返回,而是执行smoke()函数.

       getbuf()函数在test中调用。

       getbuf的汇编代码如下:

       getbuf中调用了Gets,并将缓冲区地址作为参数传入,根据getbuf的汇编代码,buf的起始位置为ebp-40的位置,而根据栈帧建立的规则,返回地址的位置在ebp+4,故只需要向缓冲区写入48个字节的内容,就可以覆盖修改返回地址,为了调用smoke()函数,将返回地址修改为smoke()的地址,即08048e0a。

       因此输入的数据最后四个字节为0a 8e 04 08。0a会被当作\n,因此修改为smoke的第二条指令地址,即0a修改为0b。

       新建文件输入16进制数据如下:

       使用hex2raw将其转换为字符串数据输入,成功调用smoke()。

(2)Level1:Sparkler

       Level1要求输入字符串后调用fizz()函数,并需要将cookie值作为参数传入,代码如下:

       Fizz()的汇编代码如图所示,userid对应的cookie值位于0x804d104,传入的参数cookie在ebp+8的位置。需要找到fizz建立的栈帧的ebp的值。在getbuf返回前,执行了leave指令,leave指令等同于mov ebp,esp;pop ebp。然后执行ret指令进入fizz还会执行pop eip,因此在进入fizz()前,esp的值为原getbuf()函数的ebp+8。由于fizz不是由call指令调用的,没有返回地址入栈的过程,进入fizz()后,ebp入栈使esp的值-4,因此getbuf的ebp+8-4就是新的ebp的值,即新的ebp为getbuf的ebp+4。所以只要将getbuff的ebp +12的位置写入正确的cookie值,就可以向fizz()传入正确的cookie值。

       因此向缓冲区写入56个字节的内容,45-48字节为fizz()的地址,53-56字节为0x73b099ff,新建文件,16进制数据如下:

       转换为字符串输入,成功调用了fizz()并传入了正确的cookie值。

(3)Level2:Firecracker

       这一次需要调用的是bang()函数,如下:

       bang函数使用了全局变量,需要将全局变量global_val设置为cookie值。

       需要在getbuf返回时先跳转到一段代码,在这段代码中设置global_val为cookie值,然后将bang的地址入栈,通过ret指令跳转执行bang()。最后的跳转使用ret是因为call和jmp指令使用PC相对寻址,难以设置正确。

       bang()的汇编代码如下,global_value的地址为0x804d10c,需要把cookie值写入这个地址。

       把cookie值写入global_value并跳转执行bang()需要执行以下指令:

       将这段代码编译,再反汇编得到这段代码的机器码:

       只需要将机器码写入buf,在getbuf返回时跳转到buf的起始位置,执行这些指令就可以了。buf的位置是esp-40,只能通过gdb调试找到运行时的位置。

       gdb调试将断点打在0x804926b的位置,此时正在向Gets()传参,eax中的值为esp-40。这个值为0x556834e8。

       同(1)中相同,向缓冲区写入48个字节的数据,开头为需要执行指令的机器码,,且机器码不需要考虑大小端,44-47字节为buf的首地址0x556834e8:

       转换为字符输入,调用bang()成功。

(4)Level3:Dynamite

       Level3需要完成的任务是在执行getbuf()后,将getbuf()的返回值修改为cookie值,并返回到test()函数,同时恢复被破坏的栈。

       类似于level2,通过缓冲区溢出在getbuf()返回时跳转到一段代码,在这段代码中完成getbuf返回值的修改,栈的恢复,最后使用ret指令返回到test()当中。恢复到test()函数的栈帧,需要恢复ebp的值,在getbuf()返回前会在leave指令中pop ebp恢复旧的ebp值,但是这个值被复制进缓冲区的字符覆盖掉了,因此需要找到ebp的值并恢复。

       修改返回值只需要将cookie值放入eax寄存器就可以了。恢复test()函数的ebp的值需要使用gdb调试找到,将断点设置在0x8048e40处,此处test()函数的栈帧已经建立。找到ebp的值为0x55683540。在指令中给ebp赋值或者在输入的字符串直接将这个值写入存放旧的ebp的位置都可以完成栈的恢复。

       最后是使用ret指令返回test(),返回到call getbuf的下一条指令处0x8048e50。最终需要执行的汇编代码如下:

       反汇编得到机器码如下:

       最终输入的字符串的16进制形式如下:

       转换为字符输入,结果如下:

(5)Level4:Nitroglycerin

       本关与level3中任务相同,不同的是使用-n标志运行程序,会调用testn(),在testn()中调用getbufn()五次,且缓冲区的大小为512字节。每次getbufn()的栈空间随机,因此不可以再使用level3中的方式找到buf的起始位置,但栈帧结构是相同的,可以利用这一点找到buf的大致位置。

      buf的地址

       首先先找到buf的大致位置,确保可以跳转到这里执行需要执行的指令。

       getbufn的汇编代码如下,buf的首地址是ebp-0x208。

       接下来进入gdb调试,将断点打在0x8049247,此处getbufn的栈帧已经建立完毕:

       五次调用getbufn,buf的首地址如下:

       0x55683308

       0x556832c8

       0x55683318

       0x55683308

       0x55683358

       因此可以找到buf首地址的大致范围0x556832c8-0x55683358。

       改写getbufn的返回地址只能跳转到一个固定的地址,如何在跳转到固定地址后能够执行需要执行的指令,需要使用nop指令,利用一种nop sled的方式实现。nop sled就是在实际攻击代码前插入多条nop指令,nop指令只对PC+1,只要可以跳转到nop指令的部分,就可以一直执行到实际的攻击代码处并执行攻击代码。以上已经试探过了buf首地址的大致范围,选取首地址最大的0x55683358处,跳转到这里就可以保证进入缓冲区,然后在写入的数据中先插入nop指令,把攻击代码放到后面就可以了。

需要执行的代码

       能够保证跳转到合适的位置,接下来就可以准备需要执行的代码了。需要完成的工作为修改getbufn的返回值,恢复testn的ebp,返回testn。其中修改返回值和返回testn与level3相同。

       恢复testn的ebp可以通过观察testn与getbufn的栈帧情况进行处理。testn的部分汇编代码如下:

       结合getbufn的汇编代码,可以得出getbufn的栈帧关系如下:

       在getbufn返回前执行的leave指令将ebp的值赋给esp,然后弹出testn的ebp(已被覆盖),然后通过ret指令pop eip跳转执行指定的指令,esp+8。getbuf调用前后,esp的值是不变的。因此要恢复testn的ebp,只需要将esp+0x28赋值给ebp。

       最终需要执行的代码如下:

       编译后反汇编如下:

       因此最终输入的数据如下,共528个字节:

       由于getbufn执行5次,需要5次以上数据的输入,使用0a(\n)分隔。转换为字符后输入,目标完成。

三.实验总结

      通过本次实验,加深了对缓冲区溢出的理解,并学习了解了缓冲区溢出攻击的方法,更加熟悉了函数调用时栈帧建立的过程和栈帧情况。其中最主要的是理解了缓冲区溢出攻击的方式,即通过溢出覆盖返回地址跳转到一段设定的程序进行执行,并可以通过恢复寄存器的方式恢复栈帧,以及应对动态堆栈的nop sleds方法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/89009.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

聊聊什么是gRPC

前言 现如今,微服务变得越来越流行,而服务间的通信也变得越来越重要,服务间通信本质是交换信息,而交换信息的中介/桥梁正是我们的API。 诚然,目前构建API最受欢迎的仍然是使用Restful(HTTP-JSON&#xff…

我学Python的那段日子(一)变量和简单数据类型

1.Python中的变量和简单数据类型(一) 1.1关于Python中的输出函数 使用 print()如: print("Hello,Python");在ide中显示的结果为 1.2 Python中的变量 所谓的变量即是可以用来保存数据的一个参数,变量的值是可变的。…

最短木板长度 华为OD真题 100

import java.util.Scanner; import java.util.*; import java.util.stream.Collectors;class Main {public static int min_num;public static void main(String[] args) {// 处理输入Scanner in new Scanner(System.in);int n in.nextInt();int m in.nextInt();in.nextLine…

小蓝本 第一本 《因式分解技巧》 第七章 综合运用 笔记 (第七天)

小蓝本 第一本 《因式分解技巧》 第七章 综合运用 笔记 (第七天)前言换元法好题例2题目解法经验补充例3题目解法经验例5题目解法补充例9题目解法经验补充例10题目解法补充例11题目解法补充例13题目解法习题7题目题解错题题号改错前言 12天攻掉《因式分解…

【笔记】计算机组成原理复习重点——篇1

计算机组成原理复习重点笔记 计算机组成原理计算机体系结构 学科基础必修课 研究生入学考试全国联考45分,占比30% 64学时,4学分,上课56,实验8 教材:计算机组成原理(第二版 ) 唐朔飞 高等教育出版社 目录 第1篇 概论 第…

如何确保RabbitMQ消息的可靠性?

开启生产者确认机制,确保生产者的消息能到达队列 开启持久化功能,确保消息未消费前在队列中不会丢失 开启消费者确认机制为auto,由spring确认消息处理成功后完成ack 开启消费者失败重试机制,并设置MessageRecoverer&#xff0c…

前端框架搭建(二)导入静态资源【vite】

1.根目录下创建styles目录 这里可根据你项目中的样式文件类型创建,因为这里我只有一个css没有scss 2.css目录下创建如下文件 global.css:全局所有的样式入口scrollbar.css:滚动条样式transition.css:动画样式 global.css impo…

Web3中文|盘点进军Web3的国际著名体育联盟

纵观如今的文化娱乐业,体育是最适合利用NFT实现粉丝参与和互动的领域。 NFT可以定格体育迷最喜欢的赛场高光时刻、记录体育迷所支持的球队或球星的美好瞬间,体育迷甚至还可以通过NFT体验交易收藏品的乐趣。 想知道这是怎么回事吗?让我们来粗…

查询 Linux 命令属于哪个软件包

在 Linux 中,有些命令的名称软件包的名称是不一样的,或者一个软件包中包含有多个命令。有时候,我们需要确定某个命令来自于哪个软件包,以便于可以在其他机器上安装,或者寻找该软件包的源代码进行编译或者修改。 下面以…

达美乐披萨:一家把自己“送”上市的企业

一、公司简介 达势股份,是知名披萨品牌在中国大陆、中国香港特别行政区和中国澳门特别行政区的独家总特许经营商,截至日前,公司在中国大陆14个城市拥有569家直营门店。 二、基本面分析 2.1 财务数据,扩张与亏损并存 **营收方面&a…

Sa-Token浅谈

主要介绍Sa-Token的鉴权使用以及实现原理。 文章目录简介使用源码解释创建会话1.前置检查2.获取配置3.分配token4.获取 User-Session5.设置token-id映射关系6.登录成功事件发布7.检查会话数量客户端注入Token简介 官网介绍的非常详细,主要突出这是一个轻量级鉴权框…

23个常见的 JavaScript 函数

本文收集了23个日常开发中非常常用的功能,其中一些可能很复杂,另一些可能很简单,但我相信它们都会或多或少对每个人都有帮助。 01、生成随机颜色 当网站需要生成随机颜色时,我们可以通过以下代码来执行此操作。 02、数组重新排序…

文件包含漏洞包含日志文件获取Shell实战

今天继续给大家介绍渗透测试相关知识,本文主要内容是文件包含漏洞包含日志文件获取Shell实战。 免责声明: 本文所介绍的内容仅做学习交流使用,严禁利用文中技术进行非法行为,否则造成一切严重后果自负! 再次强调&#…

Vue渲染器(四):双端diff算法

渲染器(四):双端diff算法 在上一章中,我们介绍了简单diff算法的实现原理。它利用vnode的key属性,尽可能多地复用DOM,并通过移动DOM的方式来完成更新,从而减少不断地创建和销毁DOM元素带来的性能…

(python + 雷电模拟器)frida下载与安装

frida下载 我这边是用pycharm下载的 我是直接下载最新的,暂时没发现什么异常 在安装成功界面查看frida版本 此时电脑端frida下载完成。打开github,搜索到frida,点击发行版 根据你的frida版本,对url进行修改进入你需要的版本…

方格涂色(冬季每日一题 30)

给定一个 nnnnnn 的方格矩阵,最初所有方格都是白色的。 现在需要将矩阵边界上的一些方格涂成黑色,从而使得: 最上一行恰好有 UUU 个方格是黑色的。最右一列恰好有 RRR 个方格是黑色的。最下一行恰好有 DDD 个方格是黑色的。最左一列恰好有 …

Android入门第47天-Fragment的基本使用

简介 我们的Android入门一步步已经进入中级。我们讲完了所有的基本组件的基本使用、Activity、Service、BroadCast。今天我们来到了Fragment篇章。Fragment和Activity比到底是一个什么样的存在呢?我们以一个很小的例子来说通Fragment。 Fragment是什么 Fragment可…

智能家居DIY系列之智能灯泡

一、什么是智能灯 传统的灯泡是通过手动打开和关闭开关来工作。有时,它们可以通过声控、触控、红外等方式进行控制,或者带有调光开关,让用户调暗或调亮灯光。 智能灯泡内置有芯片和通信模块,可与手机、家庭智能助手、或其他智能…

浅析JWT Attack

前言 在2022祥云杯时遇到有关JWT的题,当时没有思路,对JWT进行学习后来对此进行简单总结,希望能对正在学习JWT的师傅们有所帮助。 JWT JWT,即JSON WEB TOKEN,它是一种用于通信双方之间传递安全信息的简洁的、URL安全…

创新研发负载分担机制,天翼云IPv6网络带宽再升级!

网络作为社会信息化的基础,已成为人们日常生活不可或缺的一部分。网络通过模拟信号将信息转为电流进行传播,在这个过程中,网卡便充当了解码器的作用,能够将电信号转换为计算机能够识别的数字信号。 网卡,即网络接口卡&…