栈溢出笔记1.2 覆盖EIP

1.1节中我们说到可以利用栈溢出来破坏栈中原有的内容,这一节中,我们就来看看如何争夺到返回地址(EIP),使得我们可以随意控制它的值,这样我们就可以控制程序。来看一个经典的程序:

这个程序的get_print函数中定义了一个大小为11个字节的数组,正常情况下我们的输入应该最多为10个字符(还有一个\0结束符),而gets函数没有明确定义输入的大小,因此,我们可以输入超过10个字符,从而造成栈溢出。如下,输入10个‘A’,一切正常:

图8

当我输入11个‘A’时,虽然顺利打印出来11个‘A’,但是VS2008报了如下错:

图9

运行时错误检查检测到栈崩溃,这是Windows为抵抗栈溢出漏洞利用采用的措施。目前我们还不知道如何绕过,先去掉它,在工程属性中,“C/C++”——“代码生成”的“基本运行时检查”选择为默认值,然后重新编译。

图10

修改后,输入11个‘A’貌似是没什么问题了,但是输入12个‘A’的时候,又出来一个这样的对话框:

图11

缓冲区溢出被检查到了,这当然不是一个好消息。作为经典的漏洞,Windows自然有多种对付招式,这又是一种叫做栈Cookie的保护方式,可以检查到栈溢出。同样,先去掉它,在工程属性中,“C/C++”——“代码生成”的“缓冲区安全检查”选择为否(GS-, 见图10),然后重新编译。这一次,我们输入一大串‘A’:

图12

什么?VS2008又出现了弹窗?别紧张,这次是好消息。

图13

看到熟悉的0xC0000005,表明是访问了不该访问的地址。同时,0x41414141不就是“AAAA”吗?这说明我们输入的“AAAA”已经以某种方式被程序使用了,这果断是好消息。

下面,用Immunity Debugger来看看究竟发生了什么。先找到函数get_print()的代码,在 MOV EBP, ESP语句上下断点:

图14

然后运行到这里,查看栈内容:

图15

回想1.1中的内容,get_print没有参数,因此0012FF14(当前ESP)处为保存的EBP,0012FF18(EBP+4)为返回地址(重要)。

下面两句分配栈帧的代码对栈的影响较大:

/*********************************************************/
MOV EBP, ESP
SUB ESP, 4C
/*********************************************************/

分配了4C(76字节)大小的空间,因此,下面这段栈空间(get_print)是我们关注的内容:

图16

现在,定位到gets函数,我们关注的不是它的调用过程,而是参数,它位于栈上EBP-C的位置,因此,它紧邻保存的EBP。也就是说,这个缓冲区下面是保存的EBP,再下面是保存的返回地址。这很重要,它决定我们需要输入多少内容才能准确地改写保存的返回地址(EIP)。

我们在gets函数之后设断点,并输入以下内容(16个A和4个B):

图17

此时,查看栈内容:

图18

看到了吗?保存的EBP被‘AAAA’覆盖,保存的返回地址(EBP+4)被BBBB覆盖。因为,我们知道局部变量的准确位置,因此,可以准确的知道需要多少字节来覆盖返回地址的内容。

这样,我们就从程序手中争夺了EIP,get_print()返回时,它将跳转到0x42424242处执行,由于该地址不可访问,因此会出现0xC0000005错误。后面,我们将给EIP写入有意义的地址,从而执行我们自己的内容。

时间: 2024-08-02 13:26:55

栈溢出笔记1.2 覆盖EIP的相关文章

栈溢出笔记1.10 基于SEH的栈溢出

上节中简单地讲述了SEH的原理及逻辑结构.本节,要继续讲述SEH的物理结构及如何利用它进行栈溢出. 先来看SEH的物理结构.先回想上节中的图51,我们在程序停在gets函数输入的时候查看SEH链,看到了一大堆异常处理器,而当我们把断点设置在gets函数下一条语句的时候,其中很多没有了,这给我们一个直观的感觉:SEH链保存在栈上. 下面,我们就来看看栈上的SEH链.我们使用的是example_10,即添加了一个自己的异常处理块的程序(编译时继续采用前面教程中的设置,即关闭缓冲区安全检查).依然把断

