Microsoft Sentinel and a Honeypot That Got Hit 50 Times in Under an Hour

Connecting Microsoft Sentinel to the slytech.us hybrid environment, building custom detection rules mapped to MITRE ATT&CK, deploying a deliberately exposed honeypot VM, and watching real global attack traffic roll in.

This project connects Microsoft Sentinel to the existing slytech.us environment, builds detection rules against real identity data, and deploys a honeypot VM with RDP intentionally exposed to see what shows up.

It builds on the hybrid identity, endpoint management, and governance work from the previous three posts.

Eight Connectors, Zero Configuration

The Log Analytics workspace was already running. Sentinel connected to it directly. No new infrastructure, no separate data pipeline. Eight Microsoft data connectors auto-discovered and connected on first login.

  • Microsoft Defender for Endpoint
  • Microsoft Entra ID
  • Microsoft Entra ID Protection
  • Microsoft Defender XDR
  • Microsoft Defender for Cloud Apps
  • Microsoft Defender for Identity
  • Microsoft Defender for Office 365
  • Microsoft 365 Insider Risk Management

Everything already running in the tenant started feeding into the SIEM automatically.

Sentinel connected to law-slytech-lab workspace in the Defender portal

Eight Microsoft data connectors auto-connected in Sentinel

The Detection Rules

Three custom analytics rules against identity data already flowing from Entra ID.

Brute Force Sign-in Attempt detects multiple failed logins from the same IP within an hour:

SigninLogs
| where TimeGenerated > ago(1h)
| where ResultType != "0"
| summarize FailedAttempts = count() by IPAddress, UserPrincipalName
| where FailedAttempts >= 5
| project IPAddress, UserPrincipalName, FailedAttempts

Disabled Account Sign-in Attempt catches authentication attempts against deprovisioned accounts. Result code 50057 is specifically “user account is disabled” in Entra ID:

SigninLogs
| where TimeGenerated > ago(1h)
| where ResultType == "50057"
| project TimeGenerated, UserPrincipalName, IPAddress, Location, ResultDescription

Privileged Account Created flags any account added to an admin or global role:

AuditLogs
| where TimeGenerated > ago(1h)
| where OperationName == "Add member to role"
| where Result == "success"
| extend TargetUser = tostring(TargetResources[0].userPrincipalName)
| extend Role = tostring(TargetResources[0].displayName)
| where Role contains "Admin" or Role contains "Global"
| project TimeGenerated, TargetUser, Role, InitiatedBy = tostring(InitiatedBy.user.userPrincipalName)

All three ran every 5 minutes, evaluated the last hour of data, and alerted on any result.

Brute force rule configuration showing query, scheduling, and severity settings

All three analytics rules enabled in Sentinel

MITRE ATT&CK Mapping

RuleTacticTechnique
Brute Force Sign-in AttemptCredential AccessT1110 — Brute Force
Disabled Account Sign-in AttemptDefense Evasion / Initial AccessT1078 — Valid Accounts
Privileged Account CreatedPrivilege EscalationT1098 — Account Manipulation

T1110 is what automated scanners do the moment they find an exposed service. T1078 covers what happens after an account gets compromised and then deprovisioned. T1098 is the endgame: persistence through privilege escalation.

Alerts Were Firing but Incidents Weren’t

The rules were enabled, data was flowing, and the queries returned results in Advanced Hunting. Nothing appeared in the incidents queue.

Two things were working against each other. The original brute force query used bin(TimeGenerated, 5m) to group events into time buckets. Failed logins from the same IP got split across multiple bins and none crossed the threshold individually. Removing the time bin fixed it.

The second issue was incident correlation being disabled. Alerts were sitting in the SecurityAlert table without rolling up into the incidents queue. Enabling correlation and alert grouping on all three rules fixed that.

The way to check whether rules are generating alerts before blaming the rule logic:

SecurityAlert
| where TimeGenerated > ago(24h)
| project TimeGenerated, AlertName, AlertSeverity, Description
| order by TimeGenerated desc

Alerts were there. The incidents queue was the problem, not the detection.

Advanced Hunting showing failed login attempts from two accounts

Brute force incident created in Sentinel with 3 grouped alerts

Incident detail showing attack timeline and severity

The Honeypot

A Windows Server 2019 VM provisioned via Terraform into a dedicated subnet with all inbound traffic allowed. Named CORPDC02 internally to look like a backup domain controller. Public IP exposed to the internet with RDP on port 3389 wide open.

resource "azurerm_network_security_group" "honeypot" {
  name                = "nsg-honeypot"
  location            = azurerm_resource_group.slytech.location
  resource_group_name = azurerm_resource_group.slytech.name
  security_rule {
    name                       = "allow-all-inbound"
    priority                   = 100
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "*"
    source_port_range          = "*"
    destination_port_range     = "*"
    source_address_prefix      = "*"
    destination_address_prefix = "*"
  }
}

The VM went on its own subnet because the main lab subnet NSG has RDP deny rules. Traffic hits the subnet NSG before the NIC-level NSG, so the honeypot’s allow-all rule was getting overridden. A dedicated subnet with no restrictive rules fixed it.

Terraform plan showing honeypot resources to be created

Terraform plan continued showing VM configuration details

Terraform apply complete showing all resources created successfully

Public IP address assigned to the honeypot VM

RDP session connected to CORPDC02

Getting logs from the honeypot into Sentinel required switching from the deprecated MMA agent to the Azure Monitor Agent and creating a Data Collection Rule targeting Security Events. The AMA agent also needed a managed identity assigned to the VM before it would connect.

az vm identity assign -g rg-slytech-lab -n vm-honeypot
az vm extension set `
    --resource-group rg-slytech-lab `
    --vm-name vm-honeypot `
    --name AzureMonitorWindowsAgent `
    --publisher Microsoft.Azure.Monitor `
    --version 1.22 `
    --enable-auto-upgrade true

The First Few Hours

Within the first few hours of the VM being live, 53 attacks were already visible on the map. The geographic enrichment query joins attack IPs against a 54,000-record GeoIP watchlist imported into Sentinel:

let GeoIPDB_FULL = _GetWatchlist("geoip");
SecurityEvent
| where EventID == 4625
| where TimeGenerated > ago(24h)
| where Computer contains "CORPDC02"
| evaluate ipv4_lookup(GeoIPDB_FULL, IpAddress, network)
| summarize AttackCount = count() by IpAddress, cityname, countryname, latitude, longitude
| where AttackCount > 0 and isnotempty(latitude) and isnotempty(longitude)

The automated tools hitting the machine cycled through the same username list: Admin, Administrator, user, corpdc02, Windows, Accounting, test. They didn’t know what was on the machine. Every RDP-exposed IP on the internet gets the same treatment.

Attack map showing 53 attacks from multiple countries in the first few hours

One thing worth noting on the map setup: the Defender portal workbook editor wouldn’t accept latitude/longitude column mappings through its UI. Opening the same workbook in the Azure portal editor, configuring the map settings there, and the changes synced back to the Defender portal.

Overnight

Left the honeypot running overnight. The numbers tell the rest of the story.

Attack map showing global attack distribution after overnight run

Country breakdown showing top attacking nations by volume

Hourly attack trend showing volume over 24 hours

In just under 24 hours, the honeypot logged 1,763 failed login attempts from 34 countries. No vulnerability exploited, no phishing link clicked. Just an exposed port and a recognizable machine name.

1,763 failed login attempts from 34 countries logged in under 24 hours

Lessons Learned

Building detections in a lab against manufactured data is useful. Watching attack traffic roll in from 34 different countries against a machine that was live for less than 24 hours is different. The rule firing, the incident appearing, the source IPs mapping to a world map, that is when the detection pipeline stops being abstract.

The honeypot data also confirmed something worth reinforcing in any environment: Administrator, admin, user, and the machine’s own hostname are the first usernames every automated scanner tries. If any of those exist as active accounts in a real environment, they are getting hit constantly. Rename them, disable them, or put them behind MFA at minimum. The logs make this impossible to ignore when you are watching it happen in real time.