VPN and Remote Access Credential Stuffing / Brute Force
Credential stuffing and brute force against VPN and remote access gateways is a persistent initial access vector for ransomware operators and nation-state actors. NCSC and CISA have repeatedly warned about Fortinet, Cisco ASA/FTD, Ivanti Connect Secure, Palo Alto GlobalProtect, and SonicWall VPN gateways being targeted. Attackers use credential databases from prior breaches and automated tools to test credentials at scale against VPN login portals. Unlike password spraying against M365, VPN credential stuffing often targets a single account at high frequency (bypassing account lockout through IP rotation) or uses a large pool of breached credential pairs. Volt Typhoon (China-nexus) specifically targets small business routers and VPN gateways for SOHO Living-off-the-Land access. Compromised VPN access gives attackers direct network access, bypassing perimeter defences entirely.
What is THREAT-VPN-CredentialStuffing VPN and Remote Access Credential Stuffing / Brute Force?
VPN and Remote Access Credential Stuffing / Brute Force (THREAT-VPN-CredentialStuffing) maps to the Credential Access and Initial Access tactics — the adversary is trying to steal account names and passwords in MITRE ATT&CK.
This page provides production-ready detection logic for VPN and Remote Access Credential Stuffing / Brute Force, covering the data sources and telemetry it touches: CommonSecurityLog (CEF from VPN appliances), Syslog (VPN appliance native logging), Azure Sentinel built-in connectors for Fortinet, Palo Alto, Cisco. The queries below are rated high severity at high confidence, and ship for 7 SIEM platforms — KQL, SPL, Elastic, QRadar, Sumo, YARA-L, LogScale.
MITRE ATT&CK
- Tactic
- Credential Access Initial Access
// THREAT: VPN / Remote Access Credential Stuffing
// Detects brute force and credential stuffing against VPN authentication
// Sources: CommonSecurityLog (CEF from firewall/VPN appliances), Syslog
// Alert 1: High-volume authentication failures against VPN
CommonSecurityLog
| where TimeGenerated > ago(24h)
| where DeviceVendor has_any ("Fortinet", "Cisco", "Palo Alto", "SonicWall", "Pulse Secure", "Ivanti", "Juniper")
| where Activity has_any ("vpn", "ipsec", "ssl-vpn", "remote-access", "authentication")
| where Message has_any ("failed", "failure", "invalid", "rejected", "denied")
or LogSeverity >= 5
| summarize
FailureCount=count(),
UniqueUsers=dcount(DestinationUserName),
TargetUsers=make_set(DestinationUserName),
UniqueSourceIPs=dcount(SourceIP),
SourceIPs=make_set(SourceIP)
by DeviceAddress, DeviceVendor, bin(TimeGenerated, 15m)
| where FailureCount >= 20 or UniqueUsers >= 5
| extend ThreatType = "VPN_CredentialStuffing"
| extend Severity = iff(FailureCount >= 100, "Critical", iff(FailureCount >= 50, "High", "Medium"))
| sort by FailureCount desc;
// Alert 2: Successful VPN connection from previously-failing IP
let VPNFailingIPs = CommonSecurityLog
| where TimeGenerated > ago(24h)
| where Activity has_any ("vpn", "ssl-vpn", "remote-access")
| where Message has_any ("failed", "failure", "invalid", "rejected")
| summarize Failures=count() by SourceIP
| where Failures >= 10
| distinct SourceIP;
CommonSecurityLog
| where TimeGenerated > ago(24h)
| where Activity has_any ("vpn", "ssl-vpn", "remote-access")
| where Message has_any ("success", "established", "connected", "authenticated")
| where SourceIP in (VPNFailingIPs)
| project TimeGenerated, SourceIP, DestinationUserName, DeviceVendor,
DeviceAddress, Activity, Message
| extend ThreatType = "VPN_SuccessAfterCredentialStuffing"
| extend Severity = "Critical" Two-stage VPN credential stuffing detection: (1) high-volume authentication failures from single or multiple sources against VPN gateway — the stuffing pattern; (2) successful VPN authentication from an IP that previously failed 10+ times — the compromise indicator. Alert 2 should trigger immediate investigation as it indicates a successful account takeover via credential stuffing.
Data Sources
Required Tables
False Positives
- Legitimate users with incorrect VPN credentials due to recent password change (brief surge then success with new credentials)
- Misconfigured VPN clients that retry with old credentials on every connection attempt
- Automated backup or monitoring systems with outdated credentials attempting VPN authentication
- Multiple users behind a shared corporate NAT connecting to VPN simultaneously (same source IP, multiple users)
Sigma rule & cross-platform mapping
The detection logic for VPN and Remote Access Credential Stuffing / Brute Force (THREAT-VPN-CredentialStuffing) above is provided in a vendor-neutral
form so you can deploy it on any SIEM. The same logic is shipped here as native
KQL (Microsoft Sentinel / Defender), SPL (Splunk), Elastic (Elastic Security (EQL)), QRadar (IBM QRadar (AQL)), Sumo (Sumo Logic CSE), YARA-L (Google Chronicle / SecOps), LogScale (CrowdStrike LogScale (CQL)) queries. In Sigma terms, this detection targets the
following logsource:
logsource:
product: azure Browse the community-maintained Sigma rules for this technique:
Platform-specific guides for THREAT-VPN-CredentialStuffing
Testing Methodology
Validate this detection against 1 adversary technique from Atomic Red Team. Each test below lists the behaviour to exercise and the telemetry you should expect to see. Executable commands and cleanup steps are available with Pro.
- Test 1VPN Credential Stuffing Simulation via Python Requests
Expected signal: VPN authentication logs record multiple failures (error: invalid credentials) for multiple usernames from the test IP within the 15-minute window.
Response Playbook
Triage
- Identify the source IP(s) of the credential stuffing. Check AbuseIPDB, Shodan, and VirusTotal for IP reputation. Stuffing typically originates from VPS hosts, botnets, or residential proxies.
- For successful VPN authentications following stuffing: immediately identify the account and their last legitimate authentication. When did they last successfully VPN in? From where? Has their device changed?
- Verify with the user: contact them via phone or secondary communication channel to confirm whether they initiated the VPN session.
- If VPN access is confirmed as unauthorised: immediately terminate the VPN session, disable the account, and assess what the attacker accessed during the session.
- Review VPN session logs for the compromised account: which resources did they access? Did they attempt lateral movement? Did they download or access sensitive files?
Containment
- Block the stuffing source IP(s) at the perimeter firewall and in the VPN gateway IP blacklist.
- For accounts with successful authentication from stuffing IP: terminate active sessions, disable account, reset password, require MFA re-enrollment.
- Implement VPN geo-blocking if your workforce is geographically concentrated — block VPN connections from countries where you have no employees.
- Deploy multi-factor authentication on the VPN if not already implemented — credential stuffing is ineffective against VPN MFA.
- Consider implementing client certificate authentication for VPN as an additional factor — certificates cannot be stuffed.
- Apply temporary IP rate limiting on the VPN login endpoint to slow credential stuffing operations.
Evidence Collection
- VPN authentication logs: all failure/success events for the incident window, including usernames and source IPs
- VPN session logs: resource access, traffic volume, duration for successful sessions from stuffing IPs
- Network flow logs from authenticated VPN session: lateral movement attempts, scanning activity
- Threat intelligence lookups for source IPs
Escalation Criteria
- ! Successful VPN authentication from a credential-stuffed IP — immediate incident declaration
- ! Post-VPN-access lateral movement indicators (net use, SMB connections to file servers, RDP to internal hosts)
- ! VPN access to domain controllers or sensitive server segments
- ! Data transfer volume significantly above baseline during the suspicious VPN session
Investigation Guide
Forensic Artifacts
- >
VPN authentication logs with timestamps, usernames, source IPs, and success/failure - >
VPN session records: connected IP, session duration, traffic volume - >
RADIUS/LDAP authentication logs if VPN authentication is federated - >
Network flow logs from VPN-to-internal-network segment during suspicious session
Tuning Guidance
VPN credential stuffing thresholds depend heavily on your environment. For small organisations with few remote users, even 5 failures from a single source in 15 minutes may be anomalous. For large organisations with many remote workers, failure rates may be higher due to legitimate connection issues. The most actionable signal is the success-after-failure detection — tune the failure prerequisite threshold down for high-security environments (as low as 5 failures) since a successful authentication following any unusual failure pattern warrants investigation. Also consider alerting on VPN logins outside business hours for accounts that have never historically accessed VPN at those times.
Hunting Queries
Hunt for IPs with both high failure rates and at least one success against VPN authentication — the credential stuffing to compromise pattern across any time window.
CommonSecurityLog
| where TimeGenerated > ago(7d)
| where DeviceVendor has_any ("Fortinet", "Cisco", "Palo Alto", "SonicWall", "Ivanti")
| where Activity has_any ("vpn", "ssl-vpn", "remote-access")
| summarize
TotalAttempts=count(),
Failures=countif(Message has_any ("fail", "invalid", "reject")),
Successes=countif(Message has_any ("success", "connected", "established"))
by SourceIP, bin(TimeGenerated, 1d)
| where Failures >= 10 and Successes >= 1
| extend SuccessAfterFailure = (Successes >= 1 and Failures >= 10)
| sort by Failures desc index=network sourcetype IN ("fortigate:vpn","cisco:asa","panos:traffic")
(action="failure" OR action="success") type="vpn"
| eval result=if(action="success", "success", "failure")
| bin _time span=1d
| stats sum(eval(if(result="failure",1,0))) AS Failures,
sum(eval(if(result="success",1,0))) AS Successes
BY src_ip, _time
| where Failures >= 10 AND Successes >= 1
| sort - Failures Atomic Red Team Tests
Simulates a credential stuffing attack against a VPN web portal by iterating through a list of username/password pairs. This tests detection of high-volume authentication failures from a single source.
Command
python3 -c "
import requests, time
creds = [('[email protected]','password123'),('[email protected]','Spring2025!'),
('[email protected]','Admin123!'),('[email protected]','Welcome1!')]
for user, pwd in creds * 5:
r = requests.post('https://<VPN_PORTAL>/login', data={'username':user,'password':pwd}, verify=False)
print(f'{user}: {r.status_code}')
time.sleep(1)
" Expected Telemetry
VPN authentication logs record multiple failures (error: invalid credentials) for multiple usernames from the test IP within the 15-minute window.
Expected Detection
Alert fires when FailureCount >= 20 or UniqueUsers >= 5 within the 15-minute aggregation window.