嵌入式YouTube播放器告诉我您正在看什么

2021-01-19 02:00:40

2019年10月11日,00:16:我完成了几个小时前做的但没吃的冷冻比萨饼,最后写了报告,在Google安全漏洞提交表上按提交,然后看看经典的,谢谢!我们收到了您的报告。信息。这种感觉很难被击败。

我只是提交了一个错误,使用该错误,我可以简单地向某人发送链接,当他们单击该链接并访问我的网站时,我可以窃取他们的YouTube观看记录,观看他们所有未公开视频的链接,他们的稍后观看播放列表,他们喜欢的视频列表等等。真是太酷了。

这个问题需要对YouTube的内部运作有一点了解。最重要的是,关于以下四个有趣的播放列表:

由于YouTube由视频组成,因此YouTube中的许多内部内容都由播放列表组成。每个人都有几个,即使他们从未创造过一个。在发现此错误之前,我已经从以前的研究中了解了这些信息(通过先前的研究,我只是意味着尝试每个功能并试图理解它们的工作原理)。让我们一一看一下这些播放列表,因为它们在以后会变得很重要。

发现此错误时,每个YouTube用户都有一个ID为HL的播放列表,它代表“历史记录列表”(我假设)。此列表包含您以前在YouTube上观看的每个视频。

您可能已经在YouTube上到处看到小时钟图标,按下该按钮会将视频添加到“稍后观看”中。这也是内部带有ID WL的特殊播放列表。

这是一个棘手的问题。在发现错误时,我对它的工作方式有些困惑,因此我不得不多做一些猜测。我所知道的是,它是通过某种方式修改您的频道ID(长度为24个字符)构成的,可以通过进入频道页面并查看URL来找到它:

经过一番尝试和错误之后,通过查看测试/个人帐户的播放列表,我找到了一种“猜测”特殊“喜欢的视频”播放列表的方法。您只需要用LLD或LLB替换频道ID的前三个字符:

//其中之一将是给定频道“ UCBvX9uEO0a3fZNCK12MAgug”的“喜欢的视频”播放列表-> “ LLDvX9uEO0a3fZNCK12MAgug”“ UCBvX9uEO0a3fZNCK12MAgug”-> ” LLBvX9uEO0a3fZNCK12MAgug”

这个特殊的播放列表包含您所有的视频。无论视频的隐私设置如何,它都应有尽有。因此,您上载的所有公开,不公开和私有视频都在您的特殊“上传”播放列表中。

发现错误时,必须使用与“喜欢的视频”播放列表相同的猜测,但是这次,频道ID的前3个字符必须为UUD或UUB:

//其中之一将是给定频道“ UCBvX9uEO0a3fZNCK12MAgug”的“上传”播放列表-> “ UUDvX9uEO0a3fZNCK12MAgug”“ UCBvX9uEO0a3fZNCK12MAgug”-> ” UUBvX9uEO0a3fZNCK12MAgug”

或者,如果您不想执行任何操作,则可以转到频道页面,单击“视频”标签,然后单击“全部播放”。但是仅当该按钮可见时,不幸的是并非总是如此。

如果您对这些播放列表自2019年以来如何变化以及它们在撰写本文时的今天的工作方式方面的细节感兴趣,可以查看我撰写的这份Gist。

现在,您了解了每个YouTube用户拥有的这些特殊播放列表。现在,您可能会认为我们应该像打开其他任何播放列表一样打开某人的“上传”播放列表,而只是泄漏他们所有未列出的视频:

不幸的是,这并不容易。这些播放列表也有另一种特殊之处,那就是不同的用户会在其中看到不同的视频。如果频道所有者打开他/她的“上传”播放列表,则无论隐私设置如何,她都将看到她的所有视频。如果攻击者试图打开受害者的“上传”播放列表,则只会显示“公开”视频,而受害者没有看到的其他任何“不公开”和“私有”视频。

作为攻击者,我们可以清楚地看到这些播放列表可能包含有关用户的非常敏感的信息。我们想偷这些。但不幸的是,它们似乎受到了良好的保护……

如果您有一个网站,并希望其中包含一个小型YouTube播放器,那么可以使用一个应用程序。它被称为YouTube IFrame Player。将此播放器嵌入您的网站非常容易,您只需复制带有iframe标签的HTML代码,然后将其粘贴到您网站的源代码中:

