本文的目的不是为了介绍如何进行恶意的破坏性活动,而是为了教会你如何去防御此类破坏性活动,以帮助你扩大知识范围,完善自己的技能,如有读者运用本文所学技术从事破坏性活动,本人概不负责。

0×01 前言

1988年,世界上第一个缓冲区溢出攻击Morris蠕虫在互联网上泛滥,短短一夜的时间全世界6000多台网络服务器瘫痪或半瘫痪,不计其数的数据和资料被毁。造成一场损失近亿美元的空前大劫难!

缓冲区溢出是一种非常普遍、非常危险的漏洞,在各种操作系统、应用软件中广泛存在。利用缓冲区溢出攻击,可以导致程序运行失败、系统宕机、重新启动等后果。更为严重的是,可以利用它执行非授权指令,甚至可以取得系统特权,进而进行各种非法操作。

0×02 基础知识

在学习这篇教程之前,你需要准备以下东西:

1、一台拥有Linux虚拟机的计算机或者拥有Linux操作系统的物理机。

2、GCC编译器。

3、GDB调试器。

4、任意一款文本编辑器(如vim)。

除此之外,我们还需要了解一些基础知识。

栈操作

对于栈这个概念的最好诠释就是将其想象为一个装乒乓球的圆筒。

从上面口子往下一次放一个进去,先放进去的后面才能出来。栈也同样如此,不过这个圆筒是装乒乓球的,而栈是存储数据的。从计算机术语中来说,栈是一种具有先进后出队列特性的数据结构。

1、入栈或压栈,它在汇编语言中是通过push指令完成的。

2、从栈上取出元素的过程被称为出栈,它在汇编语言中是通过pop指令完成的。

在内存中,每个进程在其内存堆栈段中都拥有自己的栈,针对栈的处理我们需要了解两个寄存器EBP(扩展基址指针寄存器)和ESP(栈指针寄存器)的概念。

EBP指向当前栈的底部,而ESP总是指向栈顶。(如上图)

函数调用过程

函数其实就是一个可供其他函数调用的自包含的代码模块,这句话听起来很绕口,但理解起来很简单,这种函数调用其实就是导致程序流程的跳转,当我们在汇编程序中调用一个函数时,将会发生以下三个步骤:

1、按照调用约定,首先需要将函数参数按照逆序入栈,从而对函数调用进行设置。

2、将EIP保存到栈上(EIP是指令寄存器,存放当前指令的下一条指令的地址),这样程序在调用函数返回后能够在之前中断的地方继续执行下去,所以EIP存放的地址被称为返回地址。

3、执行call命令,将该函数地址放入EIP寄存器进行执行。

下面我们就以一个例子来了解函数调用过程。

示例C程序(function.c):

int foo(int a, int b)
{
    int e = a + b;
    return e;
}
int main(void)
{
    foo(5, 2);
    return 0;
}

首先我们进行编译

gcc -g function.c -o testfunction.o

-g选项使目标文件testfunction.o包含程序的调试信息。

很简单的一个程序,我们主要用它来了解一下函数调用过程。

我们使用gdb来调试程序:

start命令用于拉起被调试程序,并执行至main函数的开始位置。disassemble命令的/m指示显示汇编指令的同时,显示相应的程序源码。

我们先来看看调用foo()函数这段汇编代码:

0x80000580 <+0>:    55      push   %ebp
0x80000581 <+1>:    89 e5   mov    %esp,%ebp
0x80000583 <+3>:    e8 18 00 00 00  call   0x800005a0 <__x86.get_pc_thunk.ax>
0x80000588 <+8>:    05 78 1a 00 00  add    $0x1a78,%eax
 
0x8000058d <+13>:   6a 02   push   $0x2
0x8000058f <+15>:   6a 05   push   $0x5
0x80000591 <+17>:   e8 ca ff ff ff  call   0x80000560 <foo>

和前面我们所说的流程一样,首先将调用程序的EBP寄存器入栈。然后将当前ESP寄存器保存到EBP寄存器。之后获取要返回的地址。接下来就是将函数参数按照逆序入栈,最后执行call命令。

现在我们已经了解是如何进入函数的,接下来我们继续了解函数又是如何结束的呢。

