mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-26 19:54:37 +03:00
8cae0648ec
Demand-driven expansion targeting the fastest-growing 2025-2026 threat and
skills categories (ISC2/WEF/CrowdStrike/Mandiant signals):
- AI Security (NEW domain, 12 skills): LLM red-teaming with garak/PyRIT,
prompt injection (direct/indirect/RAG), MCP tool-poisoning, agentic tool
invocation, guardrails, model/data poisoning, system-prompt leakage,
embedding/vector weaknesses, model extraction, continuous red-teaming
- Supply Chain Security (NEW domain, 5 skills): SBOMs, dependency confusion,
malicious-npm triage, typosquatting, SLSA/Sigstore provenance
- Hardware & Firmware Security (NEW domain, 4 skills): CHIPSEC/UEFI audit,
Secure Boot bypass, TPM measured-boot attestation, ESP bootkit hunting
- Identity (10): Entra ID/ROADtools, GraphRunner, AADInternals, ADCS/Certipy,
shadow credentials, coercion, BloodHound CE, device-code phishing, SSO abuse
- Cloud-native (8): Stratus, Pacu, CloudFox, container escape, K8s RBAC,
Falco, Trivy, kube-bench
- Offensive C2 (6): Sliver, Havoc, NetExec, DPAPI, NTLM relay ESC8, redirectors
- DFIR (6): Hayabusa, Chainsaw, KAPE, Velociraptor, EZ Tools, Plaso
- Backfill (4): OpenCTI, MISP, honeytokens, post-quantum crypto migration
Each skill follows the repo taxonomy (SKILL.md + references/{standards,api-reference}.md
+ scripts/agent.py + LICENSE), with researched real tool commands (no placeholders),
complete frontmatter, and ATT&CK/ATLAS + NIST CSF mappings. Updates README domain
table, skill count, and index.json.
134 lines
5.2 KiB
Python
134 lines
5.2 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
agent.py - Hunt Entra offensive-tool fingerprints in Graph activity logs.
|
|
|
|
Runs curated KQL hunts against an Azure Log Analytics / Microsoft Sentinel
|
|
workspace using the Azure Monitor Query REST API. Authentication uses an
|
|
AAD bearer token (pass --token, or set AZ_MONITOR_TOKEN). Obtain one with:
|
|
|
|
az account get-access-token --resource https://api.loganalytics.io \
|
|
--query accessToken -o tsv
|
|
|
|
Defensive/blue-team tool. Use with appropriate Log Analytics read permissions.
|
|
|
|
References:
|
|
- Azure Monitor Query API https://learn.microsoft.com/rest/api/loganalytics/dataaccess/query/get
|
|
- AADGraphActivityLogs https://learn.microsoft.com/entra/identity/monitoring-health/concept-aad-graph-activity-logs
|
|
"""
|
|
import argparse
|
|
import json
|
|
import os
|
|
import sys
|
|
import urllib.request
|
|
import urllib.error
|
|
|
|
API = "https://api.loganalytics.io/v1/workspaces/{ws}/query"
|
|
|
|
HUNTS = {
|
|
"ingestion": """
|
|
union withsource=Tbl MicrosoftGraphActivityLogs, AADGraphActivityLogs
|
|
| where TimeGenerated > ago({days}d)
|
|
| summarize Records=count(), LastSeen=max(TimeGenerated) by Tbl
|
|
""",
|
|
"roadtools-ua": """
|
|
AADGraphActivityLogs
|
|
| where TimeGenerated > ago({days}d)
|
|
| where RequestMethod == "GET"
|
|
| where UserAgent contains "python" and UserAgent contains "aiohttp"
|
|
| summarize RequestCount = count() by CallerIpAddress, AppId, UserAgent, UserId
|
|
| sort by RequestCount desc
|
|
""",
|
|
"tool-agents": """
|
|
union MicrosoftGraphActivityLogs, AADGraphActivityLogs
|
|
| where TimeGenerated > ago({days}d)
|
|
| where UserAgent has_any ("AADInternals","aad-internals","azurehound","BloodHound","Go-http-client")
|
|
| project TimeGenerated, UserAgent, CallerIpAddress, AppId, UserId, RequestUri
|
|
| sort by TimeGenerated desc
|
|
""",
|
|
"endpoint-sweep": """
|
|
AADGraphActivityLogs
|
|
| where TimeGenerated > ago({days}d)
|
|
| where RequestMethod == "GET"
|
|
| extend TopLevelResource = tolower(tostring(split(split(RequestUri, "?")[0], "/")[3]))
|
|
| summarize TopLevelResources = make_set(TopLevelResource), AppIds = make_set(AppId),
|
|
CallerIPs = make_set(CallerIpAddress), UserAgents = make_set(UserAgent),
|
|
StartTime = min(TimeGenerated), EndTime = max(TimeGenerated)
|
|
by UserId, bin(TimeGenerated, 5m)
|
|
| where TopLevelResources has_all ("users","tenantdetails","groups","applications",
|
|
"serviceprincipals","devices","directoryroles","roledefinitions","contacts",
|
|
"oauth2permissiongrants","authorizationpolicy")
|
|
| project StartTime, EndTime, UserId, AppIds, CallerIPs, UserAgents
|
|
""",
|
|
"volume-outlier": """
|
|
MicrosoftGraphActivityLogs
|
|
| where TimeGenerated > ago({days}d)
|
|
| where RequestMethod == "GET"
|
|
| where RequestUri has_any ("/users","/groups","/servicePrincipals","/applications","/directoryRoles","/roleManagement")
|
|
| summarize Reads=count(), Resources=dcount(RequestUri) by UserId, AppId, CallerIpAddress, bin(TimeGenerated, 10m)
|
|
| where Reads > {threshold}
|
|
| sort by Reads desc
|
|
""",
|
|
}
|
|
|
|
|
|
def run_query(workspace, token, kql):
|
|
url = API.format(ws=workspace)
|
|
body = json.dumps({"query": kql}).encode()
|
|
req = urllib.request.Request(url, data=body, method="POST", headers={
|
|
"Authorization": f"Bearer {token}",
|
|
"Content-Type": "application/json",
|
|
})
|
|
try:
|
|
with urllib.request.urlopen(req, timeout=120) as r:
|
|
return json.loads(r.read().decode())
|
|
except urllib.error.HTTPError as e:
|
|
raise SystemExit(f"[!] query failed HTTP {e.code}: {e.read().decode(errors='replace')[:300]}")
|
|
except urllib.error.URLError as e:
|
|
raise SystemExit(f"[!] network error: {e.reason}")
|
|
|
|
|
|
def print_table(result):
|
|
tables = result.get("tables", [])
|
|
if not tables:
|
|
print(" (no tables returned)")
|
|
return
|
|
t = tables[0]
|
|
cols = [c["name"] for c in t.get("columns", [])]
|
|
rows = t.get("rows", [])
|
|
print(" " + " | ".join(cols))
|
|
if not rows:
|
|
print(" (0 rows)")
|
|
for row in rows[:50]:
|
|
print(" " + " | ".join(str(v) for v in row))
|
|
if len(rows) > 50:
|
|
print(f" ... {len(rows) - 50} more rows")
|
|
|
|
|
|
def main():
|
|
p = argparse.ArgumentParser(description="Hunt Entra offensive-tool fingerprints in Graph logs.")
|
|
p.add_argument("--workspace", required=True, help="Log Analytics workspace ID (GUID)")
|
|
p.add_argument("--token", default=os.environ.get("AZ_MONITOR_TOKEN"),
|
|
help="AAD bearer token for api.loganalytics.io (or set AZ_MONITOR_TOKEN)")
|
|
p.add_argument("--hunt", choices=list(HUNTS) + ["all"], default="all",
|
|
help="Which hunt to run")
|
|
p.add_argument("--days", type=int, default=7, help="Lookback window in days")
|
|
p.add_argument("--threshold", type=int, default=200,
|
|
help="Read-count threshold for volume-outlier hunt")
|
|
args = p.parse_args()
|
|
|
|
if not args.token:
|
|
raise SystemExit("[!] provide --token or set AZ_MONITOR_TOKEN "
|
|
"(az account get-access-token --resource https://api.loganalytics.io)")
|
|
|
|
selected = list(HUNTS) if args.hunt == "all" else [args.hunt]
|
|
for name in selected:
|
|
kql = HUNTS[name].format(days=args.days, threshold=args.threshold)
|
|
print(f"\n=== HUNT: {name} (last {args.days}d) ===")
|
|
result = run_query(args.workspace, args.token, kql)
|
|
print_table(result)
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|