【技术分享】浅谈ASLR和Shellcode的那些事儿

阅读量196515

|

发布时间 : 2016-10-18 14:48:19

x
译文声明

本文是翻译文章,文章来源:安全客

原文地址:https://woumn.wordpress.com/2016/10/12/bypassing-aslr-on-windows-into-a-reverse-shell/

译文仅供参考,具体内容表达以及含义原文为准。

http://p4.qhimg.com/t0126f4379227fbf772.png

传送门

【技术分享】教你如何拿到RedHat8服务器的Shell


温馨提示:在此之前,我曾撰写过一篇关于反向shell的文章。在这篇文章中,我将会引用到此前这篇文章中的部分内容,所以我建议各位同学在阅读本文之前先查阅一下那篇文章[文章传送门],以节省各位的宝贵时间。


前言

在这篇文章中,我将会针对一种新型的堆栈环境来进行安全分析。除此之外,我还会告诉大家如何自己构建一个payload来绕过ASLR(随机分配地址空间技术),整个过程与我在此前那篇文章中所描述的方法有一些略微的变化。

注:在我进行测试Windows 7系统环境中,DEP(数据执行保护)功能已经被禁用了。DEP是一套软硬件技术,它不仅能够防止存储在栈内存中的操作码得到直接执行,而且它还能够在内存上执行额外的安全检查以帮助防止恶意代码在目标系统中运行。


了解Windows架构下的堆栈环境

相较于Linux而言,Windows的堆栈架构则稍有不同。除了堆栈空间的架构有区别之外,Windows的调用规则也与Linux平台不一样。我待会儿会跟大家解释这些不同之处对我们意味着什么,但是在此之前,我们要先了解一下不同环境下的堆栈架构,以及各个方法之间相互调用的规则。

需要注意的是,被调用的方法(method)需要负责清除堆栈空间中所有与之相关的数据。这时我们就要明确区分出函数的主调用者和被调用者了,这一点非常的重要,因为这些函数会将数据写入我们的堆栈。

在Linux平台下,我们是以调用者的身份进行操作的,而这就意味着某个方法需要通过调用其他的方法来将正确的操作指令压入栈中,当其他的方法返回了相应的值之后,系统才会通过调用此前压入栈中的命令来清除堆栈中相关的数据。但是我们可以看到,Windows平台则是以一种被调用者的模式运行的。这也就意味着,被调用的方法将要负责清理堆栈中的相关数据。所以,Windows平台下的堆栈示意图与我们之前那张Linux环境下的堆栈结构图片大致相似,但是仍然有一些细微的区别。

Linux的堆栈结构如下图所示:

http://p5.qhimg.com/t0189117b4cb75686ee.png

Windows的堆栈结构如下图所示:

http://p4.qhimg.com/t0134f9c0a902fdf39b.png

从这张图片中我们可以看到,EIP寄存器之后还有一些数据,而ESP寄存器之后还有一些队列数据。而在ESP寄存器之前的数据就是负责清除数据的操作码,这些操作码的插入位置需要根据不同系统架构的调用规则来进行区分。我之所以要给大家介绍这些内容,是因为这些知识对于我们之后编写漏洞利用代码来说是非常重要的。所以在我们继续讲解之前,我要帮各位同学填补这部分的知识空缺。

实际上,从我们的角度来看,Windows的堆栈架构与Linux的堆栈架构有着惊人地相似之处。从广义的角度来讲,两者而唯一的区别就是Windows堆栈有ASLR。所以,这就是我们这篇文章中的主角,我们将会尝试使用这篇文章中所要介绍的漏洞利用方法来尝试绕过ASLR。接下来,让我们开始吧!


构建恶意输入

与之前RedHat8的漏洞利用过程非常相似,但我们这次只需把注意力放在一个缓冲区溢出漏洞的身上。虽然该缓冲区的具体长度要稍后才能确定,但是我们现在至少要获取到足够的信息以了解该缓冲区的实际架构。