foo函数被执行之后,我们使用disassemble命令显示其汇编指令:

函数收场白:

0x8000057e <+30>:   c9  leave 
0x8000057f <+31>:   c3  ret

被调函数在返回调用程序之前所要做的事情就是将栈清空,而有效的清空栈就是leave语句功能的一部分。然后就是从栈中弹出所保存的EIP返回调用程序。

0×03 缓冲区溢出

缓冲区是指一块可用于接受和存放数据的存储区域,缓冲区一旦分配,其大小也就固定了。首先我们来看一段c程序:

#include <string.h>
 
int main(){
    char test[10];
    strcpy(test,"AAAAAAAAAAAAAAAAAAAAAAAAAA");
}

这段代码非常简单,首先我们定义了一个10字节的字符串,然后使用strcpy函数复制了26个字节的A到test。这明显会发生问题,但是我们先不用管它,我们首先来编译运行一下这个程序:

gcc编译:gcc -ggdb -mpreferred-stack-boundary=2 -fno-stack-protector -o test test.c

运行结果:

可以发现出现了段错误提示,不用郁闷,这正是我们想要的,下面我们使用gdb调试器看看哪里出错了。

我们可以发现,程序试图执行0×41414141处的指令时程序崩溃,而0×41414141刚好是AAAA的十六进制编码。接下来,我们检查一下寄存器EIP:

检查完EIP我们可以清楚的发现问题所在了,从前面的基础知识我们了解到EIP存放的地址被称为返回地址,程序在调用函数返回后能够在之前中断的地方继续执行下去靠的就是EIP,现在EIP被这些A破坏了,程序肯定要崩溃,这就是经典的缓冲区溢出原理。

0×04 总结

本篇文章我们了解了栈的基本概念,函数调用过程以及缓冲区溢出的基本原理,但是这并没有结束,我们还没有去利用这个缓冲区溢出漏洞,下一篇文章我将给大家展示实际情况下缓冲区溢出漏洞出现的位置,以及如何去利用它获取一个Shell。

0×05 参考资料

1、百度百科

2、Buffer Overflow Tutorial: https://gist.github.com/apolloclark/6cffb33f179cc9162d0a

3、Buffer Overflow Exploit: https://dhavalkapil.com/blogs/Buffer-Overflow-Exploit/

4、维基百科: https://en.wikipedia.org/wiki/Buffer_overflow

5、基于堆栈的缓冲区溢出开发教程:https://www.exploit-db.com/docs/28475.pdf

6、函数调用过程探究:http://www.cnblogs.com/bangerlee/archive/2012/05/22/2508772.html

