mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-07-13 19:05:17 +03:00
Add folder anatomy (scripts/agent.py + references/api-reference.md) for 648 cybersecurity skills
Complete skill folder anatomy across all cybersecurity skills: - scripts/agent.py: 80-150 line Python agents using real libraries (impacket, boto3, azure-mgmt-*, kubernetes, pefile, yara, scapy, shodan, stix2, etc.) - references/api-reference.md: real API documentation with method signatures - LICENSE: MIT license for all skill folders
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 Anthropic Agent Skills Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
# API Reference: Implementing Passwordless Auth with Microsoft Entra
|
||||
|
||||
## Libraries
|
||||
|
||||
### msal (Microsoft Authentication Library)
|
||||
- **Install**: `pip install msal`
|
||||
- **Docs**: https://msal-python.readthedocs.io/
|
||||
- `ConfidentialClientApplication()` -- App registration auth
|
||||
- `acquire_token_for_client()` -- Client credentials flow
|
||||
|
||||
### Microsoft Graph API
|
||||
- **Base**: `https://graph.microsoft.com/v1.0` and `/beta`
|
||||
- **Docs**: https://learn.microsoft.com/en-us/graph/api/overview
|
||||
|
||||
## Authentication Methods Policy API
|
||||
|
||||
| Endpoint | Description |
|
||||
|----------|-------------|
|
||||
| `GET /policies/authenticationMethodsPolicy` | Full auth methods config |
|
||||
| `GET /users/{id}/authentication/methods` | User's registered methods |
|
||||
| `GET /users/{id}/authentication/fido2Methods` | FIDO2 keys for user |
|
||||
| `GET /users/{id}/authentication/microsoftAuthenticatorMethods` | Authenticator setup |
|
||||
| `GET /users/{id}/authentication/windowsHelloForBusinessMethods` | WHfB status |
|
||||
|
||||
## Conditional Access API
|
||||
|
||||
| Endpoint | Description |
|
||||
|----------|-------------|
|
||||
| `GET /identity/conditionalAccess/policies` | List CA policies |
|
||||
| `GET /identity/conditionalAccess/authenticationStrength/policies` | Auth strength policies |
|
||||
|
||||
## Sign-In Logs API
|
||||
|
||||
| Endpoint | Description |
|
||||
|----------|-------------|
|
||||
| `GET /auditLogs/signIns` | Sign-in activity logs |
|
||||
| Filter: `authenticationDetails/any(a:a/authenticationMethod eq 'FIDO2 security key')` |
|
||||
|
||||
## Authentication Method Types
|
||||
- `fido2AuthenticationMethod` -- FIDO2 security keys
|
||||
- `microsoftAuthenticatorAuthenticationMethod` -- Authenticator app
|
||||
- `windowsHelloForBusinessAuthenticationMethod` -- Windows Hello
|
||||
- `passwordAuthenticationMethod` -- Traditional password
|
||||
- `phoneAuthenticationMethod` -- SMS/phone call (legacy)
|
||||
- `emailAuthenticationMethod` -- Email OTP
|
||||
|
||||
## Required Graph Permissions
|
||||
- `UserAuthenticationMethod.Read.All`
|
||||
- `Policy.Read.All`
|
||||
- `AuditLog.Read.All`
|
||||
- `User.Read.All`
|
||||
|
||||
## External References
|
||||
- Entra Passwordless: https://learn.microsoft.com/en-us/entra/identity/authentication/concept-authentication-passwordless
|
||||
- FIDO2 Keys: https://learn.microsoft.com/en-us/entra/identity/authentication/howto-authentication-passwordless-security-key
|
||||
- Graph Auth Methods: https://learn.microsoft.com/en-us/graph/api/resources/authenticationmethods-overview
|
||||
- Conditional Access Auth Strength: https://learn.microsoft.com/en-us/entra/identity/authentication/concept-authentication-strengths
|
||||
@@ -0,0 +1,206 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Microsoft Entra ID passwordless authentication audit agent using MS Graph API."""
|
||||
|
||||
import json
|
||||
import sys
|
||||
import argparse
|
||||
from datetime import datetime
|
||||
|
||||
try:
|
||||
import requests
|
||||
from msal import ConfidentialClientApplication
|
||||
except ImportError:
|
||||
print("Install: pip install msal requests")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
GRAPH_URL = "https://graph.microsoft.com/v1.0"
|
||||
GRAPH_BETA = "https://graph.microsoft.com/beta"
|
||||
|
||||
|
||||
def get_access_token(tenant_id, client_id, client_secret):
|
||||
"""Authenticate to Microsoft Graph using client credentials."""
|
||||
app = ConfidentialClientApplication(
|
||||
client_id, authority=f"https://login.microsoftonline.com/{tenant_id}",
|
||||
client_credential=client_secret)
|
||||
result = app.acquire_token_for_client(scopes=["https://graph.microsoft.com/.default"])
|
||||
if "access_token" in result:
|
||||
return result["access_token"]
|
||||
print(f"[!] Auth failed: {result.get('error_description', 'Unknown error')}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def graph_get(token, endpoint, beta=False):
|
||||
"""Make authenticated GET request to Microsoft Graph."""
|
||||
base = GRAPH_BETA if beta else GRAPH_URL
|
||||
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
|
||||
resp = requests.get(f"{base}{endpoint}", headers=headers)
|
||||
resp.raise_for_status()
|
||||
return resp.json()
|
||||
|
||||
|
||||
def get_auth_methods_policy(token):
|
||||
"""Get authentication methods policy to check passwordless configuration."""
|
||||
return graph_get(token, "/policies/authenticationMethodsPolicy", beta=True)
|
||||
|
||||
|
||||
def get_fido2_policy(token):
|
||||
"""Get FIDO2 security key configuration."""
|
||||
policy = get_auth_methods_policy(token)
|
||||
for method in policy.get("authenticationMethodConfigurations", []):
|
||||
if method.get("id") == "fido2":
|
||||
return {
|
||||
"state": method.get("state"),
|
||||
"is_attestation_enforced": method.get("isAttestationEnforced"),
|
||||
"is_self_service_allowed": method.get("isSelfServiceRegistrationAllowed"),
|
||||
"key_restrictions": method.get("keyRestrictions", {}),
|
||||
}
|
||||
return {"state": "not_configured"}
|
||||
|
||||
|
||||
def get_microsoft_authenticator_policy(token):
|
||||
"""Get Microsoft Authenticator configuration."""
|
||||
policy = get_auth_methods_policy(token)
|
||||
for method in policy.get("authenticationMethodConfigurations", []):
|
||||
if method.get("id") == "microsoftAuthenticator":
|
||||
return {
|
||||
"state": method.get("state"),
|
||||
"feature_settings": method.get("featureSettings", {}),
|
||||
}
|
||||
return {"state": "not_configured"}
|
||||
|
||||
|
||||
def get_windows_hello_policy(token):
|
||||
"""Get Windows Hello for Business configuration."""
|
||||
policy = get_auth_methods_policy(token)
|
||||
for method in policy.get("authenticationMethodConfigurations", []):
|
||||
if method.get("id") == "windowsHelloForBusiness":
|
||||
return {"state": method.get("state")}
|
||||
return {"state": "not_configured"}
|
||||
|
||||
|
||||
def list_user_auth_methods(token, user_id):
|
||||
"""List authentication methods registered by a specific user."""
|
||||
try:
|
||||
methods = graph_get(token, f"/users/{user_id}/authentication/methods")
|
||||
return [{"id": m.get("id"), "type": m.get("@odata.type", "").split(".")[-1]}
|
||||
for m in methods.get("value", [])]
|
||||
except Exception as e:
|
||||
return [{"error": str(e)}]
|
||||
|
||||
|
||||
def get_users_without_passwordless(token, max_users=100):
|
||||
"""Identify users who have not registered any passwordless method."""
|
||||
users = graph_get(token, f"/users?$top={max_users}&$select=id,displayName,userPrincipalName")
|
||||
users_without = []
|
||||
for user in users.get("value", []):
|
||||
methods = list_user_auth_methods(token, user["id"])
|
||||
passwordless_types = {"fido2AuthenticationMethod", "microsoftAuthenticatorAuthenticationMethod",
|
||||
"windowsHelloForBusinessAuthenticationMethod"}
|
||||
user_types = {m.get("type") for m in methods if not m.get("error")}
|
||||
if not user_types.intersection(passwordless_types):
|
||||
users_without.append({
|
||||
"user": user["userPrincipalName"],
|
||||
"name": user.get("displayName", ""),
|
||||
"methods": [m.get("type") for m in methods if not m.get("error")],
|
||||
})
|
||||
return users_without
|
||||
|
||||
|
||||
def get_sign_in_logs(token, days=7, passwordless_only=False):
|
||||
"""Get recent sign-in logs to analyze authentication methods used."""
|
||||
filter_str = ""
|
||||
if passwordless_only:
|
||||
filter_str = "?$filter=authenticationDetails/any(a:a/authenticationMethod eq 'FIDO2 security key')"
|
||||
try:
|
||||
logs = graph_get(token, f"/auditLogs/signIns{filter_str}", beta=True)
|
||||
return [{"user": log.get("userPrincipalName"),
|
||||
"app": log.get("appDisplayName"),
|
||||
"status": log.get("status", {}).get("errorCode", 0),
|
||||
"auth_detail": [d.get("authenticationMethod") for d in log.get("authenticationDetails", [])],
|
||||
"time": log.get("createdDateTime")}
|
||||
for log in logs.get("value", [])[:50]]
|
||||
except Exception as e:
|
||||
return [{"error": str(e)}]
|
||||
|
||||
|
||||
def get_conditional_access_policies(token):
|
||||
"""List conditional access policies related to authentication strength."""
|
||||
try:
|
||||
policies = graph_get(token, "/identity/conditionalAccess/policies", beta=True)
|
||||
auth_strength_policies = []
|
||||
for p in policies.get("value", []):
|
||||
grant = p.get("grantControls", {})
|
||||
if grant and "authenticationStrength" in json.dumps(grant):
|
||||
auth_strength_policies.append({
|
||||
"name": p.get("displayName"),
|
||||
"state": p.get("state"),
|
||||
"grant_controls": grant,
|
||||
})
|
||||
return auth_strength_policies
|
||||
except Exception as e:
|
||||
return [{"error": str(e)}]
|
||||
|
||||
|
||||
def run_passwordless_audit(token):
|
||||
"""Run comprehensive passwordless authentication audit."""
|
||||
print(f"\n{'='*60}")
|
||||
print(f" MICROSOFT ENTRA PASSWORDLESS AUTH AUDIT")
|
||||
print(f" Generated: {datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')} UTC")
|
||||
print(f"{'='*60}\n")
|
||||
|
||||
fido2 = get_fido2_policy(token)
|
||||
print(f"--- FIDO2 SECURITY KEYS ---")
|
||||
print(f" State: {fido2.get('state', 'unknown')}")
|
||||
print(f" Attestation Enforced: {fido2.get('is_attestation_enforced', 'N/A')}")
|
||||
print(f" Self-Service Registration: {fido2.get('is_self_service_allowed', 'N/A')}")
|
||||
|
||||
authenticator = get_microsoft_authenticator_policy(token)
|
||||
print(f"\n--- MICROSOFT AUTHENTICATOR ---")
|
||||
print(f" State: {authenticator.get('state', 'unknown')}")
|
||||
|
||||
hello = get_windows_hello_policy(token)
|
||||
print(f"\n--- WINDOWS HELLO FOR BUSINESS ---")
|
||||
print(f" State: {hello.get('state', 'unknown')}")
|
||||
|
||||
ca_policies = get_conditional_access_policies(token)
|
||||
print(f"\n--- CONDITIONAL ACCESS (Auth Strength) ({len(ca_policies)}) ---")
|
||||
for p in ca_policies:
|
||||
print(f" {p.get('name', 'N/A')}: {p.get('state', 'N/A')}")
|
||||
|
||||
users_without = get_users_without_passwordless(token, max_users=50)
|
||||
print(f"\n--- USERS WITHOUT PASSWORDLESS ({len(users_without)}) ---")
|
||||
for u in users_without[:10]:
|
||||
print(f" {u['user']} - Current methods: {', '.join(u['methods']) or 'none'}")
|
||||
|
||||
print(f"\n{'='*60}\n")
|
||||
return {"fido2": fido2, "authenticator": authenticator, "hello": hello,
|
||||
"users_without_passwordless": len(users_without)}
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Microsoft Entra Passwordless Auth Agent")
|
||||
parser.add_argument("--tenant-id", required=True, help="Azure AD tenant ID")
|
||||
parser.add_argument("--client-id", required=True, help="App registration client ID")
|
||||
parser.add_argument("--client-secret", required=True, help="App registration secret")
|
||||
parser.add_argument("--audit", action="store_true", help="Run passwordless audit")
|
||||
parser.add_argument("--user-methods", help="List auth methods for specific user")
|
||||
parser.add_argument("--output", help="Save report to JSON")
|
||||
args = parser.parse_args()
|
||||
|
||||
token = get_access_token(args.tenant_id, args.client_id, args.client_secret)
|
||||
|
||||
if args.audit:
|
||||
report = run_passwordless_audit(token)
|
||||
if args.output:
|
||||
with open(args.output, "w") as f:
|
||||
json.dump(report, f, indent=2, default=str)
|
||||
elif args.user_methods:
|
||||
methods = list_user_auth_methods(token, args.user_methods)
|
||||
print(json.dumps(methods, indent=2))
|
||||
else:
|
||||
parser.print_help()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user