403 Forbidden? No Problem, Here’s a POST XSS
Greetings to all the brilliant minds in the hacking community! I go by the name Remmy, and I’d like to share my experience with a successful POST XSS exploitation, which came after encountering a 403 Forbidden error on the application’s main web-page. Let’s dive into the write-up.
Reconnaissance
The target accepted any subdomains, let’s call it redacted.com, the scope was:
*.redacted.com
I conducted a subdomain enumeration using tools such as Subfinder, Amass, and crt.sh. Additionally, I performed a DNS brute force, resulting in the discovery of nearly 40,000 subdomains. After running httpx on these subdomains, I identified approximately 2,500 live and active ones.
After dedicating several days to the target, I stumbled upon a subdomain named:
rplicense.redacted.com
When I opened the website, it showed me a 403 — Forbidden: Access is denied.
Breaking the 403
Upon encountering the 403 Error, I decided to test whether it was a global restriction affecting all pages or specific to the main page by providing the subdomain with a dummy path:
rplicense.redacted.com/dummy
After inputting the dummy path, the 403 status code transformed into a 404 Not Found, indicating that the 403 code was exclusive to the main web page and not applicable to every conceivable path.
At this point, I commenced fuzzing the web application using ffuf along with a wordlist named raft-large. Here’s the command:
ffuf -u "rplicense.redacted.com/FUZZ" \
-w /path/to/word-list \
-H "User-Agent: Mozilla/5.0 (Galaxy S22; Android 6) AppleWebKit/537.48 (KHTML, like Gecko) Chrome/111.0.5628.105 Mobile Safari/537.48" \
-rate 20
After approximately 30 to 40 minutes of fuzzing, I stumbled upon a path named /archive.
First Attempt
Within this /archive directory, there was a form where you could submit your email address. In the email address field, I injected my XSS payload:
<script>alert(origin)</script>
The web application stopped me and gave me an error:
The email address contains malicious character, please try again
Indeed, it can be quite frustrating. Nevertheless, I persevered and resumed fuzzing the web application, this time focusing my efforts on the /archive directory.
Digging Deeper
After conducting further fuzzing on the /archive directory, I uncovered two additional paths:
/download.asp/mail.asp
Both of these paths featured forms where you could input your email address. I decided to test my luck again and submitted my payload on /download.asp, only to encounter the same error once more. It seemed like a persistent challenge!
However, when it came to /mail.asp, it turned out to be a different story. Upon opening the /mail.asp page, I noticed that the form structure was identical to that of /download.asp. Without hesitation, I submitted my payload, and to my delight, BOOM! The JavaScript executed successfully, marking a significant breakthrough in my exploitation efforts.
The vulnerable parameter was email_address.
Exploitation
Following the successful execution of the exploit on /mail.asp, I reached out to my friend Ayrix to host the payload on his server since I didn’t have access to Nginx or Apache at that time. I then promptly composed a detailed report summarizing the findings and submitted it to the program.
Result
Within a mere 2–3 days, Bugcrowd triaged the report, and I received a well-deserved three-digit bounty reward from the application. It was a satisfying conclusion to the entire endeavor.
Key Takeaways
- Never trust a 403 — it might only protect the root path, leaving everything else exposed
- Fuzz everything —
raft-largeuncovered hidden paths that led to the vulnerability - Same form, different backend — two identical-looking forms can have completely different validation logic
- POST XSS is still alive — don’t focus only on GET-based reflection
Through diligent fuzzing and persistence, a 403 turned into a bounty.
Don’t forget to follow me on Twitter :)