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

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. Laravel5.4 Oauth2.0认证应用 API 实战!

    项目初始化 新建项目 lukeyans-MacBook-Pro:laravel lukeyan$ laravel new laravel_demo 添加laravel自带的Passport服务 luk ...

  2. javascript札记

    bind和unbind对应,live和die对应,千万别用bind绑定,用die解除.还有bind可以多次绑定同一个函数,可能会被执行多次同一个函数 正则表达式的使用 var email_reg = ...

  3. android触控,先了解MotionEvent(一)

    http://my.oschina.net/banxi/blog/56421 这是我个人的看法,要学好android触控,了解MotionEvent是必要,对所用的MotionEvent常用的API要 ...

  4. python数据类型2

    一 文件格式补充 在python3中,除字符串外,所有数据类型在内存中的编码格式都是utf-8,而字符串在内存中的格式是Unicode的格式. 由于Unicode的格式无法存入硬盘中,所以这里还有一种 ...

  5. Unit Testing of Spring MVC Controllers1

    我们的pom.xml文件相关的部分看起来如下: <dependency>    <groupId>com.fasterxml.jackson.core</groupId& ...

  6. Md5 util

    Md5PasswordEncoder.java http://docs.spring.io/spring-security/site/docs/3.0.x/apidocs/org/springfram ...

  7. HDU2553 N皇后问题 2016-07-24 13:56 283人阅读 评论(0) 收藏

    N皇后问题 Problem Description 在N*N的方格棋盘放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成45角的斜线上. 你的任务是, ...

  8. sine

       

  9. 执行Docker命令报错解决办法

    shim error: docker-runc not installed on system   服务器重启以后,执行docker命令报以上错误,解决办法如下: cd /usr/libexec/do ...

  10. asp.net缓存使用介绍

    介绍: 在我解释cache管理机制时,首先让我阐明下一个观念:IE下面的数据管理.每个人都会用不同的方法去解决如何在IE在管理数据.有的会提到用状态管理,有的提到的cache管理,这里我比较喜欢cac ...