update lsassy module for logging and improved error handling/logging

main
Marshall Hallenbeck 2023-04-05 18:50:56 -04:00
parent a5b821d96f
commit 7acc00fe0d
2 changed files with 35 additions and 17 deletions

View File

@ -5,12 +5,13 @@
# Website:
# https://beta.hackndo.com [FR]
# https://en.hackndo.com [EN]
import logging
from lsassy.dumper import Dumper
from lsassy.parser import Parser
from lsassy.session import Session
from lsassy.impacketfile import ImpacketFile
from cme.helpers.bloodhound import add_user_bh
import logging
class CMEModule:
@ -34,12 +35,6 @@ class CMEModule:
self.method = module_options['METHOD']
def on_admin_login(self, context, connection):
# lsassy uses a custom "success" level, which requires initializing its logger or an error will be thrown
# lsassy also removes all other handlers and overwrites the formatter which is bad for us (we want ours)
# so what we do is define "success" as a logging level, then do nothing with the output
logging.addLevelName(25, 'SUCCESS')
setattr(logging, 'success', lambda message, *args: ())
host = connection.host
domain_name = connection.domain
username = connection.username
@ -80,16 +75,37 @@ class CMEModule:
credentials, tickets, masterkeys = parsed
file.close()
ImpacketFile.delete(session, file.get_file_path())
context.log.debug(f"Closed dumper file")
file_path = file.get_file_path()
context.log.debug(f"File path: {file_path}")
try:
deleted_file = ImpacketFile.delete(session, file_path)
if deleted_file:
context.log.debug(f"Deleted dumper file")
else:
context.log.fail(f"[OPSEC] No exception, but failed to delete file: {file_path}")
except Exception as e:
context.log.fail(f"[OPSEC] Error deleting temporary lsassy dumper file {file_path}: {e}")
if credentials is None:
credentials = []
for cred in credentials:
c = cred.get_object()
context.log.debug(f"Cred: {c}")
credentials = [cred.get_object() for cred in credentials if cred.ticket is None and cred.masterkey is None and not cred.get_username().endswith("$")]
credentials_unique = []
credentials_output = []
context.log.debug(f"Credentials: {credentials}")
for cred in credentials:
context.log.debug(f"Credential: {cred}")
if [cred["domain"], cred["username"], cred["password"], cred["lmhash"], cred["nthash"]] not in credentials_unique:
credentials_unique.append([cred["domain"], cred["username"], cred["password"], cred["lmhash"], cred["nthash"]])
credentials_output.append(cred)
context.log.debug(f"Calling process_credentials")
self.process_credentials(context, connection, credentials_output)
def process_credentials(self, context, connection, credentials):
@ -108,6 +124,7 @@ class CMEModule:
@staticmethod
def print_credentials(context, domain, username, password, lmhash, nthash):
context.log.debug(f"Inside print_credentials")
if password is None:
password = ':'.join(h for h in [lmhash, nthash] if h is not None)
output = "%s\\%s %s" % (domain, username, password)

View File

@ -2,6 +2,7 @@
# -*- coding: utf-8 -*-
import logging
import os
from io import StringIO
from cme.protocols.mssql.mssqlexec import MSSQLEXEC
from cme.connection import *
@ -158,7 +159,7 @@ class mssql(connection):
else:
return False
except Exception as e:
self.logger.error('Error calling check_if_admin(): {}'.format(e))
self.loggerfail('Error calling check_if_admin(): {}'.format(e))
return False
return True
@ -216,7 +217,7 @@ class mssql(connection):
if not self.args.continue_on_success:
return True
except Exception as e:
self.logger.error(u'{}\\{}{} {}'.format('{}\\'.format(domain) if not self.args.local_auth else '',
self.logger.fail(u'{}\\{}{} {}'.format('{}\\'.format(domain) if not self.args.local_auth else '',
username,
# Show what was used between cleartext, nthash, aesKey and ccache
" from ccache" if useCache
@ -258,9 +259,9 @@ class mssql(connection):
if not self.args.continue_on_success:
return True
except BrokenPipeError as e:
self.logger.error(f"Broken Pipe Error while attempting to login")
self.logger.fail(f"Broken Pipe Error while attempting to login")
except Exception as e:
self.logger.error(u'{}\\{}:{} {}'.format(
self.logger.fail(u'{}\\{}:{} {}'.format(
domain,
username,
password if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8,
@ -318,9 +319,9 @@ class mssql(connection):
if not self.args.continue_on_success:
return True
except BrokenPipeError as e:
self.logger.error(f"Broken Pipe Error while attempting to login")
self.logger.fail(f"Broken Pipe Error while attempting to login")
except Exception as e:
self.logger.error(u'{}\\{}:{} {}'.format(
self.logger.fail(u'{}\\{}:{} {}'.format(
domain,
username,
ntlm_hash if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8,
@ -384,9 +385,9 @@ class mssql(connection):
if exec_method.file_exists(self.args.put_file[1]):
self.logger.success('File has been uploaded on the remote machine')
else:
self.logger.error('File does not exist on the remote system.. erorr during upload')
self.logger.fail('File does not exist on the remote system.. erorr during upload')
except Exception as e:
self.logger.error('Error during upload : {}'.format(e))
self.logger.fail('Error during upload : {}'.format(e))
@requires_admin
def get_file(self):
@ -396,7 +397,7 @@ class mssql(connection):
exec_method.get_file(self.args.get_file[0], self.args.get_file[1])
self.logger.success('File {} was transferred to {}'.format(self.args.get_file[0], self.args.get_file[1]))
except Exception as e:
self.logger.error('Error reading file {}: {}'.format(self.args.get_file[0], e))
self.logger.fail('Error reading file {}: {}'.format(self.args.get_file[0], e))
# We hook these functions in the tds library to use CME's logger instead of printing the output to stdout