但是如今的网站很少这么简单,所以您可能想知道,如果我想使用JavaScript动态创建YouTube播放器怎么办?如果我想自动暂停视频怎么办?由于同源策略的规则以及现代浏览器提供的其他保护,这些问题似乎非常棘手,甚至在某些情况下甚至是不可能的。

值得庆幸的是,YouTube还有一个解决方案,即YouTube Player API。使用此API,您只需将JS库添加到您的网站,然后就可以使用JavaScript在您想要的网站上随意创建/修改/控制YouTube播放器。例如,如果要暂停视频,则可以仅调用player.pauseVideo()。

嗯..这很有趣,但是它如何工作?如果您以前使用跨域(iframe)通信,则答案可能很明显。 YouTube播放器使用浏览器的PostMessage API,该API允许不同的来源(在我们的情况下为您的网站和YouTube iframe)通过安全通道互相发送小消息。因此,YouTube播放器具有一个postMessage侦听器,可在其中侦听命令,并且您要执行一些操作(如暂停视频)时,放入站点的JS库会向其发送消息。实际上,即使您什么都没问,YouTube播放器都会说话很多。如果播放器发生任何变化,它会立即告诉您站点上的JS库。这使您的站点可以添加事件侦听器,例如当用户跳入当前正在播放的视频时会被调用。

让我们看一个简单的例子,说明这种交流是如何进行的:

//当您调用“ player.playVideo()”时,此postMessage从您的网站发送到引擎盖下的iframe-> {"事件" :"命令" ," func" :" playVideo" ," args" :[]," ID" :1,"频道" :"小部件" } // iframe传回了很多东西,下面是一些示例<-{"事件" :" infoDelivery" ,"信息" :{" playerState" :-1,"当前时间" :0,"持续时间" :1344," videoData" :{" video_id" :" M7lc1UVf-VE" ,"作者" :"" ,"标题" :" YouTube Developers Live:嵌入式Web Player自定义" }," videoStartBytes" :0," videoBytesTotal" :1," videoLoadedFraction" :0,"播放质量" :"未知" ," availableQualityLevels" :[]," currentTimeLastUpdated_" :1610191891.79,"播放率" :1," mediaReferenceTime" :0," videoUrl" :" https://www.youtube.com/watch?v=M7lc1UVf-VE" ,"播放列表" :null,"播放列表索引" :-1}," ID" :1,"频道" :"小部件" }<-{"事件" :" onStateChange" ,"信息" :-1," ID" :1,"频道" :"小部件" }

提醒一下,我对此经常感到困惑,但是我刚刚展示的“幕后”命令是由您的站点发送的。所谓“幕后”,是指开发人员通常包括YouTube的库,以便于交流,而该库只是将细节抽象出来,因此您可以调用pauseVideo()而不用担心其他任何问题。但是,当然,如果愿意,您可以通过普通的旧式JavaScript将这些postMessage手动发送到播放器,并且其工作方式与使用高级JS库的方式完全相同。因此,可以将其视为完全控制的抽象层。

如果要查看页面收到的postMessages,可以将事件侦听器添加到页面,该事件侦听器将每条消息打印到控制台:

//侦听所有“消息”事件并将其记录到控制台:>窗口。 addEventListener("消息&#34 ;,函数(事件){控制台。日志(事件。数据)})

好的,我们可以使用JavaScript播放和暂停播放器。没什么疯狂的,但是很酷。我们还有什么可以做的吗?就在这里。实际上,如果您阅读了文档,则可以使用Player Player做很多事情。让我们来看一些对我们来说可能有趣的东西:

如果要将播放列表嵌入到站点中,则可以使用库的player.loadPlaylist(playlist_id)方法将播放列表加载到现有的嵌入式播放器中。之后,您可以调用playVideo(),并开始播放第一个视频,然后,播放列表中的下一个视频将自动开始播放,依此类推。因此,我们有播放列表支持。

现在,如果您想将播放列表嵌入网站,又想知道其中包含哪些视频,该怎么办?也有一个功能。在当前已加载播放列表的播放器上调用player.getPlaylist(),将按当前顺序返回播放列表中的视频ID数组:

>播放器。 getPlaylist()数组(20)[" KxgcVAuem8g" ," U_OirTVxiFE" ," rbez_1MEhdQ" ," VpC9qeKUJ00" ," LnDjm9jhkoc" ," BQIOEdkivao" ," layKyzA1ABc" ," -Y9gdQnt7zs" ," U_OX5vQ567Y" ," ghOqpVet1uQ" ,…]

