mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-13 14:44:58 +03:00
27c6414ca5
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
170 lines
6.7 KiB
Python
170 lines
6.7 KiB
Python
#!/usr/bin/env python3
|
|
"""Agent for managing Microsoft Sentinel SIEM operations."""
|
|
|
|
import os
|
|
import json
|
|
import argparse
|
|
from datetime import datetime, timedelta
|
|
|
|
from azure.identity import DefaultAzureCredential, ClientSecretCredential
|
|
from azure.monitor.query import LogsQueryClient, LogsQueryStatus
|
|
from azure.mgmt.securityinsight import SecurityInsights
|
|
|
|
|
|
def get_credential(tenant_id=None, client_id=None, client_secret=None):
|
|
"""Get Azure credential for authentication."""
|
|
if client_id and client_secret and tenant_id:
|
|
return ClientSecretCredential(tenant_id, client_id, client_secret)
|
|
return DefaultAzureCredential()
|
|
|
|
|
|
def run_kql_query(credential, workspace_id, query, timespan_hours=24):
|
|
"""Execute a KQL query against a Log Analytics workspace."""
|
|
client = LogsQueryClient(credential)
|
|
timespan = timedelta(hours=timespan_hours)
|
|
response = client.query_workspace(workspace_id, query, timespan=timespan)
|
|
if response.status == LogsQueryStatus.SUCCESS:
|
|
rows = []
|
|
for table in response.tables:
|
|
columns = [col.name for col in table.columns]
|
|
for row in table.rows:
|
|
rows.append(dict(zip(columns, row)))
|
|
return rows
|
|
return []
|
|
|
|
|
|
def detect_impossible_travel(credential, workspace_id):
|
|
"""Detect impossible travel sign-ins using KQL."""
|
|
query = """
|
|
SigninLogs
|
|
| where ResultType == 0
|
|
| project TimeGenerated, UserPrincipalName, IPAddress,
|
|
Latitude = toreal(LocationDetails.geoCoordinates.latitude),
|
|
Longitude = toreal(LocationDetails.geoCoordinates.longitude)
|
|
| sort by UserPrincipalName asc, TimeGenerated asc
|
|
| extend PrevLat = prev(Latitude), PrevLon = prev(Longitude),
|
|
PrevTime = prev(TimeGenerated), PrevUser = prev(UserPrincipalName)
|
|
| where UserPrincipalName == PrevUser
|
|
| extend TimeDiff = datetime_diff('minute', TimeGenerated, PrevTime)
|
|
| where TimeDiff < 60
|
|
| extend Distance = geo_distance_2points(Longitude, Latitude, PrevLon, PrevLat) / 1000
|
|
| where Distance > 500
|
|
| project TimeGenerated, UserPrincipalName, IPAddress, Distance, TimeDiff
|
|
"""
|
|
return run_kql_query(credential, workspace_id, query, 24)
|
|
|
|
|
|
def detect_aws_credential_abuse(credential, workspace_id):
|
|
"""Detect AWS credential abuse via CloudTrail in Sentinel."""
|
|
query = """
|
|
AWSCloudTrail
|
|
| where EventName in ("ConsoleLogin", "AssumeRole", "GetSessionToken")
|
|
| where ErrorCode == ""
|
|
| summarize LoginCount = count(), DistinctIPs = dcount(SourceIpAddress),
|
|
IPList = make_set(SourceIpAddress, 10)
|
|
by UserIdentityArn, bin(TimeGenerated, 1h)
|
|
| where DistinctIPs > 3
|
|
"""
|
|
return run_kql_query(credential, workspace_id, query, 24)
|
|
|
|
|
|
def detect_mass_deletion(credential, workspace_id):
|
|
"""Detect mass S3 object deletion (potential ransomware)."""
|
|
query = """
|
|
AWSCloudTrail
|
|
| where EventName in ("DeleteObject", "DeleteObjects")
|
|
| summarize DeleteCount = count(), Buckets = dcount(RequestParameters_bucketName)
|
|
by UserIdentityArn, bin(TimeGenerated, 10m)
|
|
| where DeleteCount > 100
|
|
"""
|
|
return run_kql_query(credential, workspace_id, query, 24)
|
|
|
|
|
|
def get_incident_summary(credential, workspace_id, days=7):
|
|
"""Get incident summary from Sentinel."""
|
|
query = f"""
|
|
SecurityIncident
|
|
| where TimeGenerated > ago({days}d)
|
|
| summarize count() by Severity
|
|
| order by Severity
|
|
"""
|
|
return run_kql_query(credential, workspace_id, query, days * 24)
|
|
|
|
|
|
def match_threat_intelligence(credential, workspace_id):
|
|
"""Match network traffic against threat intelligence indicators."""
|
|
query = """
|
|
let TI_IPs = ThreatIntelligenceIndicator
|
|
| where isnotempty(NetworkIP)
|
|
| distinct NetworkIP;
|
|
CommonSecurityLog
|
|
| where DestinationIP in (TI_IPs)
|
|
| project TimeGenerated, SourceIP, DestinationIP, DestinationPort, DeviceAction
|
|
| take 100
|
|
"""
|
|
return run_kql_query(credential, workspace_id, query, 24)
|
|
|
|
|
|
def list_analytics_rules(credential, subscription_id, resource_group, workspace_name):
|
|
"""List active Sentinel analytics rules."""
|
|
client = SecurityInsights(credential, subscription_id)
|
|
rules = client.alert_rules.list(resource_group, workspace_name)
|
|
result = []
|
|
for rule in rules:
|
|
result.append({
|
|
"name": rule.display_name if hasattr(rule, "display_name") else rule.name,
|
|
"severity": getattr(rule, "severity", "Unknown"),
|
|
"enabled": getattr(rule, "enabled", True),
|
|
})
|
|
return result
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Microsoft Sentinel SIEM Agent")
|
|
parser.add_argument("--workspace-id", default=os.getenv("SENTINEL_WORKSPACE_ID"))
|
|
parser.add_argument("--tenant-id", default=os.getenv("AZURE_TENANT_ID"))
|
|
parser.add_argument("--client-id", default=os.getenv("AZURE_CLIENT_ID"))
|
|
parser.add_argument("--client-secret", default=os.getenv("AZURE_CLIENT_SECRET"))
|
|
parser.add_argument("--output", default="sentinel_report.json")
|
|
parser.add_argument("--action", choices=[
|
|
"impossible_travel", "aws_abuse", "mass_deletion",
|
|
"incidents", "threat_intel", "full_hunt"
|
|
], default="full_hunt")
|
|
args = parser.parse_args()
|
|
|
|
credential = get_credential(args.tenant_id, args.client_id, args.client_secret)
|
|
report = {"scan_date": datetime.utcnow().isoformat(), "findings": {}}
|
|
|
|
if args.action in ("impossible_travel", "full_hunt"):
|
|
results = detect_impossible_travel(credential, args.workspace_id)
|
|
report["findings"]["impossible_travel"] = results
|
|
print(f"[+] Impossible travel detections: {len(results)}")
|
|
|
|
if args.action in ("aws_abuse", "full_hunt"):
|
|
results = detect_aws_credential_abuse(credential, args.workspace_id)
|
|
report["findings"]["aws_credential_abuse"] = results
|
|
print(f"[+] AWS credential abuse events: {len(results)}")
|
|
|
|
if args.action in ("mass_deletion", "full_hunt"):
|
|
results = detect_mass_deletion(credential, args.workspace_id)
|
|
report["findings"]["mass_deletion"] = results
|
|
print(f"[+] Mass deletion events: {len(results)}")
|
|
|
|
if args.action in ("incidents", "full_hunt"):
|
|
results = get_incident_summary(credential, args.workspace_id)
|
|
report["findings"]["incidents_7d"] = results
|
|
print(f"[+] Incident summary (7d): {results}")
|
|
|
|
if args.action in ("threat_intel", "full_hunt"):
|
|
results = match_threat_intelligence(credential, args.workspace_id)
|
|
report["findings"]["ti_matches"] = results
|
|
print(f"[+] Threat intel matches: {len(results)}")
|
|
|
|
with open(args.output, "w") as f:
|
|
json.dump(report, f, indent=2, default=str)
|
|
print(f"[+] Report saved to {args.output}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|