8 hours ago8 hr This started as a routine look at a client's remote access portal logs. We found around 50,000 password-spray sessions a day coming from just five networks, with zero successful logins. Nobody had noticed, because spraying is quiet by design. Instead of hammering one account with thousands of passwords, the attacker tries a few common passwords against thousands of usernames, which stays under per-account lockout thresholds. Anything with a public login page gets this as constant background noise. Here's how we spotted it, measured it and shut it off at the edge.Access you'll wantThe portal or VPN authentication logs, whether that's local logs, a syslog server or a SIEMA Linux shell with the usual tools (grep, awk, sort, uniq)Admin access to the edge firewall or load balancer in front of the portalWhat it looks like in the logsOnce you've seen it, the pattern is easy to recognize:Thousands to tens of thousands of authentication sessions per day, far more than your user count could explainLots of usernames, often ones that don't exist in your directory, like admin, test, scanner, or first.last guesses from a scraped staff listA handful of source /24 networks, often hosting providers, rotating through addresses within each blockNo successes at all. If any attempts succeed, stop reading and start incident response.Counting failures by networkEvery product logs differently, so you'll need to adapt the field extraction. Here's a generic log line:2026-10-01T03:12:44Z portal auth=fail user=jsmith src=203.0.113.45 reason=bad_passwordCount failed attempts per source /24:grep 'auth=fail' portal.log \ | grep -oE 'src=[0-9.]+' | cut -d= -f2 \ | awk -F. '{print $1"."$2"."$3".0/24"}' \ | sort | uniq -c | sort -rn | head -20Then check how many distinct usernames each network tried. A real user behind a NAT fails with one or two names. A sprayer tries hundreds.grep 'auth=fail' portal.log \ | awk '{for(i=1;i<=NF;i++){if($i~/^user=/)u=substr($i,6); if($i~/^src=/)s=substr($i,5)} split(s,o,"."); print o[1]"."o[2]"."o[3]".0/24", u}' \ | sort -u | awk '{print $1}' | uniq -c | sort -rn | head -20And confirm there were no successes from those networks:grep 'auth=success' portal.log | grep -E 'src=(203\.0\.113|198\.51\.100)\.' | wc -lFor this client, five networks accounted for essentially all of the failures, each had tried hundreds of usernames, and the success count was zero.Block it before it reaches login and MFAWhere you block matters. If the portal forwards each attempt to your MFA provider or directory, the spray costs you more than log space. It loads your domain controllers, can lock out real staff whose usernames happen to match, and can spam people with push prompts if a password ever does match. Drop the traffic before it gets to the login logic.Most platforms have a named list you can block against. It might be an address list or address group on a firewall, a data group referenced by a load balancer rule, or an external dynamic list. Keep the list in one place so adding a network is a one-line change. On a Linux edge, ipset does the same job:ipset create spray-block hash:net ipset add spray-block 203.0.113.0/24 ipset add spray-block 198.51.100.0/24 iptables -I INPUT -p tcp --dport 443 -m set --match-set spray-block src -j DROPMake the rule persistent using your distribution's mechanism, and put a comment or ticket reference on each entry. Whoever looks at that list next will want to know why it's there.Geo-blocking, if your users are all in one countryBlocking five networks handles today's sprayer, and the next one will come from somewhere else. If every legitimate user is in one country, allowing only that country to reach the portal removes most of the noise with one rule. Most commercial firewalls have built-in geo objects. Keep an exception process for staff who travel. Geo-IP data is approximate and VPN providers can appear to be anywhere, so I treat this as noise reduction, not a security control on its own.MFA and lockout still do the real workEdge blocking cuts load and noise, but it doesn't protect accounts. Attackers rotate sources, and spraying is slow on purpose. What actually protects your users:MFA on every remote access path, preferably phishing-resistant or number-matching, so a guessed password alone isn't enoughA lockout or smart-lockout policy that slows guessing without making it trivial to lock out the whole staffBanned-password lists so seasonal passwords like Fall2026! get rejectedAlerts on any successful login from an unusual country or network, and on MFA prompts users report they didn't triggerNext-day checksRe-run the per-network count on the next day's log. The blocked networks should be gone.The firewall rule's hit counter should be climbing.Real users can still log in, including from home ISPs and mobile carriers.The MFA provider logs no longer show a stream of authentication requests for unknown users.Be careful with theseBefore blocking a network, check that it isn't a mobile carrier or a large ISP your users share. Hosting provider ranges are usually safe to block. Residential ranges are not.If a load balancer sits in front of the portal, make sure the real client IP is being logged. Otherwise every attempt looks like it came from one internal address.A block rule placed below a broad allow rule never matches. Check the hit counts after you add it.The list is easy to forget about. Review the blocked networks every few months and remove stale entries.We re-run the per-network count on that portal every so often. New sprayers keep turning up from new places, and adding another /24 to the list takes about a minute.
Create an account or sign in to comment