Official extension spoofing attacks: when trusted add-ons are not so trusted
4 min read
Many applications have official extensions; these are pieces of software that allow users to add new functionalities and features to improve interaction with the rest of the company's products.
Products regularly allow the integration of official and third-party extensions from their websites or desktop applications.
Today, I will share a vulnerability I found while auditing a software solution widely used worldwide by companies called … I'm sorry, but I won't say the solutions name or the actual objects with which it interacts :P ; the important thing here is to share the technique so that you can consider it every time your team designs or audits a solution that allows adding functionality through extensions ;) .
As I mentioned before, I won't say the kinds of stuff with which it interacts; however, we will suppose that the application allows you to generate a parent company and subsidiaries for illustrative purposes. In addition to the above, I must point out that it has a super administrator, who has access to the parent company, and can a) create subsidiary companies, b) access them, and c) create users for each subsidiary company; which means that for each subsidiary company, it's possible to create users with different roles such as administrators, configuration editors, viewers, among others.
The application has a section to install official (see Figure 1) and third-party (see Figure 2) extensions. This one is available to the parent company and subsidiary companies.
Figure 1. Official extensions tab
Figure 2. Third-Party extensions tab
During testing, I realized 1) that all official extensions are hosted on GitHub and 2) that third-party extensions must contain a file called extension.json and follow specific code requirements to load correctly on the platform.
For the tests, I had different users and roles, but for this article, I will mention two:
- Super administrator, who had access to the parent company and subsidiary A, subsidiary B, and subsidiary C.
- Config publisher account that only had access to subsidiary company A.
I tried to load third-party extensions from the account as configuration editor of subsidiary company A but couldn't because they didn't meet the requirements. So, I decided to create an account on GitHub, clone one of the official extensions: Users Management Dashboard, and host it on my repository: https://github.com/my_account/User-Mgmt-Dashboard-Clone
Next, I loaded the cloned extension URL (https://github.com/my_account/User-Mgmt-Dashboard-Clone) in the 3rd Party-Extensions section (see Figure 3), but I couldn't see it from the Third Party Extensions tab even though the server returned that the cloned extension was loaded through a 200 OK response (see Figure 4).
Figure 3. Loading the cloned extension
Figure 4. A response confirming that the cloned extension was loaded successfully
At that point, I decided to open my repository, open the file extension.json and change the extension name from user-management-dashboard to user-management-dashboard-clone. I went to the 3rd Party Extensions tab and reloaded the cloned extension URL, and realized that I could already see the extension in the 3rd Party Extensions tab (Figure 5).
Figure 5. The renamed cloned extension is visible in the Third Party Extensions tab.
At that moment, I suspected that perhaps the first time I loaded the cloned extension, it had been loaded correctly. But since it had the same name as the official extension, it had overwritten the official extension URL.
To confirm my suspicions, I opened my repository, edited extension.json, changed the extension name to the last name (user-management-dashboard), reviewed the code, and added some XSS inside so that when a user opens the dashboard, an alert is displayed.
Once I saved all changes in my repository, I went to the 3rd Party Extensions tab, deleted the extension I had previously loaded, and loaded the modified cloned extension URL again (see Figure 6).
Figure 6. Loading the modified cloned extension
And as before, the extension was not loaded in the 3rd Party Extensions tab. But this time, I decided to go to the Official Extensions tab and open the Users Management Dashboard extension (Figure 7). As soon as the extension was opened, the XSS was executed (see Figure 8).
Figure 7. Opening the Users Management Dashboard
Figure 8. XSS is triggered when a user opens the fake official extension
Once I confirmed my suspicions, I decided to elevate the impact as maximum as possible. After analyzing the solution, I realized that every time a user opens an extension, it generates a token so that the extension can consume company information.
This extension may have the privileges requested at the time of installation, but these will also be subject to the role of the users who visit it, that is, if a viewer user opens the extension, the extension can only be assigned a token with user read privileges, regardless of the extension requires additional privileges such as editing users to work 100%.
As shown in Figure 9, I reloaded the cloned extension URL and intercepted the request at install time. I changed the company name to partner_company and increased the privileges (I extracted these privileges from the developer's documentation that the solution provides to third parties that want to create extensions).
Figure 9. Edited request to install a fake official extension with full access to the parent company
When my editor user tried to open the extension, the app would immediately return an error message: Forbidden, since my editor user did not have access to the parent company. However, as shown in Figure 10, when the super admin user opened the extension (from the subsidiary company A), the solution generated a token for the extension with all permissions on the parent company. One moment, did I say parent company? Yes, instead of loading it with information from subsidiary company A, it uploaded information from the parent company (the environments are not as isolated as we thought).
Figure 10. Parent company information is loaded from the Subsidiary A environment
Since the source of this extension is the cloned malicious extension, and I have access to the source code, the next step was to steal the token via XSS and perform an account takeover attack on the parent company's super admin account. The moral of the story is: be wary of extensions, even official ones, because they may have been tampered with by an attacker. Does your solution allow installing extensions? Has it already been audited by our Strikers team? I hope you had as much fun reading this article as when I exploited this vulnerability.
Yesenia Trejo is our Lead Striker