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:
MAGI
2026-03-18 10:38:13 -06:00
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)