As cyber threats continue to evolve, organisations are increasingly turning to penetration testing (PT) as a critical tool to assess their security posture and identify vulnerabilities that could be exploited by attackers. However, not all PTs are created equal, and relying solely on automated tools or scans can leave blind spots that real-world attackers could exploit.
That's why our industry-leading PT team takes a different approach, one that involves simulating a real-world attack by leveraging the same tools, techniques, and procedures that actual attackers use. By doing so, our team can more accurately mimic the tactics of a motivated attacker, identify and exploit vulnerabilities that may be missed by automated tools or scans, and ultimately provide our clients with a more comprehensive understanding of their security risks.
During a recent grey box web application penetration test, our experienced testing team uncovered a significant vulnerability that, if left unaddressed, could have allowed a malicious actor to gain unauthorised access to sensitive data.
Below we explain how our team found an ASP.Net XSS Filter Bypass.
Getting Started with XSS Discovery!
In this blog, I'll walk you through my experience discovering and exploiting a cross-site scripting (XSS) vulnerability during a penetration test on https://example.com.
To begin with, the first step was to enumerate the website and identify any areas where user input was accepted. After visiting the website, I was redirected to the login page at https://example.com/Portal/Login. By using the browser extension tool Wappalyzer and examining the source code, I discovered that the website was built using ASP.NET.
Using a tool like Burp Suite or OWASP ZAP, I began to submit various inputs to see how the application responded. During this process, I discovered that some user input was being reflected in an error page response. This meant that there was a potential vulnerability that could be exploited, as reflected user input is often a sign of an XSS vulnerability.
Input Reflected in Response
After identifying that user input was being reflected in an error page response, my first objective was to try and exploit this vulnerability to achieve an XSS attack. However, I quickly discovered that there was a character limit in place, which made it challenging to inject a payload that would trigger an XSS attack.
To overcome this limitation, I used the following payload:
This payload was designed to test whether the reflected input was being sanitized or not, and whether it could be used to inject arbitrary code. By adding the
<test> tag to the payload, I could quickly determine whether the payload was being executed on the server side or not. The long string of numbers was used to reach the character limit, which helped me confirm that there was a restriction in place.
Exploiting the XSS Vulnerability
After discovering that there was a 20-character limit on the reflected input, I began to research ways to bypass this limitation and trigger an XSS attack. I performed a Google search for "XSS 20 characters" and found some useful blogs and resources that helped me craft a payload that could bypass the limit.
The payload that ultimately worked for me was
It's worth noting that XSS vulnerabilities can be exploited in many ways, and the impact can range from a harmless pop-up message to a full-scale compromise of the victim's machine or the server itself. This is why it's essential to identify and remediate XSS vulnerabilities as soon as possible.
We got the pop-up! So what now?
Exploiting the XSS Vulnerability with Limited Character Limits
After successfully triggering an XSS pop-up using the
<svg/onload=alert``> payload, I was curious to see if I could bypass the 20-character limit and achieve a more sophisticated attack. However, to do so, I would need a domain with Unicode equivalence, IDN, or Emoji domains, which I didn't have access to during this pentest.
Undeterred, I decided to try and find another way to bypass the XSS filter. I started with the Portswigger XSS CheatSheet, but unfortunately, none of the techniques worked.
Next, I went back to basics and started trying different things. I eventually came up with the idea of adding one more "id" parameter to the URL, like so:
Bypassing the Character Limit to Achieve XSS
After discovering that the previous technique of adding an additional "id" parameter to the URL still hit the character limit, I continued to experiment with different approaches.
My next idea was to try using the
<b>12345</b> payload as a parameter, like so:
https://example.com/Portal/Password?id=test&<b>12345</b>. Unfortunately, this resulted in a 404 error page, indicating that the server was rejecting the request.
However, upon closer inspection of the previous response, I noticed that the reflection started with
id="reflection". With this in mind, I decided to modify the URL to include
12345= like so:
/Portal/Password?id=test&<b>12345=</b>. This technique still did not work, and I was starting to feel frustrated.
Our first attempt involved adding an additional id parameter, but it didn't work. We then tried using <b>12345=</b> as the parameter, but that resulted in a 404 page. However, we noticed that the response from the previous attempt started with id="reflection", which gave us an idea to try <b>12345=</b> twice. This time, we successfully received a reflection with no "id=" in the response.
Excited to proceed, we added the XSS payload using the URL https://example.com/Portal/Password?id=test&<b>12345=</b><script>alert(‘XSS’)</script><b>12345=</b>.
But it didn't work as expected. After several attempts, we finally discovered the correct payload: https://example.com/Portal/Password?id=test&<b>12345</b><script>alert(‘XSS’)</script><b>12345=</b>.
With this, we were able to bypass the character limit and successfully execute an XSS attack!
XSS Filter Bypassed!
Hence, we can now exploit this easily without any special needs!!