Public/Reconnaissance/anonymous/Find-AzurePublicResource.ps1
function Find-AzurePublicResource { [cmdletbinding()] param ( [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [ValidatePattern('^[A-Za-z0-9][A-Za-z0-9-]+[A-Za-z0-9]$', ErrorMessage = "It does not match expected pattern '{1}'")] [string]$Name, [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [Alias("word-list", "w")] [string]$WordList, [Parameter(Mandatory = $false)] [Alias("throttle-limit", 't', 'threads')] [int]$ThrottleLimit = 50, [Parameter(Mandatory = $false)] [ValidateSet("Object", "JSON", "CSV")] [Alias("output", "o")] [string]$OutputFormat ) begin { $validDnsNames = [System.Collections.Concurrent.ConcurrentBag[string]]::new() } process { Write-Host "🎯 Analyzing Azure resources for: $Name" -ForegroundColor Green try { if ($WordList) { Write-Host " 📄 Loading permutations from word list..." -ForegroundColor Cyan $permutations = [System.Collections.Generic.HashSet[string]](Get-Content $WordList) Write-Host " ā Loaded $($permutations.Count) permutations from '$WordList'" -ForegroundColor Green } else { $permutations = [System.Collections.Generic.HashSet[string]]::new() } if ($sessionVariables.permutations) { Write-Host " 📊 Loading session permutations..." -ForegroundColor Cyan $permutations += $sessionVariables.permutations Write-Host " ā Loaded total of $($permutations.Count) permutations" -ForegroundColor Green } Write-Host " 🌐 Generating Azure service DNS names..." -ForegroundColor Yellow $dnsNames = [System.Collections.Generic.HashSet[string]]::new([StringComparer]::OrdinalIgnoreCase) $domains = @( # Storage 'blob.core.windows.net', # Blob Storage 'file.core.windows.net', # File Storage 'table.core.windows.net', # Table Storage 'queue.core.windows.net', # Queue Storage 'dfs.core.windows.net', # Data Lake Storage Gen2 # Databases 'database.windows.net', # SQL Database 'documents.azure.com', # Cosmos DB 'redis.cache.windows.net', # Redis Cache 'mysql.database.azure.com', # MySQL 'postgres.database.azure.com', # PostgreSQL 'mariadb.database.azure.com', # MariaDB # Security 'vault.azure.net', # Key Vault # Compute & Containers 'azurecr.io', # Container Registry 'azurewebsites.net', # App Service/Functions 'scm.azurewebsites.net', # App Service Kudu # AI/ML 'cognitiveservices.azure.com', 'openai.azure.com', # Azure OpenAI 'search.windows.net', # Azure Search 'azureml.net', # Machine Learning # Integration 'servicebus.windows.net', 'azure-api.net', # API Management 'service.signalr.net', # SignalR Service 'webpubsub.azure.com', # Web PubSub # Other 'azureedge.net', # CDN 'azure-devices.net', # IoT Hub 'eventgrid.azure.net', # Event Grid 'azuremicroservices.io', # Spring Apps 'azuresynapse.net', # Synapse Analytics 'atlas.microsoft.com', # Azure Maps 'batch.azure.com' # Azure Batch ) $domains | ForEach-Object { $domain = $_ $permutations | ForEach-Object { [void] $dnsNames.Add(('{0}{1}.{2}' -f $Name, $_, $domain)) [void] $dnsNames.Add(('{1}{0}.{2}' -f $Name, $_, $domain)) [void] $dnsNames.Add(('{0}.{1}' -f $Name, $domain)) } } $totalDns = $dnsNames.Count Write-Host " 🎯 Testing $totalDns DNS name candidates..." -ForegroundColor Yellow Write-Host " 🔍 Starting DNS resolution with $ThrottleLimit concurrent threads..." -ForegroundColor Cyan $results = [System.Collections.Concurrent.ConcurrentBag[psobject]]::new() # Create a thread-safe collection to track found resources for immediate display $foundResources = [System.Collections.Concurrent.ConcurrentBag[string]]::new() $dnsNames | Sort-Object -Unique | ForEach-Object -ThrottleLimit $ThrottleLimit -Parallel { function Get-ResourceType { param($dnsName) switch -Regex ($dnsName) { # Storage '\.blob\.core\.windows\.net$' { return 'StorageBlob' } '\.file\.core\.windows\.net$' { return 'StorageFile' } '\.table\.core\.windows\.net$' { return 'StorageTable' } '\.queue\.core\.windows\.net$' { return 'StorageQueue' } '\.dfs\.core\.windows\.net$' { return 'DataLakeStorage' } # Databases '\.database\.windows\.net$' { return 'SqlDatabase' } '\.documents\.azure\.com$' { return 'CosmosDB' } '\.redis\.cache\.windows\.net$' { return 'RedisCache' } '\.mysql\.database\.azure\.com$' { return 'MySQL' } '\.postgres\.database\.azure\.com$' { return 'PostgreSQL' } '\.mariadb\.database\.azure\.com$' { return 'MariaDB' } # Security '\.vault\.azure\.net$' { return 'KeyVault' } # Compute & Containers '\.azurecr\.io$' { return 'ContainerRegistry' } '\.azurewebsites\.net$' { return 'AppService' } '\.scm\.azurewebsites\.net$' { return 'AppServiceKudu' } # AI/ML '\.cognitiveservices\.azure\.com$' { return 'CognitiveServices' } '\.openai\.azure\.com$' { return 'AzureOpenAI' } '\.search\.windows\.net$' { return 'AzureSearch' } '\.azureml\.net$' { return 'MachineLearning' } # Integration '\.servicebus\.windows\.net$' { return 'ServiceBus' } '\.azure-api\.net$' { return 'APIManagement' } '\.service\.signalr\.net$' { return 'SignalR' } '\.webpubsub\.azure\.com$' { return 'WebPubSub' } # Other '\.azureedge\.net$' { return 'CDN' } '\.azure-devices\.net$' { return 'IoTHub' } '\.eventgrid\.azure\.net$' { return 'EventGrid' } '\.azuremicroservices\.io$' { return 'SpringApps' } '\.azuresynapse\.net$' { return 'SynapseAnalytics' } '\.atlas\.microsoft\.com$' { return 'AzureMaps' } '\.batch\.azure\.com$' { return 'AzureBatch' } default { return 'Unknown' } } } try { $validDnsNames = $using:validDnsNames $results = $using:results $foundResources = $using:foundResources $dnsResult = [System.Net.Dns]::GetHostEntry($_) if ($dnsResult -and $dnsResult.AddressList.Count -gt 0) { $resourceType = Get-ResourceType -dnsName $_ $ipAddresses = $dnsResult.AddressList.IPAddressToString -join ", " $resourceName = $_.Split('.')[0] # Create the result object $obj = [PSCustomObject]@{ Domain = $_ RecordType = "A" Data = $ipAddresses TTL = $null DNSProvider = "System.Net.Dns" ProviderType = "System" ProviderRegion = "Local" Reliability = $null Timestamp = Get-Date QueryMethod = "GetHostEntry" ResourceName = $resourceName ResourceType = $resourceType Uri = "https://$_" HostName = $dnsResult.HostName IPAddress = $dnsResult.AddressList } $results.Add($obj) # Add to found resources for immediate display $foundMessage = " ā $resourceName -> $ipAddresses [$resourceType]" $foundResources.Add($foundMessage) } } catch [System.Net.Sockets.SocketException] { } } # Display found resources immediately after parallel processing if ($foundResources.Count -gt 0) { foreach ($message in $foundResources) { Write-Host $message -ForegroundColor Green } } } catch { Write-Message -FunctionName $($MyInvocation.MyCommand.Name) -Message $($_.Exception.Message) -Severity 'Error' } } end { Write-Verbose "Function $($MyInvocation.MyCommand.Name) completed" if ($results -and $results.Count -gt 0) { Write-Host "`n📊 Azure Resource Discovery Summary:" -ForegroundColor Magenta Write-Host " Total Resources Found: $($results.Count)" -ForegroundColor Yellow # Group by resource type for summary $resourceTypeCounts = $results | Group-Object ResourceType | Sort-Object Count -Descending foreach ($group in $resourceTypeCounts) { Write-Host " $($group.Name): $($group.Count)" -ForegroundColor White } # Return results in requested format switch ($OutputFormat) { "JSON" { return $results | ConvertTo-Json -Depth 3 } "CSV" { return $results | ConvertTo-CSV } "Object" { return $results } default { return $results | Format-Table -AutoSize } } } else { Write-Host "`nā No public Azure resources found" -ForegroundColor Red Write-Information "No public Azure resources found" -InformationAction Continue } } <# .SYNOPSIS Finds publicly accessible Azure resources. .DESCRIPTION The Find-AzurePublicResource function generates permutations of Azure resource names using a base name and an optional wordlist. It constructs DNS names for various Azure services including Storage, Databases, Security, Compute, AI/ML, Integration, and other Azure services. The function attempts to resolve these DNS names and returns successfully resolved resources with their type, IP addresses, and URIs. The function provides real-time feedback with emoji-decorated console output showing progress and discovered resources. It supports multiple output formats and uses parallel processing for efficient DNS resolution. .PARAMETER Name The base name of the Azure resource to search for. Must match the pattern: starts and ends with an alphanumeric character, and may contain hyphens. .PARAMETER WordList Optional. Path to a file containing additional words (one per line) to use for generating name permutations. These words will be combined with the base name to create potential resource names. Aliases: word-list, w .PARAMETER ThrottleLimit Optional. The maximum number of concurrent DNS resolution operations. Default is 50. Adjust based on system resources and network capacity. Aliases: throttle-limit, t, threads .PARAMETER OutputFormat Optional. Specifies the output format for results. Valid values are: - Object: Returns PowerShell objects (default when piping) - JSON: Returns results in JSON format - CSV: Returns results in CSV format Aliases: output, o .EXAMPLE Find-AzurePublicResource -Name "contoso" -WordList "./wordlist.txt" -ThrottleLimit 100 -OutputFormat JSON Searches for Azure resources using "contoso" with custom permutations from wordlist.txt, using 100 concurrent threads, and returns results in JSON format. .EXAMPLE Find-AzurePublicResource -Name "example" -OutputFormat Table Searches for Azure resources and displays results in a formatted table. .NOTES - Requires PowerShell 7+ for parallel processing functionality - Useful for reconnaissance and security assessments of Azure environments - Only DNS names that successfully resolve are returned as results #> } |