.github/skills/honeypot-investigation/SKILL.md
Use this skill when asked to analyze, investigate, or report on honeypot server security. Triggers on keywords like "honeypot investigation", "analyze honeypot", "honeypot security", "honeypot report", or when a server name is mentioned with honeypot analysis context. This skill provides comprehensive security analysis including attack patterns, threat intelligence correlation, IP enrichment, vulnerability assessment, and executive report generation.
npx skillsauth add scstelz/security-investigator honeypot-investigationInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
This agent performs comprehensive security analysis on honeypot servers to assess attack patterns, threat intelligence, vulnerabilities, and defensive effectiveness. Honeypots are decoy systems designed to attract attackers and provide early warning of emerging threats.
Before starting ANY honeypot investigation:
create_file for reports (NEVER use PowerShell terminal commands)Date Range Rules (from main copilot-instructions):
datetime(2025-12-10) to datetime(2025-12-14)| Parameter | Description | Example |
|-----------|-------------|---------|
| Honeypot Name | Server/device name | honeypot-server |
| Time Range | Investigation period | last 48 hours, last 7 days |
reports/honeypot/Honeypot_Report_<hostname>_<timestamp>.mdtemp/honeypot_ips_<timestamp>.json, temp/honeypot_data_<timestamp>.jsonYOU MUST TRACK AND REPORT TIME AFTER EVERY MAJOR STEP:
[MM:SS] ✓ Step description (XX seconds)
Required Reporting Points:
Execute ALL THREE queries in parallel using mcp_sentinel-data_query_lake:
let start = datetime(<StartDate>);
let end = datetime(<EndDate>);
let honeypot = '<HONEYPOT_NAME>';
SecurityEvent
| where TimeGenerated between (start .. end)
| where Computer contains honeypot // Use 'contains' for flexible hostname matching
| where EventID in (4625, 4771, 4776) // Failed logon attempts
| where isnotempty(IpAddress) and IpAddress != "-" // IpAddress is built-in field
| where IpAddress != "127.0.0.1" // Exclude localhost (internal honeypot traffic)
| summarize
FailedAttempts=count(),
FirstSeen=min(TimeGenerated),
LastSeen=max(TimeGenerated),
TargetAccounts=make_set(Account, 10)
by IpAddress, EventID
| extend EventType = case(
EventID == 4625, "Failed Logon",
EventID == 4771, "Kerberos Pre-Auth Failed",
EventID == 4776, "NTLM Auth Failed",
"Unknown")
| order by FailedAttempts desc
| take 50
let start = datetime(<StartDate>);
let end = datetime(<EndDate>);
let honeypot = '<HONEYPOT_NAME>';
W3CIISLog
| where TimeGenerated between (start .. end)
| where Computer =~ honeypot
| where tolong(scStatus) >= 400 // HTTP errors (4xx/5xx) - scStatus is string type
| where cIP != "127.0.0.1" and cIP != "::1" // Exclude localhost (internal honeypot traffic)
| summarize
RequestCount=count(),
FirstSeen=min(TimeGenerated),
LastSeen=max(TimeGenerated),
TargetedURIs=make_set(csUriStem, 10),
StatusCodes=make_set(tolong(scStatus), 5) // Convert to long for proper aggregation
by IpAddress = cIP
| order by RequestCount desc
| take 50
let start = datetime(<StartDate>);
let end = datetime(<EndDate>);
let honeypot = '<HONEYPOT_NAME>';
DeviceNetworkEvents
| where TimeGenerated between (start .. end)
| where DeviceName =~ honeypot
| where ActionType in ("ConnectionSuccess", "InboundConnectionAccepted", "ConnectionFound") // Successful inbound TCP connections
| where LocalPort in (3389, 80, 443, 445, 22, 21, 23, 8080, 8443) // Filter by attacked services (LocalPort = honeypot's listening port)
| where RemoteIP != "127.0.0.1" and RemoteIP != "::1" and RemoteIP != "::ffff:127.0.0.1" // Exclude localhost
| where RemoteIP !startswith "192.168." and RemoteIP !startswith "10." and RemoteIP !startswith "172.16." // Exclude RFC1918 private IPs
| where RemoteIP !startswith "fe80:" and RemoteIP !startswith "fc00:" and RemoteIP !startswith "fd00:" // Exclude IPv6 link-local and ULA
| where RemoteIP !startswith "::ffff:" // Filter out IPv6-mapped IPv4 addresses (reduces duplicate noise)
| summarize
ConnectionCount=count(),
FirstSeen=min(TimeGenerated),
LastSeen=max(TimeGenerated),
TargetedPorts=make_set(LocalPort, 10), // LocalPort = attacked services on honeypot
Actions=make_set(ActionType, 5)
by RemoteIP // RemoteIP = attacker source
| order by ConnectionCount desc
| take 50
IMPORTANT: This query shows TCP connection establishment (network layer), NOT successful authentication. Attackers who appear here may still fail at the authentication layer (SecurityEvent 4625). For honeypots, all inbound connections should be treated as reconnaissance/attack attempts.
After Phase 1 completes:
temp/honeypot_ips_<timestamp>.json in format: {"ips": ["1.2.3.4", "5.6.7.8", ...]}[MM:SS] ✓ Failed connection queries completed (XX seconds) - [total_count] unique IPs identified, top [enrichment_count] prioritized for enrichmentExecute IP enrichment script AND Sentinel threat intel query in parallel:
# Read prioritized IPs from JSON file (top 10-15 by attack volume)
# This reduces token consumption by ~80% while maintaining critical intelligence
$env:PYTHONPATH = "<WORKSPACE_ROOT>"
cd "<WORKSPACE_ROOT>"
.\.venv\Scripts\python.exe enrich_ips.py --file temp/honeypot_ips_<timestamp>.json
Enrichment provides (for prioritized IPs only):
is_vpn, is_proxy, is_tor)abuse_confidence_score, total_reports)eol-os, self-signed, c2), CPEs, hostnamesNote: Enrichment script provides aggregated statistics for all IPs - use these summary stats in report narrative instead of listing every IP
let target_ips = dynamic(["<IP1>", "<IP2>", "<IP3>", ...]); // From Phase 1 prioritized list (top 10-15 IPs)
ThreatIntelIndicators
| extend IndicatorType = replace_string(replace_string(replace_string(tostring(split(ObservableKey, ":", 0)), "[", ""), "]", ""), "\"", "")
| where IndicatorType in ("ipv4-addr", "ipv6-addr", "network-traffic")
| extend NetworkSourceIP = toupper(ObservableValue)
| where NetworkSourceIP in (target_ips)
| where IsActive and (ValidUntil > now() or isempty(ValidUntil))
| extend Description = tostring(parse_json(Data).description)
| where Description !contains_cs "State: inactive;" and Description !contains_cs "State: falsepos;"
| extend TrafficLightProtocolLevel = tostring(parse_json(AdditionalFields).TLPLevel)
| extend ActivityGroupNames = extract(@"ActivityGroup:(\S+)", 1, tostring(parse_json(Data).labels))
| summarize arg_max(TimeGenerated, *) by NetworkSourceIP
| project
TimeGenerated,
IPAddress = NetworkSourceIP,
ThreatDescription = Description,
ActivityGroupNames,
Confidence,
ValidUntil,
TrafficLightProtocolLevel,
IsActive
| order by Confidence desc, TimeGenerated desc
After Phase 2 completes:
temp/honeypot_data_<timestamp>.json[MM:SS] ✓ IP enrichment completed (XX seconds)Step 3A: Get Device ID from Sentinel
let honeypot = '<HONEYPOT_NAME>';
DeviceInfo
| where TimeGenerated > ago(30d)
| where DeviceName =~ honeypot or DeviceName contains honeypot
| summarize arg_max(TimeGenerated, *)
| project DeviceId, DeviceName, OSPlatform, OSVersion, PublicIP
Extract DeviceId (GUID) from result - returns single most recent device record.
Step 3B: Query Security Incidents
let targetDevice = "<HONEYPOT_NAME>";
let targetDeviceId = "<DEVICE_ID>"; // REQUIRED: Get from DeviceInfo query (Step 3A)
let start = datetime(<StartDate>);
let end = datetime(<EndDate>);
let relevantAlerts = SecurityAlert
| where TimeGenerated between (start .. end)
| where Entities has targetDevice or Entities has targetDeviceId
| summarize arg_max(TimeGenerated, *) by SystemAlertId
| project SystemAlertId, AlertName, AlertSeverity, ProviderName, Tactics;
SecurityIncident
| where CreatedTime between (start .. end) // Filter on CreatedTime for incidents created in range
| summarize arg_max(TimeGenerated, *) by ProviderIncidentId // Get most recent state per ProviderIncidentId
| project ProviderIncidentId, Title, Severity, Status, Classification, CreatedTime, LastModifiedTime, Owner, AdditionalData, AlertIds, Labels
| where not(tostring(Labels) has "Redirected") // Exclude merged incidents
| mv-expand AlertId = AlertIds
| extend AlertId = tostring(AlertId)
| join kind=inner relevantAlerts on $left.AlertId == $right.SystemAlertId
| extend ProviderIncidentUrl = tostring(AdditionalData.providerIncidentUrl)
| extend OwnerUPN = tostring(Owner.userPrincipalName)
| extend LastModifiedTime = todatetime(LastModifiedTime)
| summarize
Title = any(Title),
Severity = any(Severity),
Status = any(Status),
Classification = any(Classification),
CreatedTime = any(CreatedTime),
LastModifiedTime = any(LastModifiedTime),
OwnerUPN = any(OwnerUPN),
ProviderIncidentUrl = any(ProviderIncidentUrl),
AlertCount = count(),
MitreTactics = make_set(Tactics)
by ProviderIncidentId
| order by LastModifiedTime desc
| take 10
IMPORTANT:
This query joins SecurityIncident with SecurityAlert to provide full incident context
Deduplication: The final summarize statement collapses multiple alerts per incident into a single row (groups by ProviderIncidentId)
Filter on CreatedTime to find incidents created in the investigation period
Use arg_max(TimeGenerated, *) by IncidentNumber to get the most recent update for each incident (includes status changes, comments, etc.)
Returns up to 10 unique incidents (grouped by ProviderIncidentId to ensure one row per external incident ID)
⚠️ CHECK STATUS FIELD: Only report incidents with Status="New" or "Active" as threats. Status="Closed" + Classification="BenignPositive" = expected honeypot activity (do not flag as threat)
After Phase 3 completes:
[MM:SS] ✓ Security incidents query completed (XX seconds)⚠️ CRITICAL: TVM tables are snapshot tables — NO time filtering!
DeviceTvmSoftwareVulnerabilities has NO Timestamp or TimeGenerated columnwhere Timestamp between (...) — it will fail with a schema errorquery_lake) — TVM tables are only available via Advanced HuntingRunAdvancedHuntingQuery MCP tool onlylet deviceName = '<HONEYPOT_NAME>';
DeviceTvmSoftwareVulnerabilities
| where DeviceName startswith deviceName
| project
CveId,
VulnerabilitySeverityLevel,
SoftwareVendor,
SoftwareName,
SoftwareVersion,
RecommendedSecurityUpdate,
RecommendedSecurityUpdateId
| summarize by CveId, VulnerabilitySeverityLevel, SoftwareVendor, SoftwareName, SoftwareVersion, RecommendedSecurityUpdate, RecommendedSecurityUpdateId
| order by case(VulnerabilitySeverityLevel == "Critical", 1, VulnerabilitySeverityLevel == "High", 2, VulnerabilitySeverityLevel == "Medium", 3, 4) asc
| take 30
Key columns returned:
CveId — CVE identifier (e.g., CVE-2025-15467)VulnerabilitySeverityLevel — String: Critical / High / Medium / LowSoftwareVendor, SoftwareName, SoftwareVersion — Affected software detailsRecommendedSecurityUpdate — Patch info (may be empty)🔴 PROHIBITED:
Timestamp or TimeGenerated filters (column does not exist)CvssScore (column does not exist — use VulnerabilitySeverityLevel instead)query_lake) for TVM tablesGetDefenderMachineVulnerabilities API (requires separate machine ID lookup, less reliable)After Phase 4 completes:
[MM:SS] ✓ Vulnerability scan completed (XX seconds)Use the Report Template (see section below) to create markdown report.
Critical Report Sections:
Report Generation:
create_file to save: reports/honeypot/Honeypot_Report_<hostname>_<timestamp>.mdAfter Phase 5 completes:
[MM:SS] ✓ Report generated (XX seconds)let start = datetime(<StartDate>);
let end = datetime(<EndDate>);
let honeypot = '<HONEYPOT_NAME>';
SecurityEvent
| where TimeGenerated between (start .. end)
| where Computer =~ honeypot
| where EventID == 4625 // Failed logon
| summarize FailedAttempts = count() by Account
| order by FailedAttempts desc
| take 20
let start = datetime(<StartDate>);
let end = datetime(<EndDate>);
let honeypot = '<HONEYPOT_NAME>';
W3CIISLog
| where TimeGenerated between (start .. end)
| where Computer =~ honeypot
| where csUriStem has_any ("'", "union", "select", "script", "../", "..\\", "cmd.exe", "powershell")
| summarize
AttemptCount = count(),
FirstSeen = min(TimeGenerated),
LastSeen = max(TimeGenerated),
UniqueIPs = dcount(cIP)
by ExploitPattern = case(
csUriStem has_any ("'", "union", "select"), "SQL Injection",
csUriStem has "script", "XSS",
csUriStem has_any ("../", "..\\"), "Path Traversal",
csUriStem has_any ("cmd.exe", "powershell"), "Command Injection",
"Other")
| order by AttemptCount desc
let start = datetime(<StartDate>);
let end = datetime(<EndDate>);
let honeypot = '<HONEYPOT_NAME>';
DeviceNetworkEvents
| where TimeGenerated between (start .. end)
| where DeviceName =~ honeypot
| summarize
DistinctPorts = dcount(RemotePort),
PortsScanned = make_set(RemotePort),
EventCount = count()
by RemoteIP
| where DistinctPorts >= 5 // Threshold: 5+ ports = scan
| order by DistinctPorts desc
| take 20
let start = datetime(<StartDate>);
let end = datetime(<EndDate>);
let honeypot = '<HONEYPOT_NAME>';
let threshold = 50; // 50+ failed attempts = brute force
SecurityEvent
| where TimeGenerated between (start .. end)
| where Computer =~ honeypot
| where EventID == 4625
| extend IpAddress = extract(@"Source Network Address:\s+([^\s]+)", 1, tostring(EventData))
| summarize FailedAttempts = count() by IpAddress
| where FailedAttempts >= threshold
| order by FailedAttempts desc
Use this structure for executive reports:
# Honeypot Security Analysis - <HONEYPOT_NAME>
**Analysis Period:** <START_DATE> to <END_DATE> (<HOURS> hours)
**Report Generated:** <TIMESTAMP>
**Classification:** CONFIDENTIAL
---
## Executive Summary
[3 comprehensive paragraphs covering attack overview, threat landscape, and value delivered]
**Key Metrics:**
- **Total Attack Attempts:** [count]
- **Unique Attacking IPs:** [count]
- **Security Incidents Triggered:** [count]
- **Known Malicious IPs (Threat Intel):** [count] ([percentage]%)
- **Current Vulnerabilities:** [count] HIGH, [count] MEDIUM
---
## 1. Attack Surface Analysis
[Failed connections by source IP, geographic distribution, VPN/anonymization summary]
## 2. Threat Intelligence Correlation
[IPs matched in threat intel, highest confidence threats, MSTIC indicators]
## 3. Security Incidents
[Incidents involving honeypot with severity, status, classification, MITRE tactics]
## 4. Attack Pattern Analysis
[Targeted services, credential attacks, web exploitation, port scanning]
## 5. Honeypot Vulnerability Status
[CVE inventory, exploitation risk assessment, cross-reference with attacks]
## 6. Key Detection Insights
[MITRE ATT&CK mapping, novel indicators, threat actor attribution]
## 7. Honeypot Effectiveness
[Detection metrics, recommendations for optimization]
## 8. Conclusion
[Summary, key takeaways, immediate/short-term/long-term actions]
---
**Investigation Timeline:**
[Phase timing breakdown]
**Total Investigation Time:** [duration]
| Issue | Solution |
|-------|----------|
| Missing honeypot in DeviceInfo table | Verify device name; check if device reports to Defender; try Computer field instead |
| No SecurityEvent logs | Device may not be sending Windows Security logs; verify log forwarding configuration |
| W3CIISLog table not found | IIS logging may not be enabled; query WebAccessLog or HTTP logs instead |
| IP enrichment script fails | Check ipinfo.io token in config.json; verify internet connectivity; check temp file exists |
| Date range returns no results | Verify date calculation (current date from context + proper offset); expand time range |
| KQL timeout | Reduce take limit; narrow time range; remove complex aggregations |
Before delivering report, verify:
reports/honeypot/Honeypot_Report_<hostname>_<timestamp>.mdThis skill follows all patterns from the main copilot-instructions.md:
create_file for all outputenrich_ips.py utilityExample invocations:
After completing the investigation, offer to visualize the attack data using the dedicated visualization skills:
Use the heatmap-visualization skill (.github/skills/heatmap-visualization/SKILL.md) to show attack patterns over time with threat intel drill-down.
When to offer:
Use the geomap-visualization skill (.github/skills/geomap-visualization/SKILL.md) to show attack origins on a world map.
When to offer:
Note: W3CIISLog includes native RemoteIPLatitude and RemoteIPLongitude fields - use these directly for geomap visualization without additional enrichment.
Last Updated: January 29, 2026
development
Use this skill when asked to investigate a computer, device, endpoint, or machine for security issues, suspicious activity, malware, or compliance review. Triggers on keywords like "investigate computer", "investigate device", "investigate endpoint", "check machine", "device security", "endpoint investigation", or when a device name/hostname is mentioned with investigation context. This skill provides comprehensive device security analysis including Defender alerts, sign-in patterns, logged-on users, vulnerabilities, software inventory, compliance status, network activity, and automated investigation tracking for Entra Joined, Hybrid Joined, and Entra Registered devices.
development
Recommended starting point for new users and daily SOC operations. Quick 15-minute security posture scan across 7 domains: active incidents, identity (human + NonHuman), endpoint, email threats, admin & cloud ops, and exposure. 12 queries executed in parallel batches, producing a prioritized Threat Pulse Dashboard with color-coded verdicts (🔴 Escalate / 🟠 Investigate / 🟡 Monitor / ✅ Clear) and drill-down recommendations pointing to specialized skills. Trigger on getting-started questions like "what can you do", "where do I start", "help me investigate". Supports inline chat and markdown file output
development
Use this skill when asked to investigate a user account for security issues, suspicious activity, or compliance review. Triggers on keywords like "investigate user", "security investigation", "user investigation", "check user activity", "analyze sign-ins", or when a UPN/email is mentioned with investigation context. This skill provides comprehensive Entra ID user security analysis including sign-in anomalies, MFA status, device compliance, audit logs, security incidents, Identity Protection risk, and automated reports (HTML, markdown file, or inline chat).
development
Use this skill when asked to generate SVG data visualization dashboards from investigation data or skill reports. Triggers on keywords like "generate SVG dashboard", "create a visual dashboard", "visualize this report", "SVG from the report", "visualize results", "create SVG chart", "SVG from this data". Supports two modes: manifest-driven structured dashboards (from skill reports with svg-widgets.yaml) and freeform adaptive visualizations from ad-hoc investigation data. Component library includes KPI cards, score cards, bar charts, line charts, donut charts, waterfall charts, tables, recommendation cards, assessment banners. SharePoint Dark Theme default palette.