突破防火墙

来源:黑客防线
作者:dangguai27

如何在溢出后得到安全的、隐蔽的Shell是大家一直都在讨论的问题,因为现在的防火墙和各种安全软件漫天飞,想不被它们发现还真是很难,幸好有很多牛人们用自己的实力探索出了一条这样的道路,让我们这些人能顺着前辈的步伐一点点进步。本文给出了两种目前比较先进的端口复用技术,用在溢出后的端口绑定和Shell的获取,目前防火墙和各种安全工具对这样的技术还是陌生的,可以预见又一波新的技术浪潮即将在网络这片海洋上咆哮!

溢出后端口利用的缺陷

以前学习网络课程的时候,只是了解了端口和应用层服务之间的对应关系。后来对安全方面逐渐有了兴趣,再通过学习些系统底层的东西,进一步了解端口和进程是怎样映射的。再后来,接触了缓冲区溢出,步步深入,同时也更多地涉及到了端口的使用……呵呵,觉得我在说自己的成长史吧?

回到正题,在溢出技术(这里暂时都指堆栈溢出)中,传统的端口利用方式大致有两种:一种是普通木马所采用的,攻击成功以后,在对方机器上驻留一段服务程序,而攻击者作为客户端,服务端通过一个端口打开连接资源,等待客户端连接。另一种方式是反弹木马所采用的,在本方机器打开一个端口,作为服务端,而对方机器作为客户端,攻击成功后,客户端会主动连接服务端。

对于前一种方式,防火墙对进入本机的数据包进行相应的策略设置,就能轻易的截获掉攻击数据包,从而避免本机信息本攻击者获取。

1.jpg
大小: 36.63 K
尺寸: 391 x 483
浏览: 11 次
点击打开新窗口浏览全图

图1 天网个人防火墙对于本机外连的设置

当只允许访问本机访问外界的80以下端口时,我们让对方连接我们开放的777端口的希望就会化为泡影。并且在反弹连接时对方防火墙会给出如下告警(如图2所示):

2.jpg
大小: 24.91 K
尺寸: 392 x 325
浏览: 8 次
点击打开新窗口浏览全图

图2 防火墙给出的访问非法端口的告警信息

尽管一般用户对于个人放火墙这样设置的情况不多,但一旦遇到,攻击就不会成功。

基于上述端口利用方式的缺陷,现在出现了另一种新的利用方式,即San在xcon2004(2004焦点峰会)中提到的复用当前连接的端口利用方式。这里的端口利用方式分为端口的重复绑定和重新绑定两类。本文中我不打算讨论ShellCode的具体编写,因为这方面的资料网上实在太多,我主要从实现方法这个角度来讨论。

突破防火墙限制一:复用当前端口
这种方式相对后面介绍的重新绑定端口而言要容易实现一些。在Winsock的实现中,对于服务器开放端口大多是可以重复绑定的。

这里举一个例子,某机器上开放了WWW服务,端口为80。如果该主机存在IIS溢出漏洞,则攻击者发送攻击代码到该主机并使其溢出后,采取的利用方式是在ShellCode中重复绑定对方80端口,并且使用函数Setsockopt()对套接字的属性进行设置,这里将第3个参数设置为SO_REUSEADDR而非SO_EXCLUSIVEADDRUSE。原因是这样的,SO_REUSEADDR表示如果80端口没有被独占的话,则可以重复绑定;而SO_EXCLUSIVEADDRUSE则表示只允许80端口绑定一次,但是对方www服务并没有挂掉,仍然占用着80端口,我们再次绑定肯定失败。

绑定成功以后,对方机器上打开CMD输入netstat –an命令可以看到有两个IP绑定着80端口,如图3所示:

3.jpg
大小: 42.98 K
尺寸: 500 x 319
浏览: 13 次
点击打开新窗口浏览全图

图3 重复绑定80端口

这样绑定之后,如果外界连接该主机的80端口,则使用ShellCode中绑定的那个套接字。剩下的事情就只是利用该连接来为攻击者做哪种服务而已了,可以绑定到Cmd,也可以上传、下载文件。在附带的代码中,我写了一个用高级语言实现的重复绑定80端口,然后传输上传并执行文件Sample.exe的C/S示例。

由此可见,重复帮定端口的方式的特点是,溢出成功后,直接在原来的进程中重复绑定当前服务开放的端口。

这里也有一些问题,比如135、139端口是不能重复绑定的,这是由于对应的服务可能设置了SO_EXCLUSIVEADDRUSE。此外,攻击者应该注意将我们的功能和原来的服务区别开来。实现起来,只需先判断接收到的数据包是否是我们想要的数据,如果是则按照我们预定的方式处理。如果不是我们想要的,则通过127.0.0.1传送给真正的应用,这也在附带的代码中有所实现。

突破防火墙限制二:重新绑定当前端口
这种方式与第一种有所不同,实现起来也更为复杂。由于135、139端口是不能重复绑定的,因此,要想重新利用当前端口,可行的方法就是先将当前进程结束,再绑定原端口。基本思路是这样,但问题是,怎样实现在系统进程中既要自己结束当前进程又要成功地重新绑定原端口呢?实现的方法如下:

1.溢出成功以后,在ShellCode中调用CreateProcess()为当前进程创建一个Suspend模式的子进程,这里第6个参数设置为CREATE_SUSPENDED。

2.调用函数GetThreadContext()来获得子进程中主线程的上下文结构和寄存器信息。

3.调用VirtualAllocEx()在子进程里分配内存。

4.把ShellCode指令用WriteProcessMemory()来写入子进程刚才分配的空间。这里的ShellCode指令指ShellCode中在重新绑定端口以后将要用到的部分,它的功能可以是绑定Cmd,也可以是传输文件。

5.调用SetThreadContext()把GetThreadContext()获得的EIP修改指向VirtualAllocEx()分配的内存地址,这样做的目的是让子进程的主线程结束后立即跳到我们的ShellCode指令中执行。

6.接下来就是调用ResumeThread()恢复Suspend模式的进程并马上调用TerminateProcess()结束当前进程。

这样就达到了重新绑定原端口,135、139端口均不例外。然而还有一个问题是,子进程对应的执行程序是什么呢?答案很简单,当然是Cmd.exe,因为在Windows 2000以后的各系统版本中都存在Cmd.exe。而且更合适的是,Cmd有一个参数是 /c,表示“运行完指令后终止”,这样就恰好符合了要求其主线程很快结束的需求。实现起来,只需要将CreateProcess()第2参数设置为如“cmd.exe /c dir”一类的形式就可以了。

至此,重新绑定端口的过程结束,攻击者可以远端连接,然后执行要要的功能。无论是绑定Cmd,还是传输文件,都是通过原来进程开放的端口进行,防火墙是不会阻截。在附带的代码中也有对应的高级语言模拟重新绑定19800端口的示例,测试是只需要连续两次telnet ip 19800即可。

后记
上面介绍了溢出技术中端口利用的各种方式,侧重点在实现方法上,也叙述了在实现过程中需要注意的一些问题,希望对感兴趣的朋友有所帮助。附带代码中的模拟过程都是基于高级语言的,经过多次测试都是成功的。至于汇编实现以及转变为ShellCode的生成这里没有谈及,但是相信从方法上掌握了以后,实现起来也不会是很困难。端口重复绑定和重新绑定以及Socket查找的ShellCode编写在以后的讨论中进行。

posted on 2011-05-25 15:06  hicjiajia  阅读(930)  评论(0编辑  收藏  举报