首先,我们要解决如何绕过ASLR的问题。为此,我们要使用一个简单的机制(jmp esp),这样我们就可以跳转到ESP寄存器指向的地址。这也就意味着,我们在不知道ESP寄存器指向地址的情况下实现了相对跳转。这是一个好消息,因为就算我们的堆栈帧会存储在堆栈空间的随机位置上,但总是会有一个指针指向栈底,我们可以通过一个简单的操作码去访问这个指针地址。

所以,只要我们能够找到“jump esp”指令,我们就可以将其放入堆栈的EIP寄存器中。请记住,在这种情况下, EIP寄存器所指向的任何代码都将得到执行。剩下的就是那部分负责清除数据的代码了。实际上,我并不清楚这些代码是何时被压入栈中的。但是接下来,我们要确保的就是我们的payload会在这部分代码执行完毕之后正确运行。

最后一个问题就是我们shell代码的编码问题。我们的shell代码会被发送至目标主机,所以我们需要对其进行编码。由于我们的shell代码最终将会被执行,所以在执行之前肯定需要先进行解码,而解码后的代码长度肯定会增加。所以为了解决这个问题,我们要将ESP寄存器移动到堆栈空间的前段。具体如下图所示:

http://p2.qhimg.com/t010049a131da0c0484.png


恶意输入中所要使用的参数

首先,我要说明的是Windows 7实际上采用的是小端存储模式。这一点对于我们构建返回地址(例如“jump esp”指令)是非常重要的。

我所要做的第一件事情就是确定缓冲区的长度,或者是我们需要覆盖EIP寄存器的长度。我们使用“./pattern_create.rb 5000”并将其发送至我们的服务器端。接下来,我们可以使用“./pattern_offset.rb PATTERN”来重写EIP寄存器。这样一来,我们就能够知道用来覆盖EIP的恶意输入长度了,即4093。

我们可以在Narly中使用命令“!nmod”来列出堆栈中所有的数据包,我们只需要关注那些与ASLR无关的数据包即可。具体如下图所示:

http://p6.qhimg.com/t01f3606a1922222f39.png


发生了什么事?

在尝试了几个小时之后,我发现了一些不正常的现象。其实从一开始,EIP寄存器中的数据根本就没有被覆盖。而当我尝试使用NOPs去重写EIP时,系统却提示称我的payload结构有问题。在进行了改进之后,我决定使用“jump esp”指令的地址来重写缓冲区。

在完成了改进之后,我又进行了一次测试。这一次,我又遇到了一个奇怪的问题。ESP现在指向的却是一堆垃圾数据,但是其中还包含有一小部分有效数据。

http://p6.qhimg.com/t01ef671dae2d640371.png

还记得吗?我曾在我们的payload代码前添加了一部分数据,并将ESP寄存器在栈内存中的地址向前推进了1000个字节,为的就是当我们执行exploit时防止其被覆盖。接下来,我们需要查看EIP寄存器所指向的内容。地址0x00d6c732中到底有什么?通过分析之后我发现,这是一个内存地址,它指向的是我的shell代码!具体的位置我在上图用红色的圈圈标出来了。

出于好奇,我在shell代码前添加了一个断点,然后再次发送我们的payload。令我惊讶的是,这一次WINgdb竟然暂停了,并且会等待我输入下一步运行指令。

http://p3.qhimg.com/t01207bcd06c8c8132b.png

我们的目的是为了绕过ASLR,而每当我启动服务器后,或者发送我的payload后,堆栈帧都会被随机分配至堆栈空间中。虽然我们能够成功地移动ESP寄存器的内存位置,而且也能够执行shell代码中的部分指令,但是系统仍然会报错。


总结

这篇文章中的漏洞利用方法和之前针对RedHat8的漏洞利用方法之间有很大的不同,因为当我尝试进行远程攻击时,这个漏洞利用方法仍然不起作用。我没有收到任何的错误提示信息,虽然通信连接建立成功了,但是我却没有接收到任何的响应数据,所以我只能假设是某个子进程挂掉了。

本文翻译自安全客 原文链接。如若转载请注明出处。
分享到:微信
+10赞
收藏
WisFree
分享到:微信

发表评论

内容需知
合作单位
  • 安全客
  • 安全客
Copyright © 北京奇虎科技有限公司 三六零数字安全科技集团有限公司 安全客 All Rights Reserved 京ICP备08010314号-66