SEED实验——return-to-libc实验

实验概述

本实验的学习目标是让学生获得缓冲区溢出攻击的一种有趣变体——return-to-libc攻击实验的亲身体验。这种攻击可以绕过目前在主要linux操作系统中实现的现有保护方案。利用缓冲区溢出漏洞通常的方法是使缓冲区溢出,然后在溢出部分的返回地址指向一段恶意的shellcode,使程序跳转到存储在堆栈中的shellcode。为了防止这些类型的攻击,一些操作系统允许管理员关闭堆栈的可执行功能。因此跳转到shellcode将导致程序失败。不幸的是,上述保护机制不是足够安全的。存在一种成为return-to-libc攻击的缓冲区溢出攻击的变体,其不需要可执行堆栈,甚至不需要shellcode。相反,它会导致受到攻击的程序跳转到一些现有的代码。例如已经加载到内存中的libc库中的system()函数。在这个实验中,学生被给予一个包含缓冲区溢出漏洞的程序,他们的任务是利用该漏洞,开发一个返回到libc库函数的攻击,最终获得root权限。除了这些攻击之外,学生们还将参与学习在ubuntu中实施的防止缓冲区溢出攻击的几项保护措施。学生需要评估方案是否有效,并解释评估过程。


 

第二部分:实验任务

该实验共有三个任务:

  • 漏洞利用
  • 地址随机化
  • StackGuard保护机制

任务一:漏洞利用

1.编译代码是关闭地址随机化机制和非执行栈机制

sudo sysctl -w kernel.randomize_va_space=0         //注意:这里等号和0之间不能有空格

   在进行代码编译时,加上-fno-stack-protector,即可关闭ubuntu上StackGuard保护机制,加上-z -execstack/noexecstack即可打开或关闭可执行栈的机制。

  在本实验中,我们按照如下命令编译含有缓冲区溢出漏洞的代码段:

   su root

   gcc -fno-stack-protector -z noexecstack -o retlib retlib.c

   chmod 4755 retlib  /  chmod u+s retlib

   exit

  

2.获取/bin/sh地址

  为了获取/bin/sh的内存地址,需要编写一个程序。

//getenvaddr.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc,char const *argv[])
{
    char *ptr;
    if(argc<3)
    {
        printf("Usage: %s <environment var> <target program name>\n", argv[10]);
        exit(0);
     }
    ptr = getenv(argv[1]);
    ptr += (strlen(argv[0]) - strlen(argv[2])) * 2 ;
    printf("%s will be at %p \n", argv[1], ptr ) ;
    return 0;
}

  其中,getenv的参数为一个环境变量,因此我们需要创建一个环境变量来记录路径export BIN_SH="/bin/sh"。调用程序./getenvaddr BIN_SH ./retlib得到/bin/sh的地址。

如上面截图所示,/bin/sh的地址为:0xbffffe39。

3. 获取system()和exit()地址

  这两个程序是驻留在内核态的,所有程序共享内核态的函数,因此我们可以用gdb来获取这两个程序的地址。

如上图所示,在main函数设置断点,然后运行,运用gdb调试命令,我们可以得到system()函数的地址是0xb7e5f430,exit()函数的地址是0xb7e52fb0。

将上述获得的三个地址写到代码中,


 

第三部分:

实验指导:了解函数调用机制

3.1 获取libc库函数的地址

用gdb命令进行获取。

3.2 将shell字符串放在内存中

本实验的一个挑战是将字符串“/bin/sh”放入内存中,并获取其地址。这可以使用环境变量来实现。执行C程序时,它会继承执行它的shell的所有环境变量。环境变量SHELL直接指向/bin/bash并且环境变量同时也被其他程序需要。所以我们引入一个新的shell变量MYSHELL,并指向zsh。

$ export MYSHELL = /bin/sh

我们将使用该变量的地址作为system()函数调用的参数。这个变量的位置在内存中使用以下代码就可以发现:

 

void main()
{
    char 8shell = getenv("MYSHELL");
    if(shell)
    prinf("%x\n",(unsigned int)shell);
}

如果地址随机化被关闭,将会发现打印出的地址是相同的。然而,当您运行漏洞程序retlib时,环境变量的地址可能与通过运行上述程序获得的地址完全相同。当您更改程序名称时,这样的地址甚至会更改(文件名中的字符数不一样)。好消息是,shell的地址将与上述程序打印出来的地址相当接近。因此,您可能哟啊尝试几次才能成功。

3.3 理解栈

要知道如何进行return-to-libc攻击,必须了解堆栈的工作原理。我们使用一个小程序来了解函数调用对堆栈的影响。

/* foobar.c */
#include <stdio.h>
void foo(int x)
{
  printf("Hello world: %d\n", x);
}
int main()
{
  foo(1);
  return(0);
}

我们可以用“gcc -S foobar.c”来将程序编译成汇编代码。

 

转载于:https://www.cnblogs.com/xlwang1995/p/7153878.html

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
return-to-libc攻击是一种典型的缓冲区溢出攻击方式,它绕过了内存的数据执行保护机制。在执行return-to-libc攻击时,攻击者通过精心构造的恶意输入,将栈溢出造成的缓冲区溢出利用到无法执行任意代码的情况下。 返回到C库(return-to-libc)是一种利用栈溢出漏洞的攻击技术。正常情况下,当程序发生栈溢出时,攻击者可以将恶意代码注入到程序的内存中并执行。然而,现代操作系统和编译器通常会实施一些保护措施,如地址空间布局随机化(ASLR)和栈不可执行(NX)等,以防止这种攻击。 return-to-libc攻击的基本思想是利用目标程序中的已知函数,如C库函数,来达到执行恶意代码的目的。通过了解函数名称和地址,攻击者可以通过篡改程序的返回地址来使程序跳转到所需的函数。而且,由于这些函数已经在内存中,不在栈上执行,因此可以绕过堆栈溢出和执行保护。 在return-to-libc攻击中,攻击者通过构造恶意输入,覆盖目标程序的返回地址,并将其设置为C库函数的地址,如system()或execve()。这样一来,当程序返回时,不会执行恶意代码,而是跳转到C库函数,攻击者可以使用这些函数来执行所需的操作,如系统命令执行。 然而,现代操作系统通常会实施一些防御措施来阻止return-to-libc攻击,如堆栈保护(stack protector)和地址空间布局随机化(ASLR)。这些措施增加了攻击难度,使得攻击者更难以成功利用return-to-libc攻击。因此,及时更新补丁和使用安全编程实践是防止此类攻击的关键。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值