module switch to fail instead of error function

main
mpgn 2023-04-21 06:17:50 -04:00
parent d154627633
commit 7267aae73a
34 changed files with 149 additions and 149 deletions

View File

@ -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:

View File

@ -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()

View File

@ -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)

View File

@ -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))

View File

@ -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):

View File

@ -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:

View File

@ -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):

View File

@ -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))

View File

@ -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)

View File

@ -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}")

View File

@ -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 !!!')

View File

@ -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

View File

@ -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 !")

View File

@ -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")

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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}")

View File

@ -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()

View File

@ -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))

View File

@ -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))))

View File

@ -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()

View File

@ -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()

View File

@ -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}")

View File

@ -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}")

View File

@ -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))

View File

@ -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')

View File

@ -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()

View 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:

View File

@ -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()

View File

@ -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']

View File

@ -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...")

View File

@ -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))))

View File

@ -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!")