← back to writing

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 everythingraft-large uncovered 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 :)