Steam, Fire, and Paste – A Story of UXSS via DOM-XSS & Clickjacking in Steam Inventory Helper
While this is a serious vulnerability, on its own exploitation is fairly limited due to the user-interaction required to exploit it. The victim would have to open the page, paste a Cross-site Scripting (XSS) payload into the field, and click the “Add” button to exploit it.
In order to better weaponize this vulnerability we make use of a separate vulnerability (clickjacking) in order to bolster the attack.
The following is an excerpt from the Chrome extension’s manifest:
...trimmed for brevity... "web_accessible_resources": [ "_locales/*", "bundle/*", "dist/*", "assets/*", "font/*", "html/bookmarks.html", "css/*.css", "js/*.js", "js/jquery/*.js", "js/lang/*" ], ...trimmed for brevity...
The above section demonstrates that the extension casts a wide net with its “web_accessible_resources” policy. By default Chrome extensions prevent framing and navigation to Chrome extension pages from arbitrary web pages as an extra security measure. This directive loosens this restriction, allowing for third party pages to navigate to and frame the specified resources. Much of the extension’s privileged UI pages are specified under this directive, rendering the extension vulnerable to clickjacking.
As can also be seen in the excerpt, the “/html/bookmarks.html” page is also able to be framed and thus exploited via clickjacking. We abuse this to iframe this page in our web page, and overlay the frame with DOM elements to redress the layout. This makes it so that the victim is unaware that they are actually interacting with the extension below. The following animation demonstrates this effect:
The above example demonstrates how we redress the UI to trick the victim. The “Bot Detection” page provides a button to click to copy the “Verification code” to the victim’s clipboard. This “verification code” is actually a Cross-site Scripting (XSS) payload inside of a large amount of random hex bytes. This hides the payload from the victim’s view while they paste it into the extension’s textbox, leading the victim into believing they are just copying and pasting a long random code. Finally, when the victim clicks the “Add” button, the XSS fires.
Root Cause & Further Thoughts
There are two notable points of interest in this exploit. The first is that we were able to achieve DOM-XSS even with a fairly tight Content Security Policy (CSP) of the following:
"script-src 'self' 'unsafe-eval'; object-src 'self'"
While this CSP is fairly strong, it crumbles when combined with unsafe usage of jQuery’s DOM manipulation APIs such as “.html()” and “.append()”. This is something to look for when auditing Chrome extensions (and when writing them), if you make use of jQuery and have ‘unsafe-eval’ in your CSP – you’re playing with fire.
The second interesting point is that clickjacking is a valid vulnerability which can absolutely affect Chrome extensions. All that is required is that a privileged Chrome extension UI page be exposed via the “web_accessible_resources” directive. After taking a look at many of the popular extensions on the Chrome store it seems many of them fall victim this simple mistake. Most of the time this is due to accidental overscoping via wildcarding of a privileged extension HTML page. This not only opens up extensions to attacks like clickjacking but can result in other vulnerabilities if the extension takes in user input from “location.hash”, “postMessage”, etc. The default protection given to Chrome extensions via the navigation sandboxing should not be taken for granted by the extension developers.
- June 4: Disclosed to SIH TechSupport (owners of extension)
- June 6: Vendor confirms receipt of issue, states they will look into it and fix it.
- June 7: Vendor updates extension to fix the vulnerabilities.