利用Session欺骗构造最隐蔽的WebShell
不知不觉“LM团伙”看黑防已有两个春秋了,期期不落。潜心修炼了这么久,也能开始耍上一两招了。看了黑防第二期的《DreamWeaver引发网络危机》一文,“LM团伙”内心有说不出的激动,心想网上有40%的网页都有这样的漏洞,那岂不是又能收获N多肉鸡了。可是仔细研究发现,这个文章的方法存在一些问题,并不像想象中的那样容易发挥。下面就与大家一起讨论一下Session。
既然是谈Session欺骗,那么就先来看一下Session到底是什么,它是怎么工作的。在ASP中,服务器能通过Session对象区分不同的浏览器,因为Session对象是用来记录浏览器端的变量,存储一些如用户名等比较敏感或有用的信息。这点似乎和Cookie有点像。但我们知道Cookie的值都是保存在客户端的,而Session的值却是保存在服务器端。当每个访问者第一次浏览器访问服务器的一个ASP网页的时候,服务器会为他创建一个新的并且独立的Session对象,分配给该会话一个会话标识号,并把包含会话标识符的特殊加密版本的一个Cookie(会话标识号)发送给客户。由于在Cookie(会话标识号)中没有提供Expires值,所以当浏览器关闭时,这个会话标识号也就消失了。
每当用户访问这个ASP网站时,ASP都会通过浏览器查找这个会话标识号。命名为ASPSESSIONIDxxxxxxxx,其中每个x是一个字母符。我们在抓接收包时能看见:
Set-Cookie: ASPSESSIONIDSQBBQQDS=GCINNKPDIGDNPEAOGLDFFFEM; path=/
但是这个Cookie(会话标识号)不会出现在Request.Cookies或Respsones.Cookies集合中,虽然ASP把它隐藏起来,但仍保存在浏览器上。对于每个ASP网页的请求,ASP都要查看该值。这个Cookie(会话标识号)包含的值,指明了这个用户的会话。因此,相应的Session对象(该对象已经在内存中,并且一直包含所有在前一页面请求过程中进行超操作的值)的内容可以移交给ASP网页中的脚本。也就是说,浏览器端拥有的是服务器分配的一个会话ID号,当我们有请求的时候,服务器可以通过这个ID号,查找相应Session对象的值,也就实现了区分不同的浏览器。
利用
文笔不好,不知道大家从前面的原理部分是否对Session有了一定的认识。现在我们来看看《DreamWeaver引发网络危机》一文是如何利用Session会话的。
已有某网站abc.com,下有登录页:Login.asp,成功登录后转向可以看到敏感信息的OK.asp(设有访问限制,验证通过则显示),否则转向Fail.asp。
在该文中,作者是想先构造一个hack.asp的网页,通过浏览该网页,建立Session会话,并设置一下Session验证时所需要的值,然后直接在地址栏输入登录以后的网页ok.asp,由于ok.asp是通过Session来验证的,所以作者认为这样能成功。可是,通过前面的分析我们知道,如果ok.asp和hack.asp不在同一台服务器上,这种攻击是无法实现的。因为Session对象的值都是保留在服务器端,不可能像作者所说的那样:让ASP执行并在IE中留下Session值,IE所拥有的不过是一个Session的会话标识号。如果我们在本机或其它服务器浏览了hack.asp,设置的验证值是在hack.asp所在的服务器上,但是在ok.asp所在的服务器上并没有设置相应的验证值,就连Session会话都没有建立,又如何通过验证呢?可见如果ok.asp和hack.asp不在同一台服务器上,就不会引发网络危机了。
但是我们能通过这种Session欺骗的方法在入侵后给自己留一个不易查杀的后门!下面就以MyPower动力3.5为例给大家演示,如何通过Session欺骗来达到直接登录后台目的。
我们先来看一下动力的源代码,在Admin_ChkPurview.asp中Session的验证:
AdminName=replace(session("AdminName"),"'","")
if AdminName="" then
call CloseConn()
response.redirect "Admin_login.asp"
end if
sqlGetAdmin="select * from Admin where UserName='" & AdminName & "'"
可见,动力是通过Session对象中的AdminName变量来认证的,并用它作为用户名来查询数据库,而AdminName的最初赋值是在Admin_ChkLogin.asp中,当用户成功登录以后会给你两个Session值:
session.Timeout=SessionTimeout
session("AdminName")=rs("username")
由于登录以后都是通过Session对象来检测的,所以我们在任何能访问的ASP网页中可构造以下语句(如Copyright.asp):
<%session("AdminName")="admin"%>
这样就能通过Admin_ChkPurview.asp的Session验证了。其中,Admin是指存在的管理用户名。这样构造后,即使我们在肉鸡上的任何木马都被查杀,只要管理员的用户名没有更改,我们可以先访问Copyright.asp,然后直接输入Admin_Index.asp就能直接登录后台了!
那对于这种情况如何预防呢?其实动力也用了一定的办法,你会发现按这种方法输入其它的后台页面无法成功,这是因为在Admin_ChkPurview.asp还有如下验证:
ComeUrl=lcase(trim(request.ServerVariables("HTTP_REFERER")))
if ComeUrl="" then
response.write "<br><p align=center><font color='red'>对不起,为了系统安全,不允许直接输入地址访问本系统的后台管理页面。</font></p>"
response.end
else
cUrl=trim("http://" & Request.ServerVariables("SERVER_NAME"))
if mid(ComeUrl,len(cUrl)+1,1)=":" then
cUrl=cUrl & ":" & Request.ServerVariables("SERVER_PORT")
end if
cUrl=lcase(cUrl & request.ServerVariables("SCRIPT_NAME"))
if lcase(left(ComeUrl,instrrev(ComeUrl,"/")))<>lcase(left(cUrl,instrrev(cUrl,"/"))) then
response.write "<br><p align=center><font color='red'>对不起,为了系统安全,不允许从外部链接地址访问本系统的后台管理页面。</font></p>"
response.end
end if
end if
可是在Admin_Index.asp页面中并没有调用Admin_ChkPurview.asp,所以我们能通过验证!那为什么不调用呢?不要问我了,自己试一试就知道了。
后记
我们知道通过关闭浏览器能结束会话,但是这样失去的只是服务器给我们分配的会话标识号。而在Session会话的生命周期结束之前,服务器是不会将会话标识号对应的Session值从内存中清除的。
小知识:一般IIS的Session的生命周期默认是20分钟。
利用这个原理,如果我们通过一定途经获得了其它浏览器登录服务器时建立的Session会话标识号。那么我们就能用这个会话标识号来得到被劫浏览器端同样的权限。如果是一个管理员在登录后台,那么我们在另一台电脑上用这个会话标识号通过Session欺骗同样能登录后台,从而就实现了异地的攻击。具体方法欢迎到黑防论坛讨论。
文章若有疏漏敬请兄弟指出,哪位兄弟若有更好的利用方法欢迎一起分享