PWN简单堆栈溢出漏洞利用(二)

2018年9月30日13:11:00 发表评论 7,820
摘要

本文将详细讲述PWN二进制漏洞中简单的堆栈利用,接上一篇文章中的简单栈溢出利用,本文将讲述堆栈利用的另外一种方法——EIP覆盖。

0x01 环境和程序准备

本文接上一篇文章,所以本文所用的环境和程序是和上一篇文章相同的,可参考《PWN简单堆栈溢出漏洞利用(一)》,两篇教程中使用的程序是一样的,但是为了区分开来我们需要在“/home/pwn/pwn1/"目录下建立flag文件。

注意,阅读本文前请务必提前阅读《PWN简单堆栈溢出漏洞利用(一)》,否则你可能不知道我在说什么。

0x02 程序分析

具体的main函数和getFlag()函数内容可以参考上一篇文章的程序截图,但是pwn1程序的foo函数是有些不同的,具体内容如下:

PWN简单堆栈溢出漏洞利用(二)

上一篇文章中我们已经分析过这个程序了,这里简单的再提一下,关键点在一getFlag()函数,从foo()函数中我们可以知道 if 语句这一行是恒为false的,我们之前利用了gets()函数输入让变量s溢出,然后覆盖了参数a1让a1=0x61616161,这样if就可以为true了。但是这个foo()中并没有if判断,值存在输入和输出,但是gets()函数输入溢出漏洞仍存在。下面我们考虑,是不是还有别的方法呢?我们看一下foo的函数栈结构,该栈结构和之前的是一样的。

PWN简单堆栈溢出漏洞利用(二)

我们上一篇说到的是用s溢出0x1c + 0x4 + 0x4然后再写入0x61616161覆盖掉a1,使a1的值为0x61616161,所以if的判断会成立。我们再分析一下,之前函数栈的文章中我们提到过,EIP的作用是存的函数返回地址,那我们就可以大胆猜想,如果直接覆盖掉EIP那么会发生什么?没错,我们可以让这个程序实现任意地址跳转,所以我们只要控制foo的返回地址为getFlag()函数的地址那就万事大吉,直接转到getFlag()函数进行执行,下面我们来测试一下。

0x03 溢出覆盖EIP实现任意跳转

其实覆盖EIP是一种很常见的方式。我们首先计算一下s变量溢出所需要的长度为:0x1C + 0x4 = 0x20 = 32 ,一共是32个字节就可以到达EIP的边界。那么问题来了,我们怎么拿到getFlag()函数的地址呢? 其实该地址是确定的,当程序生成的时候就已经确定了,我们可以看一下getFlag()函数的汇编代码:

PWN简单堆栈溢出漏洞利用(二)

我们能看到该函数的入口地址是0x0804855b,其实这个地址是固定的,在IDA中也可以分析出来,二者的值是一样的。下面再介绍一种新姿势,pwntools库其实是有可以直接获取函数地址工具的方法的,如下:

使用ELF方法中的symbols['getFlag']对象可以分析出getFlag()函数的地址,同样为0x804855b。那么根据上面的分析我们可以写出下面的Payload和脚本:

上面的脚本很简单,就是获取了getFlag()函数地址然后进行溢出封包替换,当程序运行到ret的时候就会跳转到EIP的地址上,也就是我们的getFlag函数中。

程序运行截图如下:

PWN简单堆栈溢出漏洞利用(二)

可以看到,我们已经成功的运行了getFlag()函数,并且读取到了文件中的flag。

0x04 总结

从近两篇教程中我们都是利用gets的溢出漏洞来控制程序的执行流程,第一篇文章中我们覆盖了参数使if判断成立,本文中我们覆盖了函数的返回地址EIP,这都是比较常见的两种方式,也是最简单的玩法,但通常我们遇到的程序可能没这么简单。我们应该结合多种工具来分析程序,像文章中提到的IDA和gdb-peda,还有pwntools,学会使用工具可以达到事半功倍的效果。

在后面的文章我们将进一步了解溢出漏洞的利用,以及注入shellcode,让程序反弹shell等。下一篇文章我们不见不散。

本文程序下载(密码:akcz):

文件下载

  • A+
所属分类:CTF

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: