Skip to content

What 3,500 brute-force attempts in 24 hours look like

One exposed VM, one day, more than 3,500 failed logons. Almost all of them came from a single address, which changes what the right defense is.

Date

This is the data from the Azure Sentinel honeypot. The project page covers how it was built. This is about what showed up in the 24 hours it ran before I shut it down.

The shape of a day

More than 3,500 failed RDP logons (Windows event 4625) in 24 hours. By country, as the Sentinel workbook’s bar chart rendered them:

Country Attempts
Indonesia 3,106
Egypt 303
Romania 55
Saudi Arabia 31
United States 13
South Korea 6
France 1
Russia 1

One address did almost all of it

A single IP in Indonesia accounted for 3,106 attempts, close to nine in ten of the day’s total. The next two addresses, both in Egypt, managed 164 and 139. Everything else was in the dozens or single digits.

SecurityEvent
| where EventID == 4625
| where isnotempty(IpAddress)
| extend Country = tostring(geo_info_from_ip_address(IpAddress).country)
| where isnotempty(Country)
| summarize Attacks = count() by IpAddress, Country
| sort by Attacks desc

Query results table listing attacker IP addresses, countries and attempt counts, led by 114.10.44.29 in Indonesia with 3,106.

A separate query watched for event 4624, a successful logon, over the network or RDP from a public address. It returned nothing.

What it means for defenders

  • Geo-blocking is the wrong lesson. Blocking Indonesia would have removed most of this day’s noise and told me nothing about tomorrow’s. The single-source pattern argues for per-address rate limiting and account lockout, which work regardless of where the next scanner sits.
  • The small sources are still worth reading. The addresses with a handful of attempts look like scanners checking whether the port answers, which is how a host gets found in the first place.
  • Exposure was the problem, not a weak password. No logon succeeded. The risk is that RDP was answerable from the internet at all. A bastion, a VPN, or just-in-time access removes the whole category.
  • The detection is cheap. One KQL query on a built-in table and one workbook, with geolocation from the built-in geo_info_from_ip_address() function rather than an external service.