From 9c2750ea72b6ecd68805faedd744933ac35ea03d Mon Sep 17 00:00:00 2001 From: Karl Fosaaen Date: Tue, 4 Aug 2020 16:30:57 -0700 Subject: [PATCH] Added Get-AzKeyVaultSecretsREST REST API function to pull Key Vault secrets --- REST/Get-AzKeyVaultSecretsREST.ps1 | 103 +++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 REST/Get-AzKeyVaultSecretsREST.ps1 diff --git a/REST/Get-AzKeyVaultSecretsREST.ps1 b/REST/Get-AzKeyVaultSecretsREST.ps1 new file mode 100644 index 0000000..aa6e568 --- /dev/null +++ b/REST/Get-AzKeyVaultSecretsREST.ps1 @@ -0,0 +1,103 @@ +Function Get-AzKeyVaultSecretsREST +{ + + # Author: Karl Fosaaen (@kfosaaen), NetSPI - 2020 + # Description: PowerShell function for enumerating available Key Vault Secrets using Azure Bearer tokens and the REST APIs. + # Pipe to "Export-Csv -NoTypeInformation" for easier exporting + # Use the SubscriptionId and token parameters to specify bearer tokens and subscriptions, handy for compromised bearer tokens from other services (CloudShell/AutomationAccounts/AppServices) + + [CmdletBinding()] + Param( + [Parameter(Mandatory=$false, + HelpMessage="Subscription ID")] + [string]$SubscriptionId, + + [Parameter(Mandatory=$true, + HelpMessage="The management scoped token")] + [string]$managementToken, + + [Parameter(Mandatory=$true, + HelpMessage="The KeyVault Scoped Token")] + [string]$vaultToken + ) + + # Sort out which subscription to list keys from + if ($SubscriptionId -eq ''){ + + # List all subscriptions for a tenant + $subscriptions = ((Invoke-WebRequest -Uri ('https://management.azure.com/subscriptions?api-version=2019-11-01') -Verbose:$false -Method GET -Headers @{ Authorization ="Bearer $managementToken"} -UseBasicParsing).content | ConvertFrom-Json).value + + # Select which subscriptions to dump info for + $subChoice = $subscriptions | out-gridview -Title "Select One or More Subscriptions" -PassThru + + if($subChoice.count -eq 0){Write-Verbose 'No subscriptions selected, exiting'; break} + + } + else{$subChoice = $SubscriptionId; $noLoop = 1} + + # Create data table to house results + $TempTbl = New-Object System.Data.DataTable + $TempTbl.Columns.Add("SubscriptionName") | Out-Null + $TempTbl.Columns.Add("KeyVault") | Out-Null + $TempTbl.Columns.Add("SecretURL") | Out-Null + $TempTbl.Columns.Add("SecretType") | Out-Null + $TempTbl.Columns.Add("SecretValue") | Out-Null + + + # Iterate through each subscription and list keys + foreach($sub in $subChoice){ + + # If subs are chosen from a list, grab the Id + if($noLoop){} + else{$SubscriptionId = $sub.subscriptionId} + + if($sub.displayName -ne $null){$subName = $sub.displayName; Write-Verbose "Gathering Key Vaults for the $subName subscription"} + else{ + try {$subName = ((Invoke-WebRequest -Uri (-join ('https://management.azure.com/subscriptions/',$SubscriptionId,'?api-version=2019-11-01')) -Verbose:$false -Method GET -Headers @{ Authorization ="Bearer $managementToken"} -UseBasicParsing).Content | ConvertFrom-Json).displayName} + catch{$subName = "undetermined"} + Write-Verbose "Gathering storage accounts for the $subName subscription" + } + + + # Get List of Key Vaults + $responseKeys = ((Invoke-WebRequest -Uri (-join ('https://management.azure.com/subscriptions/',$SubscriptionId,"/providers/Microsoft.KeyVault/vaults?api-version=2019-09-01")) -Verbose:$false -Method GET -Headers @{ Authorization ="Bearer $managementToken"} -UseBasicParsing).Content | ConvertFrom-Json) + + # Keeping the second method of vault enumeration as a backup option + #$responseKeys = ((Invoke-WebRequest -Uri (-join ('https://management.azure.com/subscriptions/',$SubscriptionId,"/resources?`$filter=resourceType eq 'Microsoft.KeyVault/vaults'&api-version=2019-09-01")) -Verbose:$false -Method GET -Headers @{ Authorization ="Bearer $managementToken"} -UseBasicParsing).Content | ConvertFrom-Json) + + if ($responseKeys.value -ne $null){$keyVaults = $responseKeys.value} + else{$keyVaults = $null} + + + if($keyVaults -eq $null){Write-Verbose "`tNo Key Vaults enumerated for the $subName Subscription"} + else{ + # Iterate through each available vault + foreach ($vault in $keyVaults){ + $vaultName = $vault.name + + # Get Secrets + try{ + Write-Verbose "`tGetting Secrets for $vaultName" + $secretsList = ((Invoke-WebRequest -Uri (-join ('https://',$vault.name,'.vault.azure.net/secrets?api-version=7.0')) -Verbose:$false -Method GET -Headers @{ Authorization ="Bearer $vaultToken"} -UseBasicParsing).content | ConvertFrom-Json).value + + # Get Values for each Secret + $secretsList | ForEach-Object{ + $secretType = $_.contentType + if($secretType -eq $null){$secretType = "No_Type_Set"} + Write-Verbose "`t`tGetting a $secretType from $vaultName" + + $secretValue = ((Invoke-WebRequest -Uri (-join ($_.id,'?api-version=7.0')) -Verbose:$false -Method GET -Headers @{ Authorization ="Bearer $vaultToken"} -UseBasicParsing).content | ConvertFrom-Json) + + # Add the key to the table + $TempTbl.Rows.Add($subName, $vaultName, $secretValue.id, $secretType, $secretValue.value) | Out-Null + + } + } + catch{Write-Verbose "`t`tCurrent token does not have secrets list permissions for this vault or secret"} + + } + } + $responseKeys = $null + } + Write-Output $TempTbl +} \ No newline at end of file