Exploit之初识Linux下缓冲区溢出的更多相关文章

  1. Linux下缓冲区溢出攻击的原理及对策(转载)

    前言 从逻辑上讲进程的堆栈是由多个堆栈帧构成的,其中每个堆栈帧都对应一个函数调用.当函数调用发生时,新的堆栈帧被压入堆栈:当函数返回时,相应的堆栈帧从堆栈中弹出.尽管堆栈帧结构的引入为在高级语言中实现 ...

  2. Linux下缓冲区溢出攻击的原理及对策

    前言 从逻辑上讲进程的堆栈是由多个堆栈帧构成的,其中每个堆栈帧都对应一个函数调用.当函数调用发生时,新的堆栈 帧被压入堆栈:当函数返回时,相应的堆栈帧从堆栈中弹出.尽管堆栈帧结构的引入为在高级语言中实 ...

  3. Linux系统缓冲区溢出

    Linux系统下穿越火线-缓冲区溢出 原理:crossfire 1.9.0 版本接受入站 socket 连接时存在缓冲区溢出漏洞. 工具: 调试工具:edb: ###python在漏洞溢出方面的渗透测 ...

  4. Kali学习笔记33:Linux系统缓冲区溢出实验

    之前做过一个Windows应用SLmail的缓冲区溢出的实验 这次来做一个Linux平台的缓冲区溢出实验: 缓冲区溢出是什么? 学过汇编的应该知道,当缓冲区边界限制不严格时,由于变量传入畸形数据或程序 ...

  5. 使用Linux进行缓冲区溢出实验的配置记录

    在基础的软件安全实验中,缓冲区溢出是一个基础而又经典的问题.最基本的缓冲区溢出即通过合理的构造输入数据,使得输入数据量超过原始缓冲区的大小,从而覆盖数据输入缓冲区之外的数据,达到诸如修改函数返回地址等 ...

  6. linux下堆溢出unlink的一个简单例子及利用

    最近认真学习了下linux下堆的管理及堆溢出利用,做下笔记:作者作为初学者,如果有什么写的不对的地方而您又碰巧看到,欢迎指正. 本文用到的例子下载链接https://github.com/ctfs/w ...

  7. Linux下函数调用堆栈帧的详细解释【转】

    转自:http://blog.chinaunix.net/uid-30339363-id-5116170.html 原文地址:Linux下函数调用堆栈帧的详细解释 作者:cssjtuer http:/ ...

  8. 缓冲区溢出基础实践(一)——shellcode 与 ret2libc

    最近结合软件安全课程上学习的理论知识和网络资料,对缓冲区溢出漏洞的简单原理和利用技巧进行了一定的了解.这里主要记录笔者通过简单的示例程序实现缓冲区溢出漏洞利用的步骤,按由简至繁的顺序,依次描述简单的 ...

  9. Linux下简单的缓冲区溢出

    缓冲区溢出是什么? 科班出身,或者学过汇编的应该知道,当缓冲区边界限制不严格时,由于变量传入畸形数据或程序运行错误,导致缓冲区被“撑爆”,从而覆盖了相邻内存区域的数据 成功修改内存数据,可造成进程劫持 ...

随机推荐

  1. Maven + spring + Mybatis + SpringMVC

    tomcat版本:apache-tomcat-7.0.70 一.新建一个maven的web项目 1.1.请勾选“Create a simple project”,创建一个简单的项目,这里不使用模板.也 ...

  2. LaTeX 公式(转自)Iowa_Battleship 神犇

    传送门 (我这个蒟蒻只是mark一下 这个LaTex公式很全!!我是照着打数学公式的!! orz大佬Iowa

  3. c++ 自动对象

    转自: https://www.cnblogs.com/geloutingyu/p/8034904.html 1.自动对象默认情况下,局部变量的生命期局限于所在函数的每次执行期间.只有当定义它的函数被 ...

  4. 【UXPA大赛企业专访】Mockplus:“设计替代开发”将成为现实

    “过去,是‘设计服务于开发’,现在,我认为是‘设计驱动开发’,而在不远的将来,随着AI的落地.大数据和云计算能力的提升,‘设计替代开发’将成为现实.Mockplus也正在为此部署并行动.” 近日,UX ...

  5. c++11 改进设计模式 Singleton模式

    关于学习 <深入应用c++11>的代码笔记: c++11之前是这么实现的 template<typename T> class Singleton{ public: stati ...

  6. memcached centos启动笔记

    root情况下命令行输入 apt-get install memcached 自动安装 不熟悉的情况下 可能找不到改程序所在目录 使用 find / -name memcached 从根目录开始寻找 ...

  7. java bulid path 和 WEB-INF/lib 下jar 包区别

    用Java Build Path导入包和把包复制到lib下是有区别的,它俩其实不会冲突,也没有什么关系的, Java Build Path是我们编译需要的包, 导入到lib下是程序运行时需要的包 ,  ...

  8. 创建一个子进程---vfork

    子.父进程共享数据段与堆栈段 函数原型:pid_t vfork(void) 返回值:子进程中返回0,父进程中返回子进程ID,出错返回-1. 注意: vfork创建的进程是按先子进程后父进程的顺序执行的 ...

  9. ipad The data couldn’t be read because it isn’t in the correct format

    原来是land left和land right都勾选的,去掉land left后出现这个问题

  10. 2018.09.28 牛客网contest/197/A因子(唯一分解定理)

    传送门 比赛的时候由于变量名打错了调了很久啊. 这道题显然是唯一分解定理的应用. 我们令P=a1p1∗a2p2∗...∗akpkP=a_1^{p_1}*a_2^{p_2}*...*a_k^{p_k}P ...