栈溢出笔记1.3 准备Shellcode

经过1.1和1.2节的讲述,我们已经知道了怎样更改EIP的值. 程序运行函数之后将跳转到我们设定的位置開始运行,因此,我们须要准备一个自己的程序,接手后面的工作.这是一个什么样的程序?是一个C语言编写的代码?是一个可直接调用的exe?肯定不是,由于EIP所指的地址保存的内容为指令的操作码,CPU读取该操作码运行相应的操作. 所以我们要准备的程序也应该是一段"操作码". 继续写1.1中的Hello World.这次我们要把一个C语言编写的MessageBox换成一个仅仅有"操作

栈溢出笔记1.4 黑掉example_2

在1.2节中我们编写了一个有漏洞的程序,通过输入可以控制其EIP,本节,我们要让example_2运行我们的MessageBox.再看看example_2: /*****************************************************************************/ // example_2: 演示栈溢出 #include <stdio.h> void get_print() { char str[11]; gets(str); printf(

栈溢出笔记1.1 函数调用过程

选择从栈溢出开始学习Shellcode的编写,是因为在没有保护机制(栈Cookie,ASLR,DEP,SafeSEH)的系统中使用栈溢出是一件很简单的事情.栈区随着函数调用动态变化,每个函数调用时在栈上占用的空间称为栈帧.用一个示例来说明栈上保存的内容及动态变化的过程. 下面是一个程序,生成一个对话框显示一条"Hello World!"消息.下面是该程序的C代码: 在VS2008中用Debug版编译之后,拖入Immunity Debugger中: 图1 example_1.exe入口点

栈溢出笔记1.9 认识SEH

从本节开始,我们就要研究一些稍微高级点的话题了,如同在1.2节中看到的,Windows中为抵抗栈溢出做了很多保护性的检查工作,编译的程序默认开启了这些保护.如果我们不能绕过这些保护,那么我们的Shellcode也就是一个玩具而已,什么都做不了. 我们从SEH(结构化异常处理)开始. 这篇文章讲SEH简洁易懂:http://www.securitysift.com/windows-exploit-development-part-6-seh-exploits/ 因此,本文的前面部分就直接对其进行翻

APICloud学习笔记之FrameGroup覆盖bug

当子页面再打开framegroup时,此framegroup会置于最顶部此bug处理方法如下: 1.在子页面定义一个事件控制framegroup的显示 1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="maximum-scale=1.0,minimum-scale=1

栈溢出笔记1.6 地址问题(1)

前面的Shellcode中,我使用的都是自己XP机器上的硬编码地址.不论什么时候在Shellcode中使用硬编码地址都不是个好主意,这一点与动态库的重定位相似,一旦系统环境和程序编译设置发生变化.Shellcode差点儿肯定会失效.因此.我们要找到更好一点的方法. 前面的Shellcode中,我用到了例如以下几个硬编码地址.它们的含义例如以下: 当中.LoadLibraryA的作用比較特殊,我们用它来载入user32.dll库. 如今我们要换掉这些硬编码地址.那么,怎样得到这些API函数的地址呢

缓冲区溢出攻击-入门例子

由于工作的需要,开始学习安全领域的知识了.感觉这个领域的知识点太多,而且非常底层,缓冲区溢出攻击这个算是最容易理解的了,就先从这个开始入门吧~ 先试个最简单的例子,学习学习原理~ 本文代码和原理主要参考http://blog.csdn.net/linyt/article/details/43283331博客,大部分内容是直接抄原博客,加了一点自己测试时遇到的问题. 测试环境 Ubuntu 16.04 TLS 测试前准备 1. 关闭地址随机化功能: echo 0 > /proc/sys/kerne

0ctf2018 pwn

前言 对 0ctf2018 的 pwn 做一个总结 正文 babystack 漏洞 非常直接的 栈溢出 ssize_t sub_804843B() { char buf; // [esp+0h] [ebp-28h] return read(0, &buf, 0x40u); } 这个题的难点在于 用 python 启动了该程序同时过滤了 stdout 和 stdout #!/usr/bin/python -u # encoding: utf-8 from pwn import * import r