如果查看原始的postMessage通信,通常可以看到iframe将一个名为videoData的对象发送到页面。该对象包含一堆有关当前播放的视频的内容,包括其标题。

>播放器。 getVideoData()对象{video_id:" KxgcVAuem8g" ,作者:" LiveOverflow2" ,标题:"不稳定555计时器-时钟模块" ,video_quality:"中" ,video_quality_features:[],列表:" PLGPckJAmiZCTyI72iI2KaJxkp-vUKBlTi" }

此功能未在YouTube的官方文档中列出,据说几年前已被删除,但正如Stack Overflow的一位同僚指出:

(即使正如我之前所说,即使将getVideoData()函数从库中完全删除了,只要iframe将对象发送到您的页面,您也可以访问它。)

如果您登录到YouTube,则嵌入式播放器也将“登录”。您在播放器中观看的视频将被添加到您的观看记录中。播放器中总是有一个小时钟图标,您可以使用它在以后将视频添加到帐户的手表中。因此,可以说,如果您已登录YouTube,则播放器也会登录,并且您的帐户具有“完全访问权”,就像YouTube的主要网站一样。

我真的很喜欢这个错误,因为它不需要任何花哨的“黑客技术”。可以这么说,实际上,当我发现此错误时,我甚至都没有在计算机上。

仅通过阅读本文的前两章,您可能已经将这两件事放在一起,并且还发现了错误。

当时,我已经看过YouTube一段时间了,分别测试播放列表,然后再测试嵌入式播放器。我找不到任何错误。然后,有一天,我记得我当时正站在电车上,可能正在去学校的路上(可能一如既往地晚了:(),我有了这个主意:

“等一等。只有拥有者才能看到她的播放列表的内容。我拥有以拥有者的名义播放任何播放列表的工具(因为嵌入式播放器也已“登录”到YouTube),并且我也具有从当前播放的播放列表中获取视频的工具。什么?这容易吗?”

原来那是那么容易。后来,在家里,我制作了一个页面,其中嵌入了YouTube播放器,并指示它播放播放列表HL(带有您的观看记录的播放列表),加载后,我调用了player.getPlaylist(),我想将结果打印到控制台。

我使用测试帐户打开了该页面,看到该测试帐户的观看记录已打印到控制台。

繁荣!我们有一个错误!您访问我的页面,我窃取了您的观看记录!不错。

我必须做一个漂亮的史诗般的POC,以证明攻击者可以使用此bug进行的所有操作。除了窃取您的观看记录,以下是利用此问题我能够进行的所有利用:

与HL播放列表类似,我们可以嵌入WL播放列表,然后使用player.getPlaylist()窃取受害者的“稍后观看”的内容。

接下来的这些攻击将需要有针对性的攻击,因为我们将要求的ID将基于受害者的通道ID。窃取HL和WL播放列表不需要任何特定于受害者的设置,因为每个人都有相同的ID。

前面我已经解释了如何获取“喜欢的视频”播放列表的播放列表ID。如果我以前知道受害者的频道ID,则可以设置一个页面来加载受害者的两个可能的播放列表ID,然后尝试使用player.getPlaylist()列出它们。尝试之一将成功,并且我将列出受害者以前喜欢的所有视频。

由于我们以“受害者的名义”播放这些播放列表,因此,如果受害者有任何定制的私人播放列表,并且我们已经知道它的ID(这将非常困难,因此影响很小),我们可以将其嵌入,并且像以前一样,只需使用getPlaylist()来窃取内容。

同样,我们还必须知道我们要定位的受害者的私人视频的ID,这很困难,并且可能需要其他错误。

但是,如果我们知道受害者的私有视频的ID,则可以将该私有视频嵌入到恶意网站中,并使用player.getVideoData()来窃取其标题以及其他一些有关其的其他信息,例如可用的字幕语言列表。

我最喜欢这种方式,因为许多人使用不公开的视频仅与特定的人共享个人/非公开视频。我也在这样做,我发送给Google的所有POC视频都是不公开的视频,我认为它们非常敏感。

因此,我之前已经解释了如何获取给定频道的“上传”播放列表的ID,并且正如您可能已经期望的那样,我们可以将该播放列表简单地嵌入到我们的恶意站点中。

发现此错误时,以所有者身份嵌入“上传”播放列表的工作与我预期的有所不同。之前我曾说过,尽管设置了隐私设置,所有者仍可以查看此播放列表中的所有视频。几乎仍然是这种情况,但是当嵌入“上载”播放列表时,所有者只能看到其中的公开和不公开视频,而私有视频则被忽略。对于当前的攻击来说,这很好,但这是一个限制,不允许我们泄漏所有的私有视频ID,并窃取所有私有标题(使用上次攻击)。或者,使用我以前的文章中的错误来窃取所有私人视频。

无论如何,我们都有“上传”播放列表的ID,可以将其嵌入到我们的网站中,然后使用player.getPlaylist()函数列出其中的所有视频ID。

如果某个视频不公开,则唯一使该视频保密的是其视频ID。现在,因为我们偷走了所有不公开的视频ID,所以我们可以观看受害者的所有不公开的视频!

这是我发送给Google的POC。不幸的是,当时我没有制作POC视频,并且由于此问题现已解决,因此我制作了一些屏幕截图以向您展示它的外观。

打开POC HTML会自动嵌入2个播放列表HL和WL,并将内容显示为播放器下方的两个列表:

向下滚动,您可以看到“针对性攻击”部分。输入频道ID后,它会列出您的“喜欢的视频”和“上传的视频”,包括未列出的视频。在此之下,您可以输入有权访问的私有视频ID,它会显示视频的标题并列出可用的字幕语言:

2019,十月11,01:15:我的部分做完了,我去睡觉。但是在上一次刷新我的电子邮件之前,希望我可能已经收到回复。这样的机会几乎为零,但是每次我发送错误时,激动的心情使我这样做。

经过两周的时间,以及一些误解之后,该错误被分类为“乍看之下,可能不够严重,无法获得奖励”。从那时起,这对我造成了很大的打击,我以前的所有错误都得到了相同的分类信息,找到这个信息后,我感到非常兴奋,并且非常肯定会获得强大的“不错的收获!我根据您的报告提出了一个错误。”首次。但是我没有。当时我经常发推文,所以让我有点沮丧:

我感到有些沮丧,因为我已经在Google VRP上进行了两个月的黑客攻击,而我的所有错误都得到了可能不够严重的信息。但是他们中的大多数仍在等待VRP小组关于奖励的决定,因此并非所有希望都丧失了。然而。

大约一个月后,我收到了来自[email protected]的新电子邮件。作为Google VRP错误猎人,这些是您正在寻找的电子邮件。我打开它,发现这个错误得到了$ 1,337的赏金。这是我的第一个“领导”奖赏。我发了一条跳舞鹦鹉的gif推文。我喜欢在这种情况下使用该gif:

当时我也觉得它很奇怪,但回头看,我仍然认为此错误的影响大于所颁发的奖励。仅考虑我的个人用例,从某人那里窃取所有可能未修复的Google bug的POC视频(因为我将其作为Unlisted video上传到YouTube)对我来说影响很大。甚至没有谈论观看历史。

我没有再与Google交流一下有关影响的感受,因此,如果我告诉他们我认为应该得到更多赏金的原因,他们可能会重新考虑奖励决定。如果您遇到类似情况,也不要害怕问。

收到奖励电子邮件后的16天,我收到一封新电子邮件,说问题已解决。我看看他们做了什么。

嵌入式播放器加载播放列表时,会使用/ list_ajax?list = [playlist-id]端点获取内容。现在,如果您将此端点提供任何专用/特殊播放列表,它将返回错误。因此,嵌入任何前面提到的播放列表将失败,并且播放器将显示错误。

这似乎已正确实现,但一个问题仍然存在,这是私有数据中videoData对象的泄漏,其中包括标题和一些其他信息。我ping了这个错误,说这个问题仍然有效。由于某些原因,我没有收到回复。我再次对Google进行ping操作,并得到答复说他们将使产品团队知道。

现在,在2021年,我回到了这个错误,并且我想在开始编写文章之前重新测试这些修复程序。事实证明,他们现在还修复了videoData泄漏。如果视频是私有的,您仍然可以嵌入它,但是播放器发送到您的站点的videoData只是一个空对象。

我喜欢这个错误的原因是,当有人问我如何寻找错误,或者他们应该如何寻找错误时,我总是会怎么说。我什至在之前的文章中说过:

“我认为,您对系统的了解越多,自然就会想到有关如何破解该系统的更多想法。”

[2019年10月11日]-报告了错误[2019年10月11日]-初步分类[2019年10月24日]-接受了错误(P4-> P2)[2019年11月14日]-发放了$ 1337的奖励[2019年11月30日] ]-错误的第一部分

......