文章目录
-
- Lab 总结博客链接
- 前引
- 实验前准备
- Part I: Code Injection Attacks
-
- Test 1
- Test 2
- Test 3
- 结尾
Lab 总结博客链接
CSAPP Lab入门系统安装摸索 + Lab 博客链接
前引
前段时间才把Bomb Lab做完 然后就认为第三章是没有Lab可以做了
之后在到现在的一段时间 人是比较懒的 玩游戏玩疯了 作息也比较不规律qwq 每天1-2点睡觉 早晨10-11点起床 早饭不吃 午饭晚饭点外卖 捏?
反正我是真麻了 尽管说人是需要休息 毕竟寒假期间 春节也才刚刚过完 但是是不是也不能那么颓靡 至少人总有一个时间是会回顾之前经过的那么多天 还是要做点正事的
同样这个Lab也是之后我在玩的时候
翻博客 想一下CSAPP后面还有什么Lab需要做的时候
我看了看结果发现第四章真的要花很多功夫才能看得完
而且第三章还有个Attack Lab没做!
但我们y1s1 Apex确实好玩 这种现象级游戏怎么感觉走不太起来呢?
实验前准备
关于这个Lab 我是只做了Ctarget部分 后面对于我来说
没有很多做的动力了 Bomb Lab相对我更感兴趣
所以如果是想看后面的 Rtarget部分的可以移步去看其他博客了
如果是还没有做Lab 和 关于这个Lab怎么做一脸茫然可以继续看下去了
首先我们还是需要解压 Attack-Lab 解压出来六个文件
然后我们依然需要ctarget的汇编文件 在终端输入
objdump -d ctarget > ctarget.asm
关于这个实验是有 官方文档的 我这边提供一个链接 可以下载到本地
然后你可以移到虚拟机里面查看
CSAPP Attack Lab官方实验PDF
然后我们把它复制到虚拟机中 方便查看
接着介绍一下一些文件的作用
cookie.txt是我们通过一些Phase需要用到的字符串…
hex2raw是Lab提供我们把16进制数转字符串的
ctarget就是Phase1-3
rtarget就是Phase4-6
对于一些指令我在后面进行实验的时候也会具体说明的
还有一点最重要的 就是如果gdb调试的话 后面要加-q
因为好像 如果运行测试会联网上传成绩 那我们连打都打不开了
我们就需要在后面加一个-q 后面我还会讲的
Part I: Code Injection Attacks
Test 1
我的英语水平并不是能够一眼就把文档看懂 :( (悄悄说 英语高考的时候是我英语顶点水平)
然后通过囫囵吞枣我们看到了这个官方文档给出的函数
这个是什么意思呢 我们再去看一下汇编 关于这个函数的
很显然 因为Ctarget就是让我们通过 缓冲区溢出来达到实验目的
我们可以很理智的推断 这个sub $0x28,%rsp
40个字节数就等于最大我们输入字符串的 空间了 如果比40个字节数更大了
则发生缓冲区溢出 ok 我们来到Test1
这个就是关于Test1的图片
具体英文我就不翻译了 通过条件就是 我们需要在输入了字符串后
要经过touch1 函数部分
如果缓冲区不溢出 我们在运行test函数后 就结束了 怎么可能能到touch1函数部分呢
我们进入汇编 一探究竟
我们首先分析一下
当我们缓冲区溢出时 首先一个函数在调用另外一个函数时 我们首先需要
把我们的下一条指令位置在栈上保存下来 然后再为另外一个函数提供新空间
当另一个函数结束时rsp就能依然回到这个保存的位置处了 是这个道理吧
那我们缓冲区一旦输入达到40个字符时
我们再输入的字符如果是 0x4017c0((touch1)的第一跳指令位置)
就会把之前函数保存的位置覆盖掉 那么当Gets函数结束后 是不是跳转
就会跳转到 touch1了呢?
感觉到位了 即可开冲!
这里我们需要用Vim来写我们的40个字符+返回地址
先在终端输入 Vim
如果没有安装的话 根据下面提示の指令自己安装即可
然后我们不妨先创一个 Hex1.txt 的 16进制文件
因为Hex2raw可以使16进制转成字符 则我们先创建一个就ok了
在终端输入
vim Hex1.txt
如果现没有Hex1.txt文件的话 会自动新建文件的
快速保存时 先esc 再加上 shift+z+z
然后我们直接输入40个16进制数 随机即可
后面再加上 0x4017c0 (注意为小端法)
之后我们保存完了 我们可以看见文件多了个Hex1.txt 打开如图
此时我们不妨此时测试一下
测试指令如下 我们通过管道导入Hex2raw 再测试
./hex2raw < Hex1.txt | ./ctarget -q
-q为不联网
注意 result旁边的四个字母 PASS 说明我们已经拿下了Test1
如果有问题的话 旁边会显示FAIL 就还需要再调试一下哈 ?
拿下!
Test 2
Test2这边是需要 进入Touch2函数 然后并且要求输入的字符串还得是
我们Cookie文件中的字符串相匹配
我们接着看下面的事项
这里我就捡重要的拿出来说
我们的Cookie字符串需要储存在%rdi寄存器中
所以我们可以得到下面的结论 我们首先需要把字符串送到寄存器
rdi中 然后我们再进入touch2函数中 即可过关
在理清思路后 我们首先需要搞懂一个地方
就是 不管是数据 指令 存储地址 命令 Anyway
对于计算机来说都是 二进制数字 只是相对于我们不同罢了
而对于计算机如何判断这些 应该是这些二进制数是如何排布的
我们的栈指针 指令 数据指针只向的是哪处
那么我们能不能这样想 当我们存储字符时 我们能不能直接储存命令
储存的命令含有
1、我们把字符串cookie mov进rdi寄存器中
2、进入touch2函数
我们先把命令存储在一个我们40个字符区间中 然后我们在像上一步
返回地址设置为我们的储存命令区间
返回时 我们的处理器在处理机械码的时候 就开始运行指令了
ok 思路分析清楚了 那我们如何得到指令的机械码呢
我们这个时候就需要再在vim中编写 InjectCode1.s文件
编写汇编之后我们再反汇编 就可以得到机械码了
输入指令
vim InjectCode1.s
然后我们想一下第一行应该是不是把字符串cookie mov进rdi寄存器中
ok 下一行呢 我们是不是应该转入到touch2函数中去了
这个时候我们首先再思考一下
我们如果push了我们touch2的地址
再retq 是不是等于我们进入了touch2函数
仔细思考一下 这里应该不是难题
先看看touch2的地址
没有问题了吧 之后的指令就是得到机械码了 我们先保存下来
我们先在终端输入
gcc -c InjectCode1.s
会生成目标代码InjectCode1.o 目标代码 接着反汇编输入指令
objdump -d InjectCode1.o > InjectCode1.txt
就会生成一个Txt文件 打开即可得到 左边的机械码
我们基本上搞定了大部分的东西了 但是我们是不是还需要找到
我们的40个字符开栈的位置呢?
这个时候就需要gdb调试了
我们先用gdb预加载gdb ctarget
我们先设置断点在0x4017a8处 然后看一下%rsp
得到%rsp此时为 0x5561dca0
开栈40字节 我们做个减法 0x5561dca0-0x28 = 0x5561dc78
则我们的40字节开头就为0x556178位置
我们所有信息都得到了
我们不妨可以就把 指令就放到开头位置(即0x556178位置)
那么我们设置返回地址也很方便
下面我的vim Hex2.txt我就省略了
我只把结果放出来
输入指令
./hex2raw < Hex2.txt | ./ctarget -q
ok 拿下~
Test 3
先给出官方文档截图
现在这部分是我大二开学的时候敲得 这部分之后的算是二次编辑了 因为这部分在当时没有做出来 原谅一哈我哈 因为当时还是大一的寒假 = = 做不出来情有可原 现在已经大二了 而且在暑假的时候做了个操作系统 对栈的理解相对来说又要更好了 所以就重新来做这部分的内容了
上面的思路 我之前写的可能写的不是很好 因为之前没有怎么理解这部分的内容 那现在我就再重新写一下吧
对于Touch3
这部分 我们其实主要目标就是把%rdi
存放着Cookie
的字符串指针 然后我们跳转到Touch3
即算成功 当然我们需要自己存放字符串 存放的位置我们过会再讲
对于字符串 原本的16进制字符串是0x59b997fa
我们的char*
指针只不过是存储字符串59b997fa
本来数字具象化变成了真正意义上的字符 则其对应的字符码为‘5’ = 0x35 ‘9’ = 0x39 ‘b' = 0x62 '9' = 0x39 '9' = 0x39 '7' = 0x37 'f' = 0x66 'a' = 0x61
相对应的ASCII字符码写为0x35 0x39 0x62 0x39 0x39 0x37 0x66 0x61
对于字符串部分就说清楚了 那我再来说说我们怎么打算储存cookie
字符串的 我们看官方文档中 写了一部分话 Pay Attention:
When functions hexmatch and strncmp are called, they push data onto the stack, overwriting portions of memory that held the buffer used by getbuf. As a result, you will need to be careful where you place the string representation of your cookie.
意思是 我们最后在Test3
中 会push数据进入堆栈 所以我们需要注意我们的cookie
字符串的存放位置
那我们就可以不考虑放到那40个字符的堆栈里面了 那个40个字符我们用来存放命令正好 那我们的字符串可以考虑放到get
的栈帧中 即是越过40个字符的上方 因为我们不再返回了 所以那部分就不会被触碰到了
至于为什么getbuf
被分配的栈帧会被hexmatch
strncpy
推入的数据覆盖 按理来说 堆栈push data
应该是向下的拓展 我们的rsp
按理来说 应该是在最低处 怎么会被覆盖- - 我也很疑惑 但是想了半天还是没想出来 就算了 就按照上面的问题来解决
这里的解决办法跟Phase 2
差不多 只不过是多了个字符串存储 把具体位置放进%rdi
而已 那我们先编写汇编函数 对于我们栈顶的8字节 是retq
返回地址 那我们的指针地址则是栈顶+8字节 字符串也是放在那里
之前通过gdb
断点得到了 栈顶0x5561dca0
touch3
的入口地址0x4018fa
编写的汇编如下 我们再编译 反汇编得到机器码
gcc -c attack2.s
objdump -d attack2.o > attack2.txt
注入代码
mov $0x5561dca8,%rdi
pushq $0x4018fa
retq
编译后的机器码
attack2.o: 文件格式 elf64-x86-64
Disassembly of section .text:
0000000000000000 <.text>:
0: 48 c7 c7 a8 dc 61 55 mov $0x5561dca8,%rdi
7: 68 fa 18 40 00 pushq $0x4018fa
c: c3 retq
机器码已经得到了 那就最后组合一下机器码 即可
48 c7 c7 a8
dc 61 55 68
fa 18 40 00
c3 00 00 00
01 01 01 01
01 01 01 01
01 01 01 01
01 01 01 01
01 01 01 01
01 01 01 01
78 dc 61 55 00 00 00 00
35 39 62 39 39 37 66 61 00
最后./hex2raw < hex1.txt | ./ctarget -q
成功完成^^
结尾
因为这里是二次编辑 对于Rtarget
这部分已经完成了
对于接下来部分感兴趣的 就下篇博客再见啦~
就这样吧