- Weekly Bug Bounty Content
- Posts
- Cross-Site Scripting (XSS): Exploiting XSS vulnerabilities
Cross-Site Scripting (XSS): Exploiting XSS vulnerabilities
The Ultimate Guide In Crafting Payloads And Exploiting XSS Vulnerabilities For Higher Bounties
Today's estimated reading time is: 12 min
Imagine thisYou found an injection point, spent 2 hours finding a bypass that works and FINALLY got that alert box popupAnd now you've got to escalate the XSS to an account takeoverYou look at the cookies, all sensitive ones are HTTPOnly :/You check whether you can change the password, and you notice that the previous password is really requiredYou checked whether you can turn off 2FA, and you see that the current 2FA code is also required...You tried so many ways and conclude that you can't escalate it any further...In today's post, I will help you go over plenty of ways how you can escalate XSS vulnerabilities to account takeovers through leaked session cookies, access tokens, and sometimes even to RCE!I will also share some unique findings I found a while back, let's get into it!Just a small reminder, all the proof of concept code that I share here is just to give you an idea of how you can achieve different tasks. Please adjust the PoC code according to your target for it in order to work.Also, to keep the post length reasonable, it is not possible to include all possible ways to achieve account takeover (as there are plenty of ways to do so). I've included the ones that are generally not very known or shared.
Today's post is brought to you by Nova SecurityThe attack surface management & vulnerability detection platform that saves you time, and earns you more bounties.Waitlist is open, join today ===> https://novasec.io/
Sensitive cookie leak:
As we've seen earlier, HTTP is a stateless protocol, meaning that the server has no idea of the previous request, and if it belonged to you. But to allow servers to identify requests of multiple users, cookies are used (sometimes Authorization header or some other kind of token or identifier).
HTTPOnly is basically a cookie security feature that tells your web browser to not allow anyone to read your cookies through client-side code such as JavaScript (think of document.cookie).
Cookies can only be sent in the request if the cookie policy (that has been set) is satisfied. I won't go into detail here but do check out the Additional Resources section in this post.
Sometimes, even when cookies are set to HTTPOnly, they can be reflected elsewhere in the application.This is usually due to developers reflecting it in the response body by error or because they need it to be retrieved later (while also enforcing the cookie security).A few ways to look for this are:
Looking in your proxy interceptor's sitemap for your session cookie's value (or cookie name). If you do not have Burpsuite Pro, you can also crawl the entire site as an authenticated user and grep for the token in the response body.
Checking the response body of the API that returns your profile data (example: /api/v1/me, /api/v1/profile, ...)
Checking for any CRLF injections on pages that return your cookie in the Set-Cookie response header (important thing is to make sure your injection point is ABOVE the Set-Cookie header as you need to transform the remaining headers in the response body).
Now, if you've found your session cookie being reflected inside the response body, all you've got to do is to make an HTTP request to that page. Extract the value using a regex pattern and send it back to your end.Here's a simple proof of concept code (you may copy this, but do adjust the details first according to your needs):
Access Tokens and JWTs:
Most modern web applications today are built with front-end JavaScript libraries and frameworks such as React, NextJS, VueJS, Angular, etc.And to keep track of users, they usually don't make use of cookies but instead, use JSON Web Tokens or access tokens.These are often stored in your web browser's local or session storage and can be easily accessed via the LocalStorageAPI or SessionStorageAPI.Sometimes, these can even be stored in your IndexedDB or Web SQL Database (although that may be much rarer to find).I recommend mapping out all possible ways that the web application may have been used to store your access token.One last note: web applications built using front-end javascript libraries and frameworks are not vulnerable to reflected XSS as they are built differently. By default, they encode all user input before reflecting it. However, this does not protect it from being vulnerable to DOM-based XSS vulnerabilities! If the web application passes your raw input into a DOM source, you may be able to execute javascript.
If you did find the access token in your local or session storage, all you've got to do is use the API to retrieve the token, and send it back to your end:
Access Tokens and JWTs in PWAs:
One thing I've encountered in the past was a web application that was built using the NextJS framework.It was vulnerable to DOM-based XSS, but I couldn't identify any kind of sensitive tokens in the local storage or session storage.However, if you're familiar with how Progressive Web Applications (PWAs) work, you'd understand that these save user data in the response body as a JSON object (to be retrieved later).
Progressive Web Apps are websites that look and feel like apps on your phone, and can even work offline (that's why you see sensitive data getting stored in the response).
Looks like magic right?
It's the service workers that make this possible.
You can think of Service Workers as scripts that run in the background and allow PWAs to intercept network requests, cache assets, and provide offline functionality.
Basically, a client-side proxy (a server that forwards requests) that helps pages load way faster.
You can usually identify a PWA using Wappalyzer or by just looking for the "__PWS_DATA__" id in one of the script tags.
All I had to do to obtain all user data (including PII such as the address, full name, phone number etc. + access token to invoke the API), was to read the data from the window property (or make a request to any page). Extract the script tag's value, and parse its contents using the JSON parse method to retrieve the access token for example. And send it back to my end.
In my case, the company was using Apollo GraphQL and had all that data stored inside the JSON object.
WordPress XSS to RCE:
Ever heard of XSS to RCE? Now you do.Next time when you find an XSS vulnerability in a CMS like WordPress, escalate it further via CSRF to remote code execution!I can't explain it any better than @brutelogic himself, but instead of going for an alert box, you basically trick the admin into visiting your XSS PoC link. And create a plugin on behalf of the admin!Easy, impactful yet most forget about this!
Additional Resources:
Cookie attributes by Mozilla Web Docs (explains cookie security flags in detail)
Use cookieStore() in case WAF blocked you by @PortSwiggerRes (basically, if session cookies are not HTTPOnly but document.cookie is blocked, you could still subscribe to the cookieStore interface and retrieve all cookies)
Account takeover through Session Data in IndexedDB by @SMHTahsin33 (this post walks you through on how you can extract data from IndexedDB)
XSS to RCE in Content Management Systems by @brutelogic
Weaponised XSS Payloads by @hakluke (drop him a follow as well)! This GitHub repo contains a set of payloads for upgrading your XSS to a P1 (RCE) for different CMSs (helped me get my very first account takeover through XSS a few years ago)!
Thank you for reading this far!
I hope you've enjoyed this post! In next week's issue, I will go through Broken Access Control issues! Stay tuned!
If you have any feedback, please do not hesitate to reach out! You can reply to this email or get in touch via Twitter DM!
Have a nice day and see you in the next post!
You can follow me on Twitter to receive upcoming updates on this newsletter:
Whenever you're ready, I can help you:
Get $200 in Digital Ocean credits to set up your Virtual Private Server:
Help you save time & earn more bounties using Nova Security: