mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-10 05:04:56 +03:00
fix: add missing process.py implementation for aws-detective skill
The process.py script was empty (0 bytes). Added a functional implementation that lists behavior graphs, retrieves investigations, queries indicators, and exports results — matching the pattern of other skills in the repository.
This commit is contained in:
committed by
Julio César Suástegui
parent
2f6701d2d8
commit
41b828e758
@@ -0,0 +1,200 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
AWS Detective Threat Hunting Script
|
||||
|
||||
Lists behavior graphs, retrieves investigations, and analyzes entity
|
||||
indicators for cloud-native threat hunting.
|
||||
"""
|
||||
|
||||
import boto3
|
||||
import json
|
||||
import sys
|
||||
import os
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
|
||||
def list_behavior_graphs(session):
|
||||
"""List all Detective behavior graphs in the account."""
|
||||
client = session.client('detective')
|
||||
response = client.list_graphs()
|
||||
graphs = response.get('GraphList', [])
|
||||
|
||||
if not graphs:
|
||||
print("[!] No behavior graphs found. Enable Detective first.")
|
||||
return []
|
||||
|
||||
print(f"[+] Found {len(graphs)} behavior graph(s)\n")
|
||||
for graph in graphs:
|
||||
print(f" ARN: {graph['Arn']}")
|
||||
created = graph.get('CreatedTime', 'N/A')
|
||||
print(f" Created: {created}")
|
||||
print()
|
||||
|
||||
return graphs
|
||||
|
||||
|
||||
def list_investigations(session, graph_arn, severities=None, max_results=20):
|
||||
"""List investigations filtered by severity."""
|
||||
client = session.client('detective')
|
||||
|
||||
filter_criteria = {}
|
||||
if severities:
|
||||
filter_criteria['Severities'] = severities
|
||||
|
||||
kwargs = {
|
||||
'GraphArn': graph_arn,
|
||||
'MaxResults': max_results,
|
||||
}
|
||||
if filter_criteria:
|
||||
kwargs['FilterCriteria'] = filter_criteria
|
||||
|
||||
response = client.list_investigations(**kwargs)
|
||||
investigations = response.get('InvestigationDetails', [])
|
||||
|
||||
if not investigations:
|
||||
print("[+] No investigations found matching criteria")
|
||||
return []
|
||||
|
||||
print(f"[+] Found {len(investigations)} investigation(s)\n")
|
||||
for inv in investigations:
|
||||
inv_id = inv.get('InvestigationId', 'N/A')
|
||||
severity = inv.get('Severity', 'N/A')
|
||||
status = inv.get('Status', 'N/A')
|
||||
entity = inv.get('EntityArn', 'N/A')
|
||||
created = inv.get('CreatedTime', 'N/A')
|
||||
print(f" Investigation: {inv_id}")
|
||||
print(f" Severity: {severity} | Status: {status}")
|
||||
print(f" Entity: {entity}")
|
||||
print(f" Created: {created}")
|
||||
print()
|
||||
|
||||
return investigations
|
||||
|
||||
|
||||
def get_investigation_detail(session, graph_arn, investigation_id):
|
||||
"""Get detailed information about a specific investigation."""
|
||||
client = session.client('detective')
|
||||
|
||||
response = client.get_investigation(
|
||||
GraphArn=graph_arn,
|
||||
InvestigationId=investigation_id,
|
||||
)
|
||||
|
||||
print(f"[+] Investigation: {investigation_id}")
|
||||
print(f" Entity: {response.get('EntityArn', 'N/A')}")
|
||||
print(f" Entity Type: {response.get('EntityType', 'N/A')}")
|
||||
print(f" Severity: {response.get('Severity', 'N/A')}")
|
||||
print(f" Status: {response.get('Status', 'N/A')}")
|
||||
print(f" Created: {response.get('CreatedTime', 'N/A')}")
|
||||
print(f" Scope Start: {response.get('ScopeStartTime', 'N/A')}")
|
||||
print(f" Scope End: {response.get('ScopeEndTime', 'N/A')}")
|
||||
|
||||
return response
|
||||
|
||||
|
||||
def list_indicators(session, graph_arn, investigation_id, max_results=50):
|
||||
"""List indicators for a specific investigation."""
|
||||
client = session.client('detective')
|
||||
|
||||
response = client.list_indicators(
|
||||
GraphArn=graph_arn,
|
||||
InvestigationId=investigation_id,
|
||||
MaxResults=max_results,
|
||||
)
|
||||
|
||||
indicators = response.get('Indicators', [])
|
||||
if not indicators:
|
||||
print("[+] No indicators found for this investigation")
|
||||
return []
|
||||
|
||||
print(f"[+] Found {len(indicators)} indicator(s)\n")
|
||||
for ind in indicators:
|
||||
ind_type = ind.get('IndicatorType', 'N/A')
|
||||
detail = ind.get('IndicatorDetail', {})
|
||||
print(f" Type: {ind_type}")
|
||||
if detail:
|
||||
print(f" Detail: {json.dumps(detail, default=str)[:200]}")
|
||||
print()
|
||||
|
||||
return indicators
|
||||
|
||||
|
||||
def export_results(data, output_dir):
|
||||
"""Export investigation results to JSON."""
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
out_path = os.path.join(output_dir, "detective_results.json")
|
||||
with open(out_path, "w") as f:
|
||||
json.dump(data, f, indent=2, default=str)
|
||||
print(f"[+] Results exported to {out_path}")
|
||||
return out_path
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description="AWS Detective Threat Hunting Tool"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--graphs", action="store_true", help="List behavior graphs"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--investigations", action="store_true", help="List investigations"
|
||||
)
|
||||
parser.add_argument("--graph-arn", type=str, help="Behavior graph ARN")
|
||||
parser.add_argument(
|
||||
"--investigation-id", type=str, help="Investigation ID for detail view"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--indicators", action="store_true", help="List indicators"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--severity",
|
||||
nargs="+",
|
||||
default=None,
|
||||
help="Severity filter (e.g. HIGH CRITICAL)",
|
||||
)
|
||||
parser.add_argument("--max-results", type=int, default=20)
|
||||
parser.add_argument("--region", default="us-east-1")
|
||||
parser.add_argument("--profile", type=str, help="AWS profile name")
|
||||
parser.add_argument(
|
||||
"--output", type=str, help="Output directory for JSON export"
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
kwargs = {"region_name": args.region}
|
||||
if args.profile:
|
||||
kwargs["profile_name"] = args.profile
|
||||
session = boto3.Session(**kwargs)
|
||||
|
||||
results = {}
|
||||
|
||||
if args.graphs:
|
||||
results["graphs"] = list_behavior_graphs(session)
|
||||
|
||||
if args.investigations:
|
||||
if not args.graph_arn:
|
||||
print("[!] --graph-arn required for --investigations")
|
||||
sys.exit(1)
|
||||
results["investigations"] = list_investigations(
|
||||
session, args.graph_arn, args.severity, args.max_results
|
||||
)
|
||||
|
||||
if args.investigation_id:
|
||||
if not args.graph_arn:
|
||||
print("[!] --graph-arn required for --investigation-id")
|
||||
sys.exit(1)
|
||||
results["detail"] = get_investigation_detail(
|
||||
session, args.graph_arn, args.investigation_id
|
||||
)
|
||||
|
||||
if args.indicators:
|
||||
if not args.graph_arn or not args.investigation_id:
|
||||
print("[!] --graph-arn and --investigation-id required for --indicators")
|
||||
sys.exit(1)
|
||||
results["indicators"] = list_indicators(
|
||||
session, args.graph_arn, args.investigation_id, args.max_results
|
||||
)
|
||||
|
||||
if args.output and results:
|
||||
export_results(results, args.output)
|
||||
|
||||
Reference in New Issue
Block a user