module switch to fail instead of error function
parent
d154627633
commit
7267aae73a
|
@ -68,7 +68,7 @@ class CMEModule:
|
|||
searchBase='CN=Configuration,' + base_dn_root
|
||||
)
|
||||
except LDAPSearchError as e:
|
||||
context.log.error('Obtained unexpected exception: {}'.format(str(e)))
|
||||
context.log.fail('Obtained unexpected exception: {}'.format(str(e)))
|
||||
|
||||
def process_servers(self, item):
|
||||
"""
|
||||
|
@ -98,7 +98,7 @@ class CMEModule:
|
|||
urls.append(match.group(1))
|
||||
except Exception as e:
|
||||
entry = host_name or 'item'
|
||||
self.context.log.error("Skipping {}, cannot process LDAP entry due to error: '{}'".format(entry, str(e)))
|
||||
self.context.log.fail("Skipping {}, cannot process LDAP entry due to error: '{}'".format(entry, str(e)))
|
||||
|
||||
if host_name:
|
||||
self.context.log.highlight('Found PKI Enrollment Server: {}'.format(host_name))
|
||||
|
@ -125,7 +125,7 @@ class CMEModule:
|
|||
templates.append(template_name)
|
||||
except Exception as e:
|
||||
entry = template_name or 'item'
|
||||
self.context.log.error(f"Skipping {entry}, cannot process LDAP entry due to error: '{e}'")
|
||||
self.context.log.fail(f"Skipping {entry}, cannot process LDAP entry due to error: '{e}'")
|
||||
|
||||
if templates:
|
||||
for t in templates:
|
||||
|
|
|
@ -66,14 +66,14 @@ class CMEModule:
|
|||
try:
|
||||
driver = GraphDatabase.driver(uri, auth=(self.neo4j_user, self.neo4j_pass), encrypted=False)
|
||||
except AuthError as e:
|
||||
context.log.error(
|
||||
context.log.fail(
|
||||
"Provided Neo4J credentials ({}:{}) are not valid. See --options".format(self.neo4j_user, self.neo4j_pass))
|
||||
sys.exit()
|
||||
except ServiceUnavailable as e:
|
||||
context.log.error("Neo4J does not seem to be available on {}. See --options".format(uri))
|
||||
context.log.fail("Neo4J does not seem to be available on {}. See --options".format(uri))
|
||||
sys.exit()
|
||||
except Exception as e:
|
||||
context.log.error("Unexpected error with Neo4J")
|
||||
context.log.fail("Unexpected error with Neo4J")
|
||||
context.log.debug("Error : ".format(str(e)))
|
||||
sys.exit()
|
||||
|
||||
|
@ -89,6 +89,6 @@ class CMEModule:
|
|||
if len(value) > 0:
|
||||
context.log.success("Node {} successfully set as owned in BloodHound".format(host_fqdn))
|
||||
else:
|
||||
context.log.error(
|
||||
context.log.fail(
|
||||
"Node {} does not appear to be in Neo4J database. Have you imported correct data?".format(host_fqdn))
|
||||
driver.close()
|
||||
|
|
|
@ -222,7 +222,7 @@ class CMEModule:
|
|||
self.target_file = open(module_options['TARGET'], "r")
|
||||
self.target_sAMAccountName = None
|
||||
except Exception as e:
|
||||
context.log.error("The file doesn't exist or cannot be openned.")
|
||||
context.log.fail("The file doesn't exist or cannot be openned.")
|
||||
else:
|
||||
self.target_sAMAccountName = module_options['TARGET']
|
||||
self.target_file = None
|
||||
|
@ -279,7 +279,7 @@ class CMEModule:
|
|||
)
|
||||
context.log.highlight("Found principal SID to filter on: %s" % self.principal_sid)
|
||||
except Exception as e:
|
||||
context.log.error('Principal SID not found in LDAP (%s)' % _lookedup_principal)
|
||||
context.log.fail('Principal SID not found in LDAP (%s)' % _lookedup_principal)
|
||||
exit(1)
|
||||
|
||||
# Searching for the targets SID and their Security Decriptors
|
||||
|
@ -295,7 +295,7 @@ class CMEModule:
|
|||
data=self.principal_raw_security_descriptor)
|
||||
context.log.highlight('Target principal found in LDAP (%s)' % self.target_principal[0])
|
||||
except Exception as e:
|
||||
context.log.error('Target SID not found in LDAP (%s)' % self.target_sAMAccountName)
|
||||
context.log.fail('Target SID not found in LDAP (%s)' % self.target_sAMAccountName)
|
||||
exit(1)
|
||||
|
||||
if self.action == 'read':
|
||||
|
@ -318,7 +318,7 @@ class CMEModule:
|
|||
data=self.principal_raw_security_descriptor)
|
||||
context.log.highlight('Target principal found in LDAP (%s)' % self.target_sAMAccountName)
|
||||
except Exception as e:
|
||||
context.log.error('Target SID not found in LDAP (%s)' % self.target_sAMAccountName)
|
||||
context.log.fail('Target SID not found in LDAP (%s)' % self.target_sAMAccountName)
|
||||
continue
|
||||
|
||||
if self.action == 'read':
|
||||
|
@ -371,7 +371,7 @@ class CMEModule:
|
|||
try:
|
||||
self.target_principal = target[0]
|
||||
except Exception as e:
|
||||
context.log.error('Principal not found in LDAP (%s), probably an LDAP session issue.' % _lookedup_principal)
|
||||
context.log.fail('Principal not found in LDAP (%s), probably an LDAP session issue.' % _lookedup_principal)
|
||||
exit(0)
|
||||
|
||||
# Attempts to retieve the SID and Distinguisehd Name from the sAMAccountName
|
||||
|
@ -388,7 +388,7 @@ class CMEModule:
|
|||
sid = format_sid(self.ldap_session.entries[0]['objectSid'].raw_values[0])
|
||||
return dn, sid
|
||||
except Exception as e:
|
||||
context.log.error('User not found in LDAP: %s' % samname)
|
||||
context.log.fail('User not found in LDAP: %s' % samname)
|
||||
return False
|
||||
|
||||
# Attempts to resolve a SID and return the corresponding samaccountname
|
||||
|
@ -537,7 +537,7 @@ class CMEModule:
|
|||
RIGHTS_GUID.ResetPassword.value not in parsed_ace['Object type (GUID)'])):
|
||||
print_ace = False
|
||||
except Exception as e:
|
||||
context.log.error(
|
||||
context.log.fail(
|
||||
"Error filtering ACE, probably because of ACE type unsupported for parsing yet (%s)" % e)
|
||||
|
||||
# Filter on specific right GUID
|
||||
|
@ -547,7 +547,7 @@ class CMEModule:
|
|||
self.rights_guid not in parsed_ace['Object type (GUID)']):
|
||||
print_ace = False
|
||||
except Exception as e:
|
||||
context.log.error(
|
||||
context.log.fail(
|
||||
"Error filtering ACE, probably because of ACE type unsupported for parsing yet (%s)" % e)
|
||||
|
||||
# Filter on ACE type
|
||||
|
@ -557,7 +557,7 @@ class CMEModule:
|
|||
'ACCESS_ALLOWED_ACE' not in parsed_ace['ACE Type']):
|
||||
print_ace = False
|
||||
except Exception as e:
|
||||
context.log.error(
|
||||
context.log.fail(
|
||||
"Error filtering ACE, probably because of ACE type unsupported for parsing yet (%s)" % e)
|
||||
else:
|
||||
try:
|
||||
|
@ -565,7 +565,7 @@ class CMEModule:
|
|||
'ACCESS_DENIED_ACE' not in parsed_ace['ACE Type']):
|
||||
print_ace = False
|
||||
except Exception as e:
|
||||
context.log.error(
|
||||
context.log.fail(
|
||||
"Error filtering ACE, probably because of ACE type unsupported for parsing yet (%s)" % e)
|
||||
|
||||
# Filter on trusted principal
|
||||
|
@ -574,7 +574,7 @@ class CMEModule:
|
|||
if self.principal_sid not in parsed_ace['Trustee (SID)']:
|
||||
print_ace = False
|
||||
except Exception as e:
|
||||
context.log.error(
|
||||
context.log.fail(
|
||||
"Error filtering ACE, probably because of ACE type unsupported for parsing yet (%s)" % e)
|
||||
if print_ace:
|
||||
print("[*] %-28s" % "ACE[%d] info" % i)
|
||||
|
|
|
@ -73,11 +73,11 @@ class CMEModule:
|
|||
connection.conn.putFile(share['name'], self.file_path, scfile.read)
|
||||
context.log.success('Created {}.searchConnector-ms file on the {} share'.format(self.filename, share['name']))
|
||||
except Exception as e:
|
||||
context.log.error('Error writing {}.searchConnector-ms file on the {} share: {}'.format(self.filename, share['name'], e))
|
||||
context.log.fail('Error writing {}.searchConnector-ms file on the {} share: {}'.format(self.filename, share['name'], e))
|
||||
else:
|
||||
try:
|
||||
connection.conn.deleteFile(share['name'], self.file_path)
|
||||
context.log.success('Deleted {}.searchConnector-ms file on the {} share'.format(self.filename, share['name']))
|
||||
except Exception as e:
|
||||
context.log.error('Error deleting {}.searchConnector-ms file on share {}: {}'.format(self.filename, share['name'], e))
|
||||
context.log.fail('Error deleting {}.searchConnector-ms file on share {}: {}'.format(self.filename, share['name'], e))
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ class CMEModule:
|
|||
"""
|
||||
|
||||
if not 'LISTENER' in module_options:
|
||||
context.log.error('LISTENER option is required!')
|
||||
context.log.fail('LISTENER option is required!')
|
||||
sys.exit(1)
|
||||
|
||||
self.empire_launcher = None
|
||||
|
@ -45,7 +45,7 @@ class CMEModule:
|
|||
if r.status_code == 200:
|
||||
token = r.json()['token']
|
||||
else:
|
||||
context.log.error("Error authenticating to Empire's RESTful API server!")
|
||||
context.log.fail("Error authenticating to Empire's RESTful API server!")
|
||||
sys.exit(1)
|
||||
|
||||
payload = {'StagerName': 'multi/launcher', 'Listener': module_options['LISTENER']}
|
||||
|
@ -53,7 +53,7 @@ class CMEModule:
|
|||
|
||||
response = r.json()
|
||||
if "error" in response:
|
||||
context.log.error("Error from empire : {}".format(response["error"]))
|
||||
context.log.fail("Error from empire : {}".format(response["error"]))
|
||||
sys.exit(1)
|
||||
|
||||
self.empire_launcher = response['multi/launcher']['Output']
|
||||
|
@ -61,7 +61,7 @@ class CMEModule:
|
|||
context.log.success("Successfully generated launcher for listener '{}'".format(module_options['LISTENER']))
|
||||
|
||||
except ConnectionError as e:
|
||||
context.log.error("Unable to connect to Empire's RESTful API: {}".format(e))
|
||||
context.log.fail("Unable to connect to Empire's RESTful API: {}".format(e))
|
||||
sys.exit(1)
|
||||
|
||||
def on_admin_login(self, context, connection):
|
||||
|
|
|
@ -53,7 +53,7 @@ class CMEModule:
|
|||
pass
|
||||
success += 1
|
||||
except Exception as e:
|
||||
context.log.error(str(e))
|
||||
context.log.fail(str(e))
|
||||
|
||||
context.log.display(f"Detecting running processes on {connection.host} by enumerating pipes...")
|
||||
try:
|
||||
|
|
|
@ -28,11 +28,11 @@ class CMEModule:
|
|||
self.user = ""
|
||||
if 'USER' in module_options:
|
||||
if module_options['USER'] == "":
|
||||
context.log.error('Invalid value for USER option!')
|
||||
context.log.fail('Invalid value for USER option!')
|
||||
exit(1)
|
||||
self.user = module_options['USER']
|
||||
else:
|
||||
context.log.error('Missing USER option, use --options to list available parameters')
|
||||
context.log.fail('Missing USER option, use --options to list available parameters')
|
||||
exit(1)
|
||||
|
||||
def on_login(self, context, connection):
|
||||
|
|
|
@ -60,7 +60,7 @@ class CMEModule:
|
|||
connection.conn.putFile(self.share, self.tmp_share + self.handlekatz, handlekatz.read)
|
||||
context.log.success('Created file {} on the \\\\{}{}'.format(self.handlekatz, self.share, self.tmp_share))
|
||||
except Exception as e:
|
||||
context.log.error('Error writing file to share {}: {}'.format(share, e))
|
||||
context.log.fail('Error writing file to share {}: {}'.format(share, e))
|
||||
|
||||
# get pid lsass
|
||||
command = 'tasklist /v /fo csv | findstr /i "lsass"'
|
||||
|
@ -76,7 +76,7 @@ class CMEModule:
|
|||
context.log.success('Process lsass.exe was successfully dumped')
|
||||
dump = True
|
||||
else:
|
||||
context.log.error('Process lsass.exe error un dump, try with verbose')
|
||||
context.log.fail('Process lsass.exe error un dump, try with verbose')
|
||||
|
||||
if dump:
|
||||
regex = r"([A-Za-z0-9-]*\.log)"
|
||||
|
@ -95,19 +95,19 @@ class CMEModule:
|
|||
connection.conn.getFile(self.share, self.tmp_share + machine_name, dump_file.write)
|
||||
context.log.success('Dumpfile of lsass.exe was transferred to {}'.format(self.dir_result + machine_name))
|
||||
except Exception as e:
|
||||
context.log.error('Error while get file: {}'.format(e))
|
||||
context.log.fail('Error while get file: {}'.format(e))
|
||||
|
||||
try:
|
||||
connection.conn.deleteFile(self.share, self.tmp_share + self.handlekatz)
|
||||
context.log.success('Deleted handlekatz file on the {} share'.format(self.share))
|
||||
except Exception as e:
|
||||
context.log.error('Error deleting handlekatz file on share {}: {}'.format(self.share, e))
|
||||
context.log.fail('Error deleting handlekatz file on share {}: {}'.format(self.share, e))
|
||||
|
||||
try:
|
||||
connection.conn.deleteFile(self.share, self.tmp_share + machine_name)
|
||||
context.log.success('Deleted lsass.dmp file on the {} share'.format(self.share))
|
||||
except Exception as e:
|
||||
context.log.error('Error deleting lsass.dmp file on share {}: {}'.format(self.share, e))
|
||||
context.log.fail('Error deleting lsass.dmp file on share {}: {}'.format(self.share, e))
|
||||
|
||||
h_in = open(self.dir_result + machine_name, "rb")
|
||||
h_out = open(self.dir_result + machine_name + ".decode", "wb")
|
||||
|
@ -132,7 +132,7 @@ class CMEModule:
|
|||
pypy_parse = pypykatz.parse_minidump_external(dump)
|
||||
except Exception as e:
|
||||
pypy_parse = None
|
||||
context.log.error(f'Error parsing minidump: {e}')
|
||||
context.log.fail(f'Error parsing minidump: {e}')
|
||||
|
||||
ssps = ['msv_creds', 'wdigest_creds', 'ssp_creds', 'livessp_creds', 'kerberos_creds', 'credman_creds',
|
||||
'tspkg_creds']
|
||||
|
@ -154,4 +154,4 @@ class CMEModule:
|
|||
if len(credz_bh) > 0:
|
||||
add_user_bh(credz_bh, None, context.log, connection.config)
|
||||
except Exception as e:
|
||||
context.log.error('Error opening dump file', str(e))
|
||||
context.log.fail('Error opening dump file', str(e))
|
||||
|
|
|
@ -32,7 +32,7 @@ def neo4j_conn(context, connection, driver):
|
|||
context.log.fail("Error querying domain admins")
|
||||
context.log.debug(e)
|
||||
else:
|
||||
context.log.error("BloodHound not marked enabled. Check cme.conf")
|
||||
context.log.fail("BloodHound not marked enabled. Check cme.conf")
|
||||
exit(1)
|
||||
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ class CMEModule:
|
|||
if path.isfile(self.imp_exe):
|
||||
file_to_upload = self.imp_exe
|
||||
else:
|
||||
context.log.error(f"Cannot open {self.imp_exe}")
|
||||
context.log.fail(f"Cannot open {self.imp_exe}")
|
||||
exit(1)
|
||||
|
||||
context.log.display(f"Uploading {self.impersonate}")
|
||||
|
@ -63,7 +63,7 @@ class CMEModule:
|
|||
connection.conn.putFile(self.share, f"{self.tmp_share}{self.impersonate}", impersonate.read)
|
||||
context.log.success(f"Impersonate binary successfully uploaded")
|
||||
except Exception as e:
|
||||
context.log.error(f"Error writing file to share {self.tmp_share}: {e}")
|
||||
context.log.fail(f"Error writing file to share {self.tmp_share}: {e}")
|
||||
return
|
||||
|
||||
try:
|
||||
|
@ -88,13 +88,13 @@ class CMEModule:
|
|||
for line in connection.execute(command, True, methods=["smbexec"]).splitlines():
|
||||
context.log.highlight(line)
|
||||
else:
|
||||
context.log.error(f"Invalid token ID submitted")
|
||||
context.log.fail(f"Invalid token ID submitted")
|
||||
|
||||
except Exception as e:
|
||||
context.log.error(f"Error running command: {e}")
|
||||
context.log.fail(f"Error running command: {e}")
|
||||
finally:
|
||||
try:
|
||||
connection.conn.deleteFile(self.share, f"{self.tmp_share}{self.impersonate}")
|
||||
context.log.success(f"Impersonate binary successfully deleted")
|
||||
except Exception as e:
|
||||
context.log.error(f"Error deleting Impersonate.exe on {self.share}: {e}")
|
||||
context.log.fail(f"Error deleting Impersonate.exe on {self.share}: {e}")
|
||||
|
|
|
@ -69,4 +69,4 @@ class CMEModule:
|
|||
if not found:
|
||||
context.log.display('No KeePass-related file were found')
|
||||
elif not found_xml:
|
||||
context.log.error('No config settings file found !!!')
|
||||
context.log.fail('No config settings file found !!!')
|
||||
|
|
|
@ -89,12 +89,12 @@ class CMEModule:
|
|||
|
||||
if 'ACTION' in module_options:
|
||||
if module_options['ACTION'] not in ['ADD', 'CHECK', 'RESTART', 'SINGLE_POLL', 'POLL', 'CLEAN', 'ALL']:
|
||||
context.log.error('Unrecognized action, use --options to list available parameters')
|
||||
context.log.fail('Unrecognized action, use --options to list available parameters')
|
||||
exit(1)
|
||||
else:
|
||||
self.action = module_options['ACTION']
|
||||
else:
|
||||
context.log.error('Missing ACTION option, use --options to list available parameters')
|
||||
context.log.fail('Missing ACTION option, use --options to list available parameters')
|
||||
exit(1)
|
||||
|
||||
if 'KEEPASS_CONFIG_PATH' in module_options:
|
||||
|
@ -111,7 +111,7 @@ class CMEModule:
|
|||
|
||||
if 'PSH_EXEC_METHOD' in module_options:
|
||||
if module_options['PSH_EXEC_METHOD'] not in ['ENCODE', 'PS1']:
|
||||
context.log.error('Unrecognized powershell execution method, use --options to list available parameters')
|
||||
context.log.fail('Unrecognized powershell execution method, use --options to list available parameters')
|
||||
exit(1)
|
||||
else:
|
||||
self.powershell_exec_method = module_options['PSH_EXEC_METHOD']
|
||||
|
@ -159,14 +159,14 @@ class CMEModule:
|
|||
try:
|
||||
self.put_file_execute_delete(context, connection, self.add_trigger_script_str)
|
||||
except Exception as e:
|
||||
context.log.error(f"Error while adding malicious trigger to file: {e}")
|
||||
context.log.fail(f"Error while adding malicious trigger to file: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
# checks if the malicious trigger was effectively added to the specified KeePass configuration file
|
||||
if self.trigger_added(context, connection):
|
||||
context.log.success(f"Malicious trigger successfully added, you can now wait for KeePass reload and poll the exported files")
|
||||
else:
|
||||
context.log.error(f"Unknown error when adding malicious trigger to file")
|
||||
context.log.fail(f"Unknown error when adding malicious trigger to file")
|
||||
sys.exit(1)
|
||||
|
||||
def check_trigger_added(self, context, connection):
|
||||
|
@ -194,12 +194,12 @@ class CMEModule:
|
|||
for process in keepass_process_list:
|
||||
keepass_users.append(process[1])
|
||||
if len(keepass_users) == 0:
|
||||
context.log.error('No running KeePass process found, aborting restart')
|
||||
context.log.fail('No running KeePass process found, aborting restart')
|
||||
return
|
||||
elif len(keepass_users) == 1: # if there is only 1 KeePass process running
|
||||
# if KEEPASS_USER option is specified then we check if the user matches
|
||||
if self.keepass_user and (keepass_users[0] != self.keepass_user and keepass_users[0].split('\\')[1] != self.keepass_user):
|
||||
context.log.error(
|
||||
context.log.fail(
|
||||
f"Specified user {self.keepass_user} does not match any KeePass process owner, aborting restart"
|
||||
)
|
||||
return
|
||||
|
@ -212,12 +212,12 @@ class CMEModule:
|
|||
self.keepass_user = keepass_users[0]
|
||||
found_user = True
|
||||
if not found_user:
|
||||
context.log.error(
|
||||
context.log.fail(
|
||||
f"Specified user {self.keepass_user} does not match any KeePass process owner, aborting restart"
|
||||
)
|
||||
return
|
||||
else:
|
||||
context.log.error('Multiple KeePass processes were found, please specify parameter USER to target one')
|
||||
context.log.fail('Multiple KeePass processes were found, please specify parameter USER to target one')
|
||||
return
|
||||
|
||||
context.log.display("Restarting {}'s KeePass process".format(keepass_users[0]))
|
||||
|
@ -246,7 +246,7 @@ class CMEModule:
|
|||
try:
|
||||
self.put_file_execute_delete(context, connection, self.restart_keepass_script_str)
|
||||
except Exception as e:
|
||||
context.log.error('Error while restarting KeePass: {}'.format(e))
|
||||
context.log.fail('Error while restarting KeePass: {}'.format(e))
|
||||
return
|
||||
|
||||
def poll(self, context, connection):
|
||||
|
@ -295,7 +295,7 @@ class CMEModule:
|
|||
context.log.success('Moved remote "{}" to local "{}"'.format(export_path, local_full_path))
|
||||
found = True
|
||||
except Exception as e:
|
||||
context.log.error("Error while polling export files, exiting : {}".format(e))
|
||||
context.log.fail("Error while polling export files, exiting : {}".format(e))
|
||||
|
||||
def clean(self, context, connection):
|
||||
"""Checks for database export + malicious trigger on the remote host, removes everything"""
|
||||
|
@ -340,12 +340,12 @@ class CMEModule:
|
|||
try:
|
||||
self.put_file_execute_delete(context, connection, self.remove_trigger_script_str)
|
||||
except Exception as e:
|
||||
context.log.error(f"Error while deleting trigger, exiting: {e}")
|
||||
context.log.fail(f"Error while deleting trigger, exiting: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
# check if the specified KeePass configuration file does not contain the malicious trigger anymore
|
||||
if self.trigger_added(context, connection):
|
||||
context.log.error(f"Unknown error while removing trigger '{self.trigger_name}', exiting")
|
||||
context.log.fail(f"Unknown error while removing trigger '{self.trigger_name}', exiting")
|
||||
else:
|
||||
context.log.display(f"Found trigger '{self.trigger_name}' in configuration file, removing")
|
||||
else:
|
||||
|
@ -370,20 +370,20 @@ class CMEModule:
|
|||
"""check if the trigger is added to the config file XML tree (returns True/False)"""
|
||||
# check if the specified KeePass configuration file exists
|
||||
if not self.keepass_config_path:
|
||||
context.log.error("No KeePass configuration file specified, exiting")
|
||||
context.log.fail("No KeePass configuration file specified, exiting")
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
buffer = BytesIO()
|
||||
connection.conn.getFile(self.share, self.keepass_config_path.split(":")[1], buffer.write)
|
||||
except Exception as e:
|
||||
context.log.error(f"Error while getting file '{self.keepass_config_path}', exiting: {e}")
|
||||
context.log.fail(f"Error while getting file '{self.keepass_config_path}', exiting: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
keepass_config_xml_root = ElementTree.fromstring(buffer.getvalue())
|
||||
except Exception as e:
|
||||
context.log.error(f"Error while parsing file '{self.keepass_config_path}', exiting: {e}")
|
||||
context.log.fail(f"Error while parsing file '{self.keepass_config_path}', exiting: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
# check if the specified KeePass configuration file does not already contain the malicious trigger
|
||||
|
|
|
@ -45,7 +45,7 @@ class CMEModule:
|
|||
sAMAccountName = ''
|
||||
values = {str(attr['type']).lower(): str(attr['vals'][0]) for attr in computer['attributes']}
|
||||
if "mslaps-encryptedpassword" in values:
|
||||
context.log.error("LAPS password is encrypted and currently CrackMapExec doesn't support the decryption...")
|
||||
context.log.fail("LAPS password is encrypted and currently CrackMapExec doesn't support the decryption...")
|
||||
return
|
||||
elif "mslaps-password" in values:
|
||||
r = json.loads(values['mslaps-password'])
|
||||
|
@ -53,9 +53,9 @@ class CMEModule:
|
|||
elif "ms-mcs-admpwd" in values:
|
||||
laps_computers.append((values['samaccountname'], '', values['ms-mcs-admpwd']))
|
||||
else:
|
||||
context.log.error("No result found with attribute ms-MCS-AdmPwd or msLAPS-Password")
|
||||
context.log.fail("No result found with attribute ms-MCS-AdmPwd or msLAPS-Password")
|
||||
laps_computers = sorted(laps_computers, key=lambda x: x[0])
|
||||
for sAMAccountName, user, msMCSAdmPwd in laps_computers:
|
||||
context.log.highlight("Computer: {:<20} User: {:<15} Password: {}".format(sAMAccountName, user, msMCSAdmPwd))
|
||||
else:
|
||||
context.log.error("No result found with attribute ms-MCS-AdmPwd or msLAPS-Password !")
|
||||
context.log.fail("No result found with attribute ms-MCS-AdmPwd or msLAPS-Password !")
|
||||
|
|
|
@ -60,14 +60,14 @@ class CMEModule:
|
|||
elif "data 52e" in str(ldapConn.result):
|
||||
return False #channel binding not enforced
|
||||
else:
|
||||
context.log.error("UNEXPECTED ERROR: " + str(ldapConn.result))
|
||||
context.log.fail("UNEXPECTED ERROR: " + str(ldapConn.result))
|
||||
else:
|
||||
#LDAPS bind successful
|
||||
return False #because channel binding is not enforced
|
||||
exit()
|
||||
except Exception as e:
|
||||
context.log.error("\n [!] "+ dcTarget+" -", str(e))
|
||||
context.log.error(" * Ensure DNS is resolving properly, and that you can reach LDAPS on this host")
|
||||
context.log.fail("\n [!] "+ dcTarget+" -", str(e))
|
||||
context.log.fail(" * Ensure DNS is resolving properly, and that you can reach LDAPS on this host")
|
||||
|
||||
#Conduct a bind to LDAPS with channel binding supported
|
||||
#but intentionally miscalculated. In the case that and
|
||||
|
@ -83,7 +83,7 @@ class CMEModule:
|
|||
ldapsClientConn = MSLDAPClientConnection(target, credential)
|
||||
_, err = await ldapsClientConn.connect()
|
||||
if err is not None:
|
||||
context.log.error("ERROR while connecting to " + dcTarget + ": " + err)
|
||||
context.log.fail("ERROR while connecting to " + dcTarget + ": " + err)
|
||||
#forcing a miscalculation of the "Channel Bindings" av pair in Type 3 NTLM message
|
||||
ldapsClientConn.cb_data = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||
_, err = await ldapsClientConn.bind()
|
||||
|
@ -92,7 +92,7 @@ class CMEModule:
|
|||
elif "data 52e" in str(err):
|
||||
return False
|
||||
elif err is not None:
|
||||
context.log.error("ERROR while connecting to " + dcTarget + ": " + err)
|
||||
context.log.fail("ERROR while connecting to " + dcTarget + ": " + err)
|
||||
elif err is None:
|
||||
return False
|
||||
|
||||
|
@ -122,7 +122,7 @@ class CMEModule:
|
|||
ssl_sock.close()
|
||||
return False
|
||||
else:
|
||||
context.log.error("Unexpected error during LDAPS handshake: " + str(e))
|
||||
context.log.fail("Unexpected error during LDAPS handshake: " + str(e))
|
||||
ssl_sock.close()
|
||||
return False
|
||||
|
||||
|
@ -155,7 +155,7 @@ class CMEModule:
|
|||
if ldapIsProtected == False:
|
||||
context.log.highlight("LDAP Signing NOT Enforced!")
|
||||
elif ldapIsProtected == True:
|
||||
context.log.error("LDAP Signing IS Enforced")
|
||||
context.log.fail("LDAP Signing IS Enforced")
|
||||
if DoesLdapsCompleteHandshake(dcTarget) == True:
|
||||
ldapsChannelBindingAlwaysCheck = run_ldaps_noEPA(inputUser, inputPassword, dcTarget)
|
||||
ldapsChannelBindingWhenSupportedCheck = asyncio.run(run_ldaps_withEPA(inputUser, inputPassword, dcTarget))
|
||||
|
@ -164,9 +164,9 @@ class CMEModule:
|
|||
elif ldapsChannelBindingAlwaysCheck == False and ldapsChannelBindingWhenSupportedCheck == False:
|
||||
context.log.highlight('LDAPS Channel Binding is set to \"NEVER\"')
|
||||
elif ldapsChannelBindingAlwaysCheck == True:
|
||||
context.log.error('LDAPS Channel Binding is set to \"Required\"')
|
||||
context.log.fail('LDAPS Channel Binding is set to \"Required\"')
|
||||
else:
|
||||
context.log.error("\nSomething went wrong...")
|
||||
context.log.fail("\nSomething went wrong...")
|
||||
exit()
|
||||
else:
|
||||
context.log.error(dcTarget + " - cannot complete TLS handshake, cert likely not configured")
|
||||
context.log.fail(dcTarget + " - cannot complete TLS handshake, cert likely not configured")
|
||||
|
|
|
@ -40,7 +40,7 @@ class CMEModule:
|
|||
|
||||
def on_admin_login(self, context, connection):
|
||||
if not self.ca:
|
||||
context.log.error(
|
||||
context.log.fail(
|
||||
"Please provide a valid CA server and CA name (CA_SERVER\CA_NAME)"
|
||||
)
|
||||
return False
|
||||
|
@ -96,7 +96,7 @@ class CMEModule:
|
|||
if pwned_users:
|
||||
context.log.success(f"{pwned_users} NT hash(es) successfully collected")
|
||||
else:
|
||||
context.log.error(
|
||||
context.log.fail(
|
||||
"Unable to collect NT hash(es) from the hijacked session(s)"
|
||||
)
|
||||
return True
|
||||
|
@ -116,12 +116,12 @@ class CMEModule:
|
|||
ret = True
|
||||
|
||||
if tracker.last_error_msg:
|
||||
context.log.error(tracker.last_error_msg)
|
||||
context.log.fail(tracker.last_error_msg)
|
||||
ret = False
|
||||
|
||||
if not tracker.files_cleaning_success:
|
||||
context.log.error("Fail to clean files related to Masky")
|
||||
context.log.error(
|
||||
context.log.fail("Fail to clean files related to Masky")
|
||||
context.log.fail(
|
||||
(
|
||||
f"Please remove the files named '{tracker.agent_filename}', '{tracker.error_filename}', "
|
||||
f"'{tracker.output_filename}' & '{tracker.args_filename}' within the folder '\\Windows\\Temp\\'"
|
||||
|
@ -130,7 +130,7 @@ class CMEModule:
|
|||
ret = False
|
||||
|
||||
if not tracker.svc_cleaning_success:
|
||||
context.log.error(
|
||||
context.log.fail(
|
||||
f"Fail to remove the service named '{tracker.svc_name}', please remove it manually"
|
||||
)
|
||||
ret = False
|
||||
|
|
|
@ -44,7 +44,7 @@ class CMEModule:
|
|||
self.met_ssl = 'https'
|
||||
|
||||
if 'SRVHOST' not in module_options or 'SRVPORT' not in module_options:
|
||||
context.log.error('SRVHOST and SRVPORT options are required!')
|
||||
context.log.fail('SRVHOST and SRVPORT options are required!')
|
||||
exit(1)
|
||||
|
||||
if 'SSL' in module_options:
|
||||
|
|
|
@ -54,7 +54,7 @@ class CMEModule:
|
|||
|
||||
if self.action == "rollback":
|
||||
if not self.current_user.is_sysadmin:
|
||||
context.log.error(
|
||||
context.log.fail(
|
||||
f"{self.current_username} is not sysadmin"
|
||||
)
|
||||
return
|
||||
|
@ -81,7 +81,7 @@ class CMEModule:
|
|||
)
|
||||
if self.action == "privesc":
|
||||
if not target_user:
|
||||
context.log.error("can't find any path to privesc")
|
||||
context.log.fail("can't find any path to privesc")
|
||||
else:
|
||||
exec_as = self.build_exec_as_from_path(target_user)
|
||||
# privesc via impersonation privilege
|
||||
|
|
|
@ -87,7 +87,7 @@ class CMEModule:
|
|||
elif context.protocol == 'mssql':
|
||||
nano.write(self.nano_embedded64)
|
||||
else:
|
||||
context.log.error('Unsupported Windows architecture')
|
||||
context.log.fail('Unsupported Windows architecture')
|
||||
sys.exit(1)
|
||||
|
||||
if context.protocol == 'smb':
|
||||
|
@ -96,7 +96,7 @@ class CMEModule:
|
|||
connection.conn.putFile(self.share, self.tmp_share + self.nano, nano.read)
|
||||
context.log.success(f"Created file {self.nano} on the \\\\{self.share}{self.tmp_share}")
|
||||
except Exception as e:
|
||||
context.log.error(f"Error writing file to share {self.share}: {e}")
|
||||
context.log.fail(f"Error writing file to share {self.share}: {e}")
|
||||
else:
|
||||
with open(self.nano_path + self.nano, 'rb') as nano:
|
||||
try:
|
||||
|
@ -106,10 +106,10 @@ class CMEModule:
|
|||
if exec_method.file_exists(self.tmp_dir + self.nano):
|
||||
context.log.success(f"Created file {self.nano} on the remote machine {self.tmp_dir}")
|
||||
else:
|
||||
context.log.error("File does not exist on the remote system... error during upload")
|
||||
context.log.fail("File does not exist on the remote system... error during upload")
|
||||
sys.exit(1)
|
||||
except Exception as e:
|
||||
context.log.error(f"Error writing file to remote machine directory {self.tmp_dir}: {e}")
|
||||
context.log.fail(f"Error writing file to remote machine directory {self.tmp_dir}: {e}")
|
||||
|
||||
# get pid lsass
|
||||
command = 'tasklist /v /fo csv | findstr /i "lsass"'
|
||||
|
@ -127,7 +127,7 @@ class CMEModule:
|
|||
context.log.success('Process lsass.exe was successfully dumped')
|
||||
dump = True
|
||||
else:
|
||||
context.log.error('Process lsass.exe error on dump, try with verbose')
|
||||
context.log.fail('Process lsass.exe error on dump, try with verbose')
|
||||
|
||||
if dump:
|
||||
context.log.display(f"Copying {nano_log_name} to host")
|
||||
|
@ -138,38 +138,38 @@ class CMEModule:
|
|||
connection.conn.getFile(self.share, self.tmp_share + nano_log_name, dump_file.write)
|
||||
context.log.success(f"Dumpfile of lsass.exe was transferred to {filename}")
|
||||
except Exception as e:
|
||||
context.log.error(f"Error while getting file: {e}")
|
||||
context.log.fail(f"Error while getting file: {e}")
|
||||
|
||||
try:
|
||||
connection.conn.deleteFile(self.share, self.tmp_share + self.nano)
|
||||
context.log.success(f"Deleted nano file on the {self.share} share")
|
||||
except Exception as e:
|
||||
context.log.error(f"Error deleting nano file on share {self.share}: {e}")
|
||||
context.log.fail(f"Error deleting nano file on share {self.share}: {e}")
|
||||
|
||||
try:
|
||||
connection.conn.deleteFile(self.share, self.tmp_share + nano_log_name)
|
||||
context.log.success(f"Deleted lsass.dmp file on the {self.share} share")
|
||||
except Exception as e:
|
||||
context.log.error(f"Error deleting lsass.dmp file on share {self.share}: {e}")
|
||||
context.log.fail(f"Error deleting lsass.dmp file on share {self.share}: {e}")
|
||||
else:
|
||||
try:
|
||||
exec_method = MSSQLEXEC(connection.conn)
|
||||
exec_method.get_file(self.tmp_dir + nano_log_name, filename)
|
||||
context.log.success(f"Dumpfile of lsass.exe was transferred to {filename}")
|
||||
except Exception as e:
|
||||
context.log.error(f"Error while getting file: {e}")
|
||||
context.log.fail(f"Error while getting file: {e}")
|
||||
|
||||
try:
|
||||
connection.execute(f"del {self.tmp_dir + self.nano}")
|
||||
context.log.success(f"Deleted nano file on the {self.share} dir")
|
||||
except Exception as e:
|
||||
context.log.error(f"Error deleting nano file on dir {self.tmp_dir}: {e}")
|
||||
context.log.fail(f"Error deleting nano file on dir {self.tmp_dir}: {e}")
|
||||
|
||||
try:
|
||||
connection.execute(f"del {self.tmp_dir + nano_log_name}")
|
||||
context.log.success(f"Deleted lsass.dmp file on the {self.tmp_dir} dir")
|
||||
except Exception as e:
|
||||
context.log.error(f"Error deleting lsass.dmp file on dir {self.tmp_dir}: {e}")
|
||||
context.log.fail(f"Error deleting lsass.dmp file on dir {self.tmp_dir}: {e}")
|
||||
|
||||
fh = open(filename, "r+b")
|
||||
fh.seek(0)
|
||||
|
@ -187,7 +187,7 @@ class CMEModule:
|
|||
pypy_parse = pypykatz.parse_minidump_external(dump)
|
||||
except Exception as e:
|
||||
pypy_parse = None
|
||||
context.log.error(f'Error parsing minidump: {e}')
|
||||
context.log.fail(f'Error parsing minidump: {e}')
|
||||
|
||||
ssps = [
|
||||
'msv_creds',
|
||||
|
@ -230,4 +230,4 @@ class CMEModule:
|
|||
if len(bh_creds) > 0:
|
||||
add_user_bh(bh_creds, None, context.log, connection.config)
|
||||
except Exception as e:
|
||||
context.log.error(f"Error opening dump file: {e}")
|
||||
context.log.fail(f"Error opening dump file: {e}")
|
||||
|
|
|
@ -48,7 +48,7 @@ class CMEModule:
|
|||
if 'success' in p:
|
||||
context.log.success("NTDS.dit dumped to %s%s" % (self.tmp_dir, self.dump_location))
|
||||
else:
|
||||
context.log.error("Error while dumping NTDS")
|
||||
context.log.fail("Error while dumping NTDS")
|
||||
return
|
||||
|
||||
os.makedirs(self.dir_result, exist_ok=True)
|
||||
|
@ -62,7 +62,7 @@ class CMEModule:
|
|||
connection.conn.getFile(self.share, self.tmp_share + self.dump_location + "\\" + 'Active Directory\\ntds.dit', dump_file.write)
|
||||
context.log.debug('Copied ntds.dit file')
|
||||
except Exception as e:
|
||||
context.log.error('Error while get ntds.dit file: {}'.format(e))
|
||||
context.log.fail('Error while get ntds.dit file: {}'.format(e))
|
||||
|
||||
context.log.debug('Copy SYSTEM to host')
|
||||
with open(os.path.join(self.dir_result,'registry','SYSTEM'), 'wb+') as dump_file:
|
||||
|
@ -70,7 +70,7 @@ class CMEModule:
|
|||
connection.conn.getFile(self.share, self.tmp_share + self.dump_location + "\\" + 'registry\\SYSTEM', dump_file.write)
|
||||
context.log.debug('Copied SYSTEM file')
|
||||
except Exception as e:
|
||||
context.log.error('Error while get SYSTEM file: {}'.format(e))
|
||||
context.log.fail('Error while get SYSTEM file: {}'.format(e))
|
||||
|
||||
context.log.debug('Copy SECURITY to host')
|
||||
with open(os.path.join(self.dir_result,'registry','SECURITY'), 'wb+') as dump_file:
|
||||
|
@ -78,14 +78,14 @@ class CMEModule:
|
|||
connection.conn.getFile(self.share, self.tmp_share + self.dump_location + "\\" + 'registry\\SECURITY', dump_file.write)
|
||||
context.log.debug('Copied SECURITY file')
|
||||
except Exception as e:
|
||||
context.log.error('Error while get SECURITY file: {}'.format(e))
|
||||
context.log.fail('Error while get SECURITY file: {}'.format(e))
|
||||
context.log.display("NTDS dump copied to %s" % self.dir_result)
|
||||
try:
|
||||
command = "rmdir /s /q %s%s" % (self.tmp_dir, self.dump_location)
|
||||
p = connection.execute(command, True)
|
||||
context.log.success('Deleted %s%s remote dump directory' % (self.tmp_dir, self.dump_location))
|
||||
except Exception as e:
|
||||
context.log.error('Error deleting {} remote directory on share {}: {}'.format(self.dump_location, self.share, e))
|
||||
context.log.fail('Error deleting {} remote directory on share {}: {}'.format(self.dump_location, self.share, e))
|
||||
|
||||
localOperations = LocalOperations("%s/registry/SYSTEM" % self.dir_result)
|
||||
bootKey = localOperations.getBootKey()
|
||||
|
@ -137,7 +137,7 @@ class CMEModule:
|
|||
context.log.display("To extract only enabled accounts from the output file, run the following command: ")
|
||||
context.log.display("grep -iv disabled {} | cut -d ':' -f1".format(connection.output_filename + '.ntds'))
|
||||
except Exception as e:
|
||||
context.log.error(e)
|
||||
context.log.fail(e)
|
||||
|
||||
NTDS.finish()
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ class CMEModule:
|
|||
connection.conn.putFile(self.share, self.tmp_share + self.procdump, procdump.read)
|
||||
context.log.success('Created file {} on the \\\\{}{}'.format(self.procdump, self.share, self.tmp_share))
|
||||
except Exception as e:
|
||||
context.log.error('Error writing file to share {}: {}'.format(share, e))
|
||||
context.log.fail('Error writing file to share {}: {}'.format(share, e))
|
||||
|
||||
# get pid lsass
|
||||
command = 'tasklist /v /fo csv | findstr /i "lsass"'
|
||||
|
@ -77,7 +77,7 @@ class CMEModule:
|
|||
context.log.success('Process lsass.exe was successfully dumped')
|
||||
dump = True
|
||||
else:
|
||||
context.log.error('Process lsass.exe error un dump, try with verbose')
|
||||
context.log.fail('Process lsass.exe error un dump, try with verbose')
|
||||
|
||||
if dump:
|
||||
regex = r"([A-Za-z0-9-]*.dmp)"
|
||||
|
@ -96,19 +96,19 @@ class CMEModule:
|
|||
connection.conn.getFile(self.share, self.tmp_share + machine_name, dump_file.write)
|
||||
context.log.success('Dumpfile of lsass.exe was transferred to {}'.format(self.dir_result + machine_name))
|
||||
except Exception as e:
|
||||
context.log.error('Error while get file: {}'.format(e))
|
||||
context.log.fail('Error while get file: {}'.format(e))
|
||||
|
||||
try:
|
||||
connection.conn.deleteFile(self.share, self.tmp_share + self.procdump)
|
||||
context.log.success('Deleted procdump file on the {} share'.format(self.share))
|
||||
except Exception as e:
|
||||
context.log.error('Error deleting procdump file on share {}: {}'.format(self.share, e))
|
||||
context.log.fail('Error deleting procdump file on share {}: {}'.format(self.share, e))
|
||||
|
||||
try:
|
||||
connection.conn.deleteFile(self.share, self.tmp_share + machine_name)
|
||||
context.log.success('Deleted lsass.dmp file on the {} share'.format(self.share))
|
||||
except Exception as e:
|
||||
context.log.error('Error deleting lsass.dmp file on share {}: {}'.format(self.share, e))
|
||||
context.log.fail('Error deleting lsass.dmp file on share {}: {}'.format(self.share, e))
|
||||
|
||||
with open(self.dir_result + machine_name, 'rb') as dump:
|
||||
try:
|
||||
|
@ -118,7 +118,7 @@ class CMEModule:
|
|||
pypy_parse = pypykatz.parse_minidump_external(dump)
|
||||
except Exception as e:
|
||||
pypy_parse = None
|
||||
context.log.error(f'Error parsing minidump: {e}')
|
||||
context.log.fail(f'Error parsing minidump: {e}')
|
||||
|
||||
ssps = ['msv_creds', 'wdigest_creds', 'ssp_creds', 'livessp_creds', 'kerberos_creds', 'credman_creds',
|
||||
'tspkg_creds']
|
||||
|
@ -141,4 +141,4 @@ class CMEModule:
|
|||
if len(credz_bh) > 0:
|
||||
add_user_bh(credz_bh, None, context.log, connection.config)
|
||||
except Exception as e:
|
||||
context.log.error('Error openning dump file', str(e))
|
||||
context.log.fail('Error openning dump file', str(e))
|
||||
|
|
|
@ -107,7 +107,7 @@ class CMEModule:
|
|||
context.log.debug("Could not get masterkeys: {}".format(e))
|
||||
|
||||
if len(self.masterkeys) == 0:
|
||||
context.log.error("No masterkeys looted")
|
||||
context.log.fail("No masterkeys looted")
|
||||
return
|
||||
|
||||
context.log.success("Got {} decrypted masterkeys. Looting RDCMan secrets".format(highlight(len(self.masterkeys))))
|
||||
|
|
|
@ -24,11 +24,11 @@ class CMEModule:
|
|||
ACTION Enable/Disable RDP (choices: enable, disable)
|
||||
"""
|
||||
if not 'ACTION' in module_options:
|
||||
context.log.error('ACTION option not specified!')
|
||||
context.log.fail('ACTION option not specified!')
|
||||
exit(1)
|
||||
|
||||
if module_options['ACTION'].lower() not in ['enable', 'disable']:
|
||||
context.log.error('Invalid value for ACTION option!')
|
||||
context.log.fail('Invalid value for ACTION option!')
|
||||
exit(1)
|
||||
|
||||
self.action = module_options['ACTION'].lower()
|
||||
|
|
|
@ -64,12 +64,12 @@ class CMEModule:
|
|||
try :
|
||||
self.value = int(self.value)
|
||||
except:
|
||||
context.log.error(f"Invalid registry value type specified: {self.value}")
|
||||
context.log.fail(f"Invalid registry value type specified: {self.value}")
|
||||
return
|
||||
if self.type in type_dict:
|
||||
self.type = type_dict[self.type]
|
||||
else:
|
||||
context.log.error(f"Invalid registry value type specified: {self.type}")
|
||||
context.log.fail(f"Invalid registry value type specified: {self.type}")
|
||||
return
|
||||
else:
|
||||
self.type = 1
|
||||
|
@ -80,10 +80,10 @@ class CMEModule:
|
|||
def on_admin_login(self, context, connection):
|
||||
self.context = context
|
||||
if not self.path:
|
||||
self.context.log.error("Please provide the path of the registry to query")
|
||||
self.context.log.fail("Please provide the path of the registry to query")
|
||||
return
|
||||
if not self.key:
|
||||
self.context.log.error("Please provide the registry key to query")
|
||||
self.context.log.fail("Please provide the registry key to query")
|
||||
return
|
||||
|
||||
remote_ops = RemoteOperations(connection.conn, False)
|
||||
|
@ -100,7 +100,7 @@ class CMEModule:
|
|||
self.path = self.path.replace('HKCR\\', '')
|
||||
ans = rrp.hOpenClassesRoot(remote_ops._RemoteOperations__rrp)
|
||||
else:
|
||||
self.context.log.error(f"Unsupported registry hive specified in path: {self.path}")
|
||||
self.context.log.fail(f"Unsupported registry hive specified in path: {self.path}")
|
||||
return
|
||||
|
||||
reg_handle = ans['phKey']
|
||||
|
@ -121,7 +121,7 @@ class CMEModule:
|
|||
self.key
|
||||
)
|
||||
except:
|
||||
self.context.log.error(f"Registry key {self.key} does not exist")
|
||||
self.context.log.fail(f"Registry key {self.key} does not exist")
|
||||
return
|
||||
# Delete value
|
||||
rrp.hBaseRegDeleteValue(
|
||||
|
@ -180,12 +180,12 @@ class CMEModule:
|
|||
if self.delete:
|
||||
pass
|
||||
else:
|
||||
self.context.log.error(f"Registry key {self.key} does not exist")
|
||||
self.context.log.fail(f"Registry key {self.key} does not exist")
|
||||
return
|
||||
rrp.hBaseRegCloseKey(remote_ops._RemoteOperations__rrp, key_handle)
|
||||
except DCERPCException as e:
|
||||
self.context.log.error(f"DCERPC Error while querying or modifying registry: {e}")
|
||||
self.context.log.fail(f"DCERPC Error while querying or modifying registry: {e}")
|
||||
except Exception as e:
|
||||
self.context.log.error(f"Error while querying or modifying registry: {e}")
|
||||
self.context.log.fail(f"Error while querying or modifying registry: {e}")
|
||||
finally:
|
||||
remote_ops.finish()
|
||||
|
|
|
@ -38,11 +38,11 @@ class CMEModule:
|
|||
self.cleanup = bool(module_options['CLEANUP'])
|
||||
|
||||
if 'NAME' not in module_options:
|
||||
context.log.error('NAME option is required!')
|
||||
context.log.fail('NAME option is required!')
|
||||
exit(1)
|
||||
|
||||
if not self.cleanup and 'SERVER' not in module_options:
|
||||
context.log.error('SERVER option is required!')
|
||||
context.log.fail('SERVER option is required!')
|
||||
exit(1)
|
||||
|
||||
self.scf_name = module_options['NAME']
|
||||
|
@ -68,10 +68,10 @@ class CMEModule:
|
|||
connection.conn.putFile(share['name'], self.file_path, scf.read)
|
||||
context.log.success(f"Created SCF file on the {share['name']} share")
|
||||
except Exception as e:
|
||||
context.log.error(f"Error writing SCF file to share {share['name']}: {e}")
|
||||
context.log.fail(f"Error writing SCF file to share {share['name']}: {e}")
|
||||
else:
|
||||
try:
|
||||
connection.conn.deleteFile(share['name'], self.file_path)
|
||||
context.log.success(f"Deleted SCF file on the {share['name']} share")
|
||||
except Exception as e:
|
||||
context.log.error(f"Error deleting SCF file on share {share['name']}: {e}")
|
||||
context.log.fail(f"Error deleting SCF file on share {share['name']}: {e}")
|
||||
|
|
|
@ -39,11 +39,11 @@ class CMEModule:
|
|||
self.cleanup = bool(module_options['CLEANUP'])
|
||||
|
||||
if 'NAME' not in module_options:
|
||||
context.log.error('NAME option is required!')
|
||||
context.log.fail('NAME option is required!')
|
||||
exit(1)
|
||||
|
||||
if not self.cleanup and 'SERVER' not in module_options:
|
||||
context.log.error('SERVER option is required!')
|
||||
context.log.fail('SERVER option is required!')
|
||||
exit(1)
|
||||
|
||||
self.lnk_name = module_options['NAME']
|
||||
|
@ -67,11 +67,11 @@ class CMEModule:
|
|||
connection.conn.putFile(share['name'], self.file_path, lnk.read)
|
||||
context.log.success(f"Created LNK file on the {share['name']} share")
|
||||
except Exception as e:
|
||||
context.log.error(f"Error writing LNK file to share {share['name']}: {e}")
|
||||
context.log.fail(f"Error writing LNK file to share {share['name']}: {e}")
|
||||
else:
|
||||
try:
|
||||
connection.conn.deleteFile(share['name'], self.file_path)
|
||||
context.log.success(f"Deleted LNK file on the {share['name']} share")
|
||||
except Exception as e:
|
||||
context.log.error(f"Error deleting LNK file on share {share['name']}: {e}")
|
||||
context.log.fail(f"Error deleting LNK file on share {share['name']}: {e}")
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ class CMEModule:
|
|||
if 'STATUS_SHARING_VIOLATION' in str(e):
|
||||
context.log.debug(str(e))
|
||||
context.log.highlight("Found Cookie file in path " + path)
|
||||
context.log.error('Cannot retrieve file, most likely Teams is running which prevents us from retrieving the Cookies database')
|
||||
context.log.fail('Cannot retrieve file, most likely Teams is running which prevents us from retrieving the Cookies database')
|
||||
if found == 0:
|
||||
context.log.display('No cookie file found in Users folder')
|
||||
|
||||
|
@ -48,10 +48,10 @@ class CMEModule:
|
|||
c.execute("SELECT value FROM cookies WHERE name = '" + name + "'")
|
||||
row = c.fetchone()
|
||||
if row is None:
|
||||
context.log.error("No " + name + " present in Microsoft Teams Cookies database")
|
||||
context.log.fail("No " + name + " present in Microsoft Teams Cookies database")
|
||||
else:
|
||||
context.log.success("Succesfully extracted " + name + ": ")
|
||||
context.log.success(row[0])
|
||||
conn.close()
|
||||
except Exception as e:
|
||||
context.log.error(str(e))
|
||||
context.log.fail(str(e))
|
||||
|
|
|
@ -22,7 +22,7 @@ class CMEModule:
|
|||
self.host = None
|
||||
|
||||
if 'HOST' not in module_options:
|
||||
context.log.error('HOST option is required!')
|
||||
context.log.fail('HOST option is required!')
|
||||
exit(1)
|
||||
|
||||
self.host = module_options['HOST']
|
||||
|
@ -37,4 +37,4 @@ class CMEModule:
|
|||
if bool(output) is True:
|
||||
context.log.success('Pinged successfully')
|
||||
elif bool(output) is False:
|
||||
context.log.error('Host unreachable')
|
||||
context.log.fail('Host unreachable')
|
||||
|
|
|
@ -86,7 +86,7 @@ class CMEModule:
|
|||
perRecordCallback=self.process_record
|
||||
)
|
||||
except LDAPSearchError as e:
|
||||
context.log.error(f"Obtained unexpected exception: {str(e)}")
|
||||
context.log.fail(f"Obtained unexpected exception: {str(e)}")
|
||||
finally:
|
||||
self.delete_log_file()
|
||||
|
||||
|
|
|
@ -53,9 +53,9 @@ class CMEModule:
|
|||
|
||||
except DCERPCException as e:
|
||||
if str(e).find('ERROR_FILE_NOT_FOUND'):
|
||||
context.log.error("No Veeam installation found")
|
||||
context.log.fail("No Veeam installation found")
|
||||
except:
|
||||
context.log.error("UNEXPECTED ERROR:")
|
||||
context.log.fail("UNEXPECTED ERROR:")
|
||||
traceback.print_exc()
|
||||
finally:
|
||||
remoteOps.finish()
|
||||
|
@ -80,7 +80,7 @@ class CMEModule:
|
|||
|
||||
# Error handling
|
||||
if "Can't connect to DB! Exiting..." in output_stripped or "No passwords found!" in output_stripped:
|
||||
context.log.error(output_stripped[0])
|
||||
context.log.fail(output_stripped[0])
|
||||
return
|
||||
|
||||
for account in output_stripped:
|
||||
|
|
|
@ -20,11 +20,11 @@ class CMEModule:
|
|||
"""
|
||||
|
||||
if not 'ACTION' in module_options:
|
||||
context.log.error('ACTION option not specified!')
|
||||
context.log.fail('ACTION option not specified!')
|
||||
exit(1)
|
||||
|
||||
if module_options['ACTION'].lower() not in ['enable', 'disable']:
|
||||
context.log.error('Invalid value for ACTION option!')
|
||||
context.log.fail('Invalid value for ACTION option!')
|
||||
exit(1)
|
||||
|
||||
self.action = module_options['ACTION'].lower()
|
||||
|
|
|
@ -24,7 +24,7 @@ class CMEModule:
|
|||
"""
|
||||
|
||||
if not 'URL' in module_options:
|
||||
context.log.error('URL option is required!')
|
||||
context.log.fail('URL option is required!')
|
||||
exit(1)
|
||||
|
||||
self.url = module_options['URL']
|
||||
|
@ -32,7 +32,7 @@ class CMEModule:
|
|||
self.payload = "64"
|
||||
if 'PAYLOAD' in module_options:
|
||||
if module_options['PAYLOAD'] not in ['64', '32']:
|
||||
context.log.error('Invalid value for PAYLOAD option!')
|
||||
context.log.fail('Invalid value for PAYLOAD option!')
|
||||
exit(1)
|
||||
self.payload = module_options['PAYLOAD']
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ class CMEModule:
|
|||
# ==================== Helper ====================
|
||||
def printCreds(self, context, session):
|
||||
if type(session) is str:
|
||||
context.log.error(session)
|
||||
context.log.fail(session)
|
||||
else:
|
||||
context.log.highlight("======={s}=======".format(s=session[0]))
|
||||
context.log.highlight("HostName: {s}".format(s=session[1]))
|
||||
|
@ -189,7 +189,7 @@ class CMEModule:
|
|||
regex = re.compile(r'^.*_Classes$')
|
||||
userObjects = [i for i in userNames if not regex.match(i)]
|
||||
except:
|
||||
context.log.error("Error handling Users in registry")
|
||||
context.log.fail("Error handling Users in registry")
|
||||
traceback.print_exc()
|
||||
finally:
|
||||
remoteOps.finish()
|
||||
|
@ -220,7 +220,7 @@ class CMEModule:
|
|||
userObjects.append(rrp.hBaseRegEnumKey(remoteOps._RemoteOperations__rrp, keyHandle, i)['lpNameOut'].split('\x00')[:-1][0])
|
||||
rrp.hBaseRegCloseKey(remoteOps._RemoteOperations__rrp, keyHandle)
|
||||
except:
|
||||
context.log.error("Error handling Users in registry")
|
||||
context.log.fail("Error handling Users in registry")
|
||||
traceback.print_exc()
|
||||
finally:
|
||||
remoteOps.finish()
|
||||
|
@ -335,7 +335,7 @@ class CMEModule:
|
|||
sessionNames.remove('Default%20Settings')
|
||||
|
||||
if self.checkMasterpasswordSet(connection, userObject):
|
||||
context.log.error("MasterPassword set! Aborting extraction...")
|
||||
context.log.fail("MasterPassword set! Aborting extraction...")
|
||||
continue
|
||||
# Extract stored Session infos
|
||||
for sessionName in sessionNames:
|
||||
|
@ -344,15 +344,15 @@ class CMEModule:
|
|||
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.error("Unexpected error:")
|
||||
context.log.fail("Unexpected error:")
|
||||
traceback.print_exc()
|
||||
self.unloadMissingUsers(context, connection, unloadedUserObjects)
|
||||
except DCERPCException as e:
|
||||
# Error during registry query
|
||||
if str(e).find('rpc_s_access_denied'):
|
||||
context.log.error("Error: rpc_s_access_denied. Seems like you don't have enough privileges to read the registry.")
|
||||
context.log.fail("Error: rpc_s_access_denied. Seems like you don't have enough privileges to read the registry.")
|
||||
except:
|
||||
context.log.error("UNEXPECTED ERROR:")
|
||||
context.log.fail("UNEXPECTED ERROR:")
|
||||
traceback.print_exc()
|
||||
finally:
|
||||
remoteOps.finish()
|
||||
|
@ -364,7 +364,7 @@ class CMEModule:
|
|||
|
||||
# Stop extracting creds if Master Password is set
|
||||
if (int(config.get('Configuration\\Security', 'UseMasterPassword')) == 1):
|
||||
context.log.error("Master Password Set, unable to recover saved passwords!")
|
||||
context.log.fail("Master Password Set, unable to recover saved passwords!")
|
||||
return
|
||||
|
||||
for section in config.sections():
|
||||
|
@ -391,7 +391,7 @@ class CMEModule:
|
|||
context.log.success("Found config file! Extracting credentials...")
|
||||
self.decodeConfigFile(context, confFile)
|
||||
except:
|
||||
context.log.error("Error! No config file found at {}".format(self.filepath))
|
||||
context.log.fail("Error! No config file found at {}".format(self.filepath))
|
||||
traceback.print_exc()
|
||||
else:
|
||||
context.log.display("Looking for WinSCP creds in User documents and AppData...")
|
||||
|
|
|
@ -62,7 +62,7 @@ class CMEModule:
|
|||
context.log.debug("Could not get masterkeys: {}".format(e))
|
||||
|
||||
if len(masterkeys) == 0:
|
||||
context.log.error("No masterkeys looted")
|
||||
context.log.fail("No masterkeys looted")
|
||||
return
|
||||
|
||||
context.log.success("Got {} decrypted masterkeys. Looting Wifi interfaces".format(highlight(len(masterkeys))))
|
||||
|
|
|
@ -53,7 +53,7 @@ class CMEModule:
|
|||
else:
|
||||
self.context.log.debug('\nAttack failed. Target is probably patched.')
|
||||
except DCERPCException as e:
|
||||
self.context.log.error(f"Error while connecting to host: DCERPCException, "
|
||||
self.context.log.fail(f"Error while connecting to host: DCERPCException, "
|
||||
f"which means this is probably not a DC!")
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue