VPN Entry and Internal Brute Force
An attacker has gained initial access through a misconfigured VPN gateway lacking multi-factor authentication and is brute-forcing administrator accounts across internal systems to escalate privileges.
Based on research by Unit 42 2026-10-14 9 steps · 3 queries T1078 T1110 T1133
Brief
Why this hunt
Unit 42 recently detailed an intrusion in "The Noise Inside the Network: How an Unsophisticated Attack Exposed a Third-Party Risk" (https://unit42.paloaltonetworks.com/noise-inside-network-third-party-risk/). The report highlights how attackers exploit weak perimeter security on third-party access points. This hunt replicates that detection path. We look for the moment an adversary enters via a VPN and immediately begins testing credentials to move laterally.
How the hunt flows
The scoping phase targets the perimeter. The first query identifies successful sign-ins to VPN services where multi-factor authentication was either disabled or not reported. This narrows the focus to high-risk sessions that bypass standard security controls.
The second phase fans out to find evidence of lateral risk. One query monitors for internal brute-force patterns. It identifies internal source IPs attempting to guess passwords for multiple administrative accounts, such as root or service accounts. Simultaneously, the hunt baselines account lifecycle changes. It looks for rare password resets or account creations that deviate from normal administrative behavior.
The triage phase correlates these signals. An agent evaluates the coincidence of the MFA-less VPN entry, the volume of internal authentication failures, and any anomalous account modifications. This determines if the activity indicates a successful intrusion or routine network noise.
What this hunt cannot see
This hunt has two primary blind spots. First, it depends on VPN gateway logs residing in the central data lake. If an attacker enters through an unmonitored or shadow gateway, the scoping step will fail. Second, the hunt relies on the accuracy of MFA reporting. If a provider always reports MFA status as NULL or if the ingestion parser does not correctly map the field, the hunt will generate excessive false positives.
Why this is a hunt
We designed this as a hunt because a single detection rule typically focuses on one signal, such as a brute-force attempt. That approach lacks context. This hunt correlates the entry point with the subsequent volume of failures and the baseline of account changes. By looking at the identity plane holistically, we distinguish between a noisy scanner and a specific adversary following a perimeter breach.
In this series
Steps
-
VPN Sign-ins Without MFA
Query · scopingIdentify successful logins to VPN services that did not use or report multi-factor authentication.
reads hb_auth_signinsqlSELECT DISTINCT device_hostname, actor_user_name, src_endpoint_ip, service_name, time FROM hb_auth_signin WHERE status_id = 1 AND (mfa = 'false' OR mfa IS NULL) AND (LOWER(service_name) LIKE '%vpn%' OR LOWER(dst_endpoint_name) LIKE '%vpn%' OR LOWER(metadata_product) LIKE '%vpn%') AND time >= datetime('now', '-{{lookback_days}} days')What a hit looks like. Rows naming the VPN gateway and the users who successfully logged in without MFA. Silence proves no MFA-less logins were recorded for gateways reporting to the lake.
-
Internal Brute Force Against Admins
Query · detection candidateFind source IPs attempting to guess passwords for multiple administrative accounts.
reads hb_auth_signinsqlSELECT src_endpoint_ip, device_hostname, COUNT(DISTINCT actor_user_name) AS unique_accounts, COUNT(*) AS attempt_count FROM hb_auth_signin WHERE status_id = 2 AND (LOWER(actor_user_name) LIKE '%admin%' OR LOWER(actor_user_name) LIKE '%root%' OR instr(',' || '{{admin_account_patterns}}' || ',', ',' || LOWER(actor_user_name) || ',') > 0) AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days') GROUP BY src_endpoint_ip, device_hostname HAVING attempt_count > 20What a hit looks like. A single internal IP address generating dozens of authentication failures across different admin names. Silence suggests no automated guessing was visible on these hosts.
-
Rare Account Lifecycle Changes
Query · baselineBaseline account changes to identify rare password resets or creations that could indicate persistence.
reads hb_account_changesqlSELECT user_name, activity_name, device_hostname, COUNT(DISTINCT actor_user_name) AS distinct_actors, MIN(time) AS first_change FROM hb_account_change WHERE activity_id IN (1, 4) AND time >= datetime('now', '-{{lookback_days}} days') GROUP BY user_name, activity_name, device_hostnameWhat a hit looks like. A password reset or account creation performed by an unusual actor. Baseline noise will show routine resets; anomalous entries will have low actor counts.
-
Triage Identity Risks
Agent triageEvaluate whether the VPN logins, brute-force attempts, and account changes suggest an active intrusion.
-
Route on Verdict
DecisionRoute the hunt based on the agent's findings.
-
Revoke Compromised Access
Response actionContain the threat by terminating sessions and resetting credentials.
-
Analyst Deep Dive
Analyst taskVerify the agent's findings and look for lateral movement not captured by the queries.
-
Hunt Close-out
Analyst taskDocument findings and record any gaps in telemetry.
Coverage
Scenario coverage
| Stage | Covered | How, or why not |
|---|---|---|
| Unauthorized VPN Access T1133 · T1078 |
Yes | vpn-entry-no-mfa |
| Internal Credential Brute Force T1110 |
Yes | internal-brute-force, unusual-account-changes |
| Broad Internal Discovery | Out of scope | Handled by a separate hunt focusing on network scanning. |
| Internal Data Collection | Out of scope | Handled by a separate hunt focusing on SMB and HTTP data scraping. |
| WSUS Remote Code Execution Attempt T1190 |
Out of scope | Handled by a separate hunt focusing on WSUS and configuration management exploitation. |
Blind spots
- Needs VPN gateway logs in hb_auth_signin. The hunt misses entry points through unmonitored infrastructure. It would answer whether logins occurred through gateways not enrolled in the lake. Remediation: Enrol all third-party VPN gateways in central logging.
- Needs Reliable MFA status in hb_auth_signin. If MFA status is always NULL, the scoping step will produce excessive false positives. It would answer whether the 'mfa' column is accurately populated by the provider. Remediation: Verify MFA logging capabilities of the gateway and update the ingestion parser if needed.
Parameters & data
Parameters
| Parameter | Type | Default | What it is |
|---|---|---|---|
admin_account_patterns | list[string] | admin, root, administrator, svc_, sql, backup | Administrative username substrings or specific accounts to prioritize in brute-force detection. |
lookback_days | number | 14 | Days of history to examine. |
scope_hosts | list[host] | — | Target hosts identified in the scoping step; leave empty to hunt across the entire estate. |
Telemetry
| Source | Category | Telemetry |
|---|---|---|
| Endpoint telemetry (hb_ surfaces) | endpoint | endpoint |
| Identity / sign-in telemetry | identity | identity |
Source
---
analysis: 'This hunt correlates three distinct identity-plane signals: the initial
VPN entry, the volume of failures, and rare account modifications. A single rule
usually only fires on the failures, lacking the context of the entry point and the
baseline of account changes.'
blind_spots:
- id: missing-vpn-logs
owner: Security Engineering
question: whether logins occurred through gateways not enrolled in the lake
remediation: Enrol all third-party VPN gateways in central logging.
requires: VPN gateway logs in hb_auth_signin
risk: The hunt misses entry points through unmonitored infrastructure.
stage: unauthorized-vpn-access
- id: mfa-reporting-gap
owner: Detection Engineering
question: whether the 'mfa' column is accurately populated by the provider
remediation: Verify MFA logging capabilities of the gateway and update the ingestion
parser if needed.
requires: Reliable MFA status in hb_auth_signin
risk: If MFA status is always NULL, the scoping step will produce excessive false
positives.
stage: unauthorized-vpn-access
coverage:
- stage: unauthorized-vpn-access
status: covered
steps:
- vpn-entry-no-mfa
- stage: internal-credential-testing
status: covered
steps:
- internal-brute-force
- unusual-account-changes
- reason: Handled by a separate hunt focusing on network scanning.
stage: internal-network-discovery
status: out_of_scope
- reason: Handled by a separate hunt focusing on SMB and HTTP data scraping.
stage: data-share-and-doc-collection
status: out_of_scope
- reason: Handled by a separate hunt focusing on WSUS and configuration management
exploitation.
stage: wsus-exploitation-attempt
status: out_of_scope
guardrails:
claims: no_unsupported
evidence: citation_required
missing_data: not_benign
telemetry: untrusted
hunt:
applicability: campaign-specific
handoff: promote-to-detection
justification: Third-party risk via misconfigured external gateways is a high-impact
exposure. Identifying successful entries and subsequent brute-force noise is a
fundamental requirement for securing the network perimeter.
methodology: model-assisted
trigger: intel-report
hypothesis: An attacker has gained initial access through a misconfigured VPN gateway
lacking multi-factor authentication and is brute-forcing administrator accounts
across internal systems to escalate privileges.
labels:
- hunt
- attack.t1133
- attack.t1078
- attack.t1110
- collection
- credential access
- discovery
- execution
- initial access
name: VPN Entry and Internal Brute Force
parameters:
admin_account_patterns:
default:
- admin
- root
- administrator
- svc_
- sql
- backup
description: Administrative username substrings or specific accounts to prioritize
in brute-force detection.
from:
kind: article
observed: '2026-10-13'
ref: unit42-third-party-risk
type: list[string]
lookback_days:
default: '14'
description: Days of history to examine.
from:
kind: manual
observed: '2024-01-01'
ref: hunt-standard
type: number
scope_hosts:
default: []
description: Target hosts identified in the scoping step; leave empty to hunt
across the entire estate.
from:
kind: manual
observed: '2024-01-01'
ref: analyst-scoping
type: list[host]
provenance:
authors:
- name: Huntbase hunt generation
org: huntbase.io
generated:
by: huntbase-hunt-generation
from: https://unit42.paloaltonetworks.com/noise-inside-network-third-party-risk/
gates:
- dry-run
- lint
model: hb_google/gemini-3-flash-preview
rationale: Start with external-facing VPN gateways. Focus on accounts that log in
from geographically unusual locations or at anomalous times, especially those that
do not trigger an MFA challenge.
references:
- name: 'The Noise Inside the Network: How an Unsophisticated Attack Exposed a Third-Party
Risk'
url: https://unit42.paloaltonetworks.com/noise-inside-network-third-party-risk/
related:
- hunt: internal-recon-and-lateral-movement
reason: After testing credentials, an attacker typically conducts internal discovery
to find high-value targets.
relation: follows
scenario:
stages:
- name: Unauthorized VPN Access
observables:
- VPN-based access attempts
- Third-party-managed external gateway appliance
- Compromised credentials
- Authentication without MFA
slug: unauthorized-vpn-access
tactic: initial-access
techniques:
- T1133
- T1078
- name: Broad Internal Discovery
observables:
- Host and network scans
- Interactions with thousands of systems
- Multiple protocol usage for reconnaissance
slug: internal-network-discovery
tactic: discovery
- name: Internal Credential Brute Force
observables:
- Password-guessing campaigns
- Brute-force authentication attempts
- Targeting of administrator accounts
slug: internal-credential-testing
tactic: credential-access
techniques:
- T1110
- name: Internal Data Collection
observables:
- Automated web requests to internal systems
- Scraping documentation pages and attachments
- Enumeration of network shares
slug: data-share-and-doc-collection
tactic: collection
- name: WSUS Remote Code Execution Attempt
observables:
- WSUS remote code execution vulnerability
- Central configuration management server
- Unauthorized code execution attempt
slug: wsus-exploitation-attempt
tactic: execution
techniques:
- T1190
summary: An opportunistic attacker exploited a misconfigured third-party VPN gateway
using compromised credentials to gain access to a bank's internal network. The
intruder performed broad network scanning, brute-force attempts against administrator
accounts, and scraped internal documentation before attempting to execute code
via a WSUS vulnerability, which was blocked by endpoint security.
series:
index: 1
slug: the-noise-inside-the-network-how-an-unsophisticated-attack-exposed-a-third-party-risk
title: 'The Noise Inside the Network: How an Unsophisticated Attack Exposed a Third-Party
Risk'
total: 2
severity: medium
targets:
analyst:
name: Tier-2 analyst
role: analyst
endpoint:
category: endpoint
name: Endpoint telemetry (hb_ surfaces)
telemetry:
- endpoint
hunter:
agent: true
name: Hunt agent
identity:
category: identity
name: Identity / sign-in telemetry
telemetry:
- identity
tlp: clear
type: investigation
---
# VPN Entry and Internal Brute Force
This hunt examines the identity plane for signs of third-party risk and credential abuse. It starts by scoping for successful VPN sign-ins where multi-factor authentication (MFA) was not enforced. It then fans out to identify internal brute-force patterns targeting administrative accounts and correlates these with rare account lifecycle changes, such as password resets or account creations. An agent weighs the combined evidence to distinguish between automated noisy scanners and a successful intrusion originating from a compromised VPN session.
## vpn-entry-no-mfa
<!-- VPN Sign-ins Without MFA -->
Identify successful logins to VPN services that did not use or report multi-factor authentication.
```sqlite target=identity role=scoping params=(lookback_days=lookback_days)
~~~yaml
expected: Rows naming the VPN gateway and the users who successfully logged in without
MFA. Silence proves no MFA-less logins were recorded for gateways reporting to the
lake.
reads:
- device_hostname
- actor_user_name
- src_endpoint_ip
- service_name
- dst_endpoint_name
- mfa
- status_id
- time
- metadata_product
silence: not_evidence_of_absence
source: hb_auth_signin
verified: dry-run
verified_at: '2026-10-14'
~~~
SELECT DISTINCT device_hostname, actor_user_name, src_endpoint_ip, service_name, time FROM hb_auth_signin WHERE status_id = 1 AND (mfa = 'false' OR mfa IS NULL) AND (LOWER(service_name) LIKE '%vpn%' OR LOWER(dst_endpoint_name) LIKE '%vpn%' OR LOWER(metadata_product) LIKE '%vpn%') AND time >= datetime('now', '-{{lookback_days}} days')
```
## investigate-lateral-risk
<!-- Investigate Brute Force and Rare Changes -->
parallel:
- → internal-brute-force
- → unusual-account-changes
join: → triage-identity-signals
## internal-brute-force
<!-- Internal Brute Force Against Admins -->
Find source IPs attempting to guess passwords for multiple administrative accounts.
```sqlite target=identity role=detection-candidate params=(lookback_days=lookback_days, admin_account_patterns=admin_account_patterns, scope_hosts=scope_hosts)
~~~yaml
expected: A single internal IP address generating dozens of authentication failures
across different admin names. Silence suggests no automated guessing was visible
on these hosts.
reads:
- src_endpoint_ip
- device_hostname
- actor_user_name
- status_id
- time
silence: not_evidence_of_absence
source: hb_auth_signin
verified: dry-run
verified_at: '2026-10-14'
~~~
SELECT src_endpoint_ip, device_hostname, COUNT(DISTINCT actor_user_name) AS unique_accounts, COUNT(*) AS attempt_count FROM hb_auth_signin WHERE status_id = 2 AND (LOWER(actor_user_name) LIKE '%admin%' OR LOWER(actor_user_name) LIKE '%root%' OR instr(',' || '{{admin_account_patterns}}' || ',', ',' || LOWER(actor_user_name) || ',') > 0) AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days') GROUP BY src_endpoint_ip, device_hostname HAVING attempt_count > 20
```
## unusual-account-changes
<!-- Rare Account Lifecycle Changes -->
Baseline account changes to identify rare password resets or creations that could indicate persistence.
```sqlite target=endpoint role=baseline params=(lookback_days=lookback_days)
~~~yaml
baseline:
compare: first_seen
window: '{{lookback_days}}d'
expected: A password reset or account creation performed by an unusual actor. Baseline
noise will show routine resets; anomalous entries will have low actor counts.
prevalence:
by: device_hostname
key:
- user_name
- activity_name
rare_below: 3
reads:
- user_name
- activity_name
- device_hostname
- activity_id
- actor_user_name
- time
silence: not_evidence_of_absence
source: hb_account_change
verified: dry-run
verified_at: '2026-10-14'
~~~
SELECT user_name, activity_name, device_hostname, COUNT(DISTINCT actor_user_name) AS distinct_actors, MIN(time) AS first_change FROM hb_account_change WHERE activity_id IN (1, 4) AND time >= datetime('now', '-{{lookback_days}} days') GROUP BY user_name, activity_name, device_hostname
```
## triage-identity-signals
<!-- Triage Identity Risks -->
```agent target=hunter
cite: required
context:
- vpn-entry-no-mfa
- internal-brute-force
- unusual-account-changes
max_iterations: 4
objective: Identify hosts where a user successfully logged in via VPN without MFA
and then initiated brute-force attempts or sensitive account modifications internally.
success_criteria: A per-host verdict of malicious, suspicious, or benign citing specific
rows.
tools:
- endpoint
- identity
```
## route-verdict
<!-- Route on Verdict -->
if~: "the triage verdict is malicious for at least one host or user" (confidence: high, judge=hunter)
then: → revoke-compromised-access
indeterminate: → analyst-validation
unavailable: → analyst-validation (blind_spot: missing-vpn-logs)
else: → hunt-summary
## revoke-compromised-access
<!-- Revoke Compromised Access -->
```action target=identity
~~~yaml
approval: required
~~~
Revoke all active sessions for the compromised accounts and force a password reset after confirming the scope with the IR lead.
```
→ analyst-validation
## analyst-validation
<!-- Analyst Deep Dive -->
```manual target=analyst
Review the source IPs and actor_user_name from the VPN logins. Note that the internal source IP for the brute force may be an internal jump box or the beachhead host itself. Pivot to hb_network_connection to verify if the beachhead host contacted the systems targeted in the brute-force query.
```
→ hunt-summary
## hunt-summary
<!-- Hunt Close-out -->
```manual target=analyst
Document whether the brute-force attempts were successful. If the failure threshold resulted in too many false positives, recommend tuning the detection-candidate query for the environment.
```
→ end
Run it
Take this hunt into your environment.
Open it in Huntbase to run every step against your own connections, with Scout weighing the evidence and your analysts in command. Or take the open hunt.md file anywhere that reads the format.
Machine-drafted by huntbase-hunt-generation using hb_google/gemini-3-flash-preview, gated by dry-run, lint, then reviewed by a person.