Item | Comment |
---|---|
Software | Microsoft Azure Portal |
URL | https://portal.azure.com |
Type of Issue | Persistent Cross-Site Scripting |
CWE | https://cwe.mitre.org/data/definitions/79.html |
OWASP | https://owasp.org/www-community/attacks/xss/ |
Roles affected | All |
Privilege Escalation | User to Administrator |
CVSS | High – 7.7 |
Credits | Christian Becker & Sven Schlüter from Y-Security |
Summary
The notification widget of the Microsoft Azure Portal does not encode certain HTML characters. This allows to inject HTML and JavaScript code into the Azure Portal, which is reflected for other users (of the same Azure Active Directory Tenant).
The Persistent Cross-Site Scripting attack would allow to read and modify the content of the logged in user and provide a possibility to escalate privilege to those of a Portal Administrator.
Video
Steps to reproduce
Multiple ways to inject JavaScript code exists and we will show as an example how a standard user can attack an administrator in a Cross-Site Scripting attack:
1st: Steps for the Attacker (low privileged user)
- Open https://portal.azure.com
- Browse to “Azure Active Directory”
- Go to “Groups”
- Select “New Group”
- Provide a “Group name” of “Y<a target=”_parent” href=”javascript:alert(document.domain)//mailto:”>Y-Security“ and hit “Create”
2nd: Steps for the Administrator to trigger the attack
- Open https://portal.azure.com
- Browse to “Azure Active Directory”
- Go to “Users” and click any user
- Under “Manage –> Groups” click “Add memberships”
- Add the previous created group “Y<a target=”_parent” href=”javascript:alert(document.domain)//mailto:”>Y-Security“ by clicking on it and hit “Select”
The Microsoft Azure Portal automatically confirms the action with a notification on the upper right, which was found to render certain HTML tag:
The malicious code is also displayed in the Notifications panel (bell) and placed persistent in the notification widget:
The JavaScript code entered as part of the payload is executed whenever the text is clicked:
The JavaScript code is executed every time the group is used and gets displayed in the notification bar – making it a persistent issue.
Details of the attack vector
In the below we have split up the attack vector to explain it in more detail:
Y<a target="_parent" href="javascript:alert(document.domain)//mailto:">Y-Security
Injection | Description |
---|---|
Y | A single character is needed before an HTML element can be used |
<a | Opening for the a element |
target=”_parent” | By default the _target would be “_blank” and hence not executing our code |
href=” | Opening for the a href attribut |
javascript:alert(document.domain) | JavaScript code to display the current domain in an alert box |
//mailto: | The double slash is required to end the JavaScript command/comment out all further code. The mailto: is required to bypass the filter |
href=” | Closing href attribute value |
>Y-Security | Closing the A Element and appending a String |
Root Cause – Bypass of Allowed URL handlers
We have bypassed the allowed URL handlers by appending a mailto:. The following code snippet is from https://portal.azure.com/Content/Dynamic/jLscZOlMp2-g.js:
var d = MsPortalFx.Base.Diagnostics, f = /^(vstfs:|ftp:|ftps:|sftp:|storageexplorer:|adlalink:|adl:|asalink:|vscode:|vsweb:|azuredatastudio:|bfcomposer:|)\/\/|mailto:/, l = /^#(allservices|asset|blade|create|dashboard|home|menu|resource)\b/, e = /^#/, a = /^(data:image)\//;
The regular expression for all allowed protocol handlers requires “to start with one of the defined URL handlers followed by a double slash”, for example “ftp://”. mailto: is the only protocol handler which does not require a double slash and therefore is shown in an extra list. The “starts-with” (`^`) regular expression is missing: |mailto:. That allowed us to place the mailto: anywhere in the URI scheme and still get a valid response from the filter/regular expression.
Variants
We believe the URL handler bypass for mailto: is generic and could be abused in other places as well. The root issue relies in the notification widget, but can be triggered also when:
- Adding a new Administrative unit with a malicious name (like the above a Element) and assigning that unit to a group
- Adding a new user with a malicious display name (like the above a Element) and adding that user to a group
Another example of this generic injection can be found under https://portal.azure.com/#create/Microsoft.KeyVault using the Create Key Vault option with the payload in the Key vault name. The injection is reflected in the error message.
Recommendation
The mailto: filter should be changed to make sure it needs to be at the start of the string. This would already remediate the injection of JavaScript code in this instance. To mitigate against HTML injection it is recommended to perform HTML encoding.
Fix (10.09.2021)
The single character fix to mitigate the issue has been rolled out on the 9th of September 2021:
var d = MsPortalFx.Base.Diagnostics, f = /^(vstfs:|ftp:|ftps:|sftp:|storageexplorer:|adlalink:|adl:|asalink:|vscode:|vsweb:|azuredatastudio:|bfcomposer:|ms-quick-assist:|ms-remote-assist:|)\/\/|^mailto:/, l = /^#(allservices|asset|blade|create|dashboard|home|menu|resource)\b/, e = /^#/, a = /^(data:image)\//;
Now, it is verified that mailto is at the start of the URL scheme which prevents the above payload from being executed. It is still possible to inject some HTML characters but we couldn’t identify another vector to bypass the security controls and inject JavaScript within the time spend on the application.
Timeline
We have disclosed the issue to Microsoft MSRC and the public with the following timeline:
Date | Comment |
---|---|
19.08.2021 | Issue discovered |
20.08.2021 | Issue exploitability verified |
20.08.2021 | Issue opened with Microsoft MSRC |
08.09.2021 | Behavior confirmed & Investigation Started |
09.09.2021 | Issue remediated |
10.09.2021 | Added mitigation description & internal release |
15.09.2021 | Coordinated Public Disclosure |
Disclosure Policy
Please note: The vulnerability is subjected under the Y-Security Disclosure policy that be found here: https://www.y-security.de/disclosure-policy/index.html