Cross-Site Scripting (XSS): Custom payload crafting

The Ultimate Guide In Crafting Payloads And Exploiting XSS Vulnerabilities For Higher Bounties

The Ultimate Guide In Crafting Payloads And Exploiting XSS Vulnerabilities For Higher Bounties

Today's estimated reading time is: 10 min (hope you like the new theme colors!)

Today, you'll learn how to craft your own payloads to bypass filters and web application firewall rules!Let's get into it!This post assumes you've identified a valid injection point that allows you to render HTML tags. If this is not the case (yet), read the following post: [#1] Cross-Site Scripting (XSS)

Table of Contents:

  • Reflected & Stored XSS

  • DOM-based XSS

  • Resources

Reflected & Stored XSS:

In order to craft a payload, you first need to be aware of a few things.First of all, your context. Is your injection point inside a script tag? Is it inside a value of an HTML attribute? Or between a specific HTML tag (for example style tags)?You should always determine your injection point before crafting any payload. Your script alert(1) payload won't work everywhere.

If your input got reflected inside the style tag (or any other tag that doesn't directly allow you to render tags that can execute javascript code, such as the textarea), then it is recommended to first close the preceding tag before opening the new one (your payload):

Another example. In case your unencoded input got reflected inside the script tags (as a value of a variable for example), then you should close the value and add a function.In the code snippet below, assume that the "lang" query parameter's value gets reflected inside the javascript variable:

Another example. If your input was reflected inside an href attribute of an a-tag for example, you could inject a payload that uses the javascript protocol (assuming that the opening & closing tags are encoded or escaped):

Remember that you should always go for a payload that executes with no additional user input needed possible:

Now that we got the basics, we should start crafting our payload using various bypassing techniques. To make things easier, let's first get into the developer's mind:I'm a full-stack developer myself, and whenever I see developers recommending security measures to each other on public forums (Stack Overflow for example).I see that they are most of the time aware of any security vulnerabilities that may be present but have a quite vague understanding of any existing bypasses.And XSS is one of them. Some think that XSS vulnerabilities are all about tags, and try to solve this by encoding input based on a loose regex pattern.Can you tell me what's wrong with the following pattern? It seems to do the job, no?

No worries if you couldn't figure it out yet, after all, you're reading this post to learn more about crafting payloads & bypassing rules!First of all, it only matches input when it is delivered with an opening AND a closing tag. The second thing, it's a global pattern and not a multi-line pattern. This means it will only check for matches of the pattern on the first line.This can easily be bypassed in multiple ways:

  • This regex won't be helpful if your injection point is inside the value of an HTML attribute or the href attribute of an a-tag for example.

  • This regex can easily be bypassed using CRLF characters as it only checks for it on 1 line.

  • This regex only checks for an opening AND a closing tag (and everything in between). However, we can omit the closing tag in some common cases.

  • This regex won't be helpful if any input is passed to a DOM sink (depending on the sink, you can in some cases also pass escaped Unicode characters.

Let's take a closer look by using the pattern to match against different variations of our payload on https://regexr.com/ :

Wondering how a payload without a closing tag works? Here's an example:

You can apply the same bypasses if the keyword or the pattern /javascript/g is used (this is how I found so many XSS vulnerabilities).There are so many ways to bypass rules.Here's an example of how I used the techniques above to craft payloads that bypass (custom) WAF rules for example:

In the example above, I used the SVG tag (it was one of the tags that were allowed) in combination with the "onload" event handler. I used a double URL encoded Carriage Return character and made use of hostname (instead of document domain as "document" was blocked)You could also concatenate code as it is much harder to detect:

Now that we've covered most of the bypasses, there's another type of stored XSS that is quite common when no (basic) validation is done in file upload features.As I stated in my previous post, it is possible to execute javascript in script-based contexts. This means that SVG and XML files for example are also capable of executing javascript.Here's one for an SVG file for example:

It is always recommended to try and upload SVG files when there's a file upload on your target.

DOM-based XSS:

For DOM-based XSS, a payload really depends on the sink to which it'll end. For example, a script tag won't work in the example below:

DOM XSS example

However, the javascript protocol will. I've encountered a lot of times where "javascript" is blacklisted or just some parts (such as "java" or "script" is blacklisted).I was almost always able to bypass it using URL-encoded CRLF characters (remember multi-line??).I also encountered cases where everything is whitelisted as long as it matches the following pattern (the app wanted to support HTTP as well as mobile app links):

The developer might've thought that this was safe, right? Or is it?

It isn't, using a URL-encoded line separator character (U+2028) we can easily circumvent the regex pattern and still inject our malicious code.

Now what if your input got in the "innerHTML" sink AND opening and closing tags are filtered?

Use Unicode! Supplying the following payload would render an image tag with the "onerror" event handler. I recommend using tools like CyberChef and Burpsuite's decoder or Hackvector to encode/decode text easily:

There are countless amount of bypasses like these, as every target is different, I keep trying different ways until I find one that works.

Resources:

I also recommend keeping an eye on Twitter's bug bounty community as most of the time, new WAF bypasses get shared there.

Thank you for reading this far!

I hope you've enjoyed this post! In the next newsletter issue, I will go through a topic I still need to figure out (suggest me some)! Stay tuned!By the way, congratulations on making it this far! You are one of the few who have come this far and you make much more chance to complete this guide and become a bug bounty hunter!

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: