def parse_mimikatz(self, data): """ Parse the output from Invoke-Mimikatz to return credential sets. This was directly stolen from the Empire project as well. """ # cred format: # credType, domain, username, password, hostname, sid creds = [] # regexes for "sekurlsa::logonpasswords" Mimikatz output regexes = [ "(?s)(?<=msv :).*?(?=tspkg :)", "(?s)(?<=tspkg :).*?(?=wdigest :)", "(?s)(?<=wdigest :).*?(?=kerberos :)", "(?s)(?<=kerberos :).*?(?=ssp :)", "(?s)(?<=ssp :).*?(?=credman :)", "(?s)(?<=credman :).*?(?=Authentication Id :)", "(?s)(?<=credman :).*?(?=mimikatz)" ] hostDomain = "" domainSid = "" hostName = "" lines = data.split("\n") for line in lines[0:2]: if line.startswith("Hostname:"): try: domain = line.split(":")[1].strip() temp = domain.split("/")[0].strip() domainSid = domain.split("/")[1].strip() hostName = temp.split(".")[0] hostDomain = ".".join(temp.split(".")[1:]) except: pass for regex in regexes: p = re.compile(regex) for match in p.findall(data): lines2 = match.split("\n") username, domain, password = "", "", "" for line in lines2: try: if "Username" in line: username = line.split(":", 1)[1].strip() elif "Domain" in line: domain = line.split(":", 1)[1].strip() elif "NTLM" in line or "Password" in line: password = line.split(":", 1)[1].strip() except: pass if username != "" and password != "" and password != "(null)": sid = "" # substitute the FQDN in if it matches if hostDomain.startswith(domain.lower()): domain = hostDomain sid = domainSid if validate_ntlm(password): credType = "hash" else: credType = "plaintext" # ignore machine account plaintexts if not (credType == "plaintext" and username.endswith("$")): creds.append((credType, domain, username, password, hostName, sid)) if len(creds) == 0: # check if we have lsadump output to check for krbtgt # happens on domain controller hashdumps for x in xrange(8, 13): if lines[x].startswith("Domain :"): domain, sid, krbtgtHash = "", "", "" try: domainParts = lines[x].split(":")[1] domain = domainParts.split("/")[0].strip() sid = domainParts.split("/")[1].strip() # substitute the FQDN in if it matches if hostDomain.startswith(domain.lower()): domain = hostDomain sid = domainSid for x in xrange(0, len(lines)): if lines[x].startswith("User : krbtgt"): krbtgtHash = lines[x + 2].split(":")[1].strip() break if krbtgtHash != "": creds.append(("hash", domain, "krbtgt", krbtgtHash, hostName, sid)) except Exception as e: pass if len(creds) == 0: # check if we get lsadump::dcsync output if '** SAM ACCOUNT **' in lines: domain, user, userHash, dcName, sid = "", "", "", "", "" for line in lines: try: if line.strip().endswith("will be the domain"): domain = line.split("'")[1] elif line.strip().endswith("will be the DC server"): dcName = line.split("'")[1].split(".")[0] elif line.strip().startswith("SAM Username"): user = line.split(":")[1].strip() elif line.strip().startswith("Object Security ID"): parts = line.split(":")[1].strip().split("-") sid = "-".join(parts[0:-1]) elif line.strip().startswith("Hash NTLM:"): userHash = line.split(":")[1].strip() except: pass if domain != "" and userHash != "": creds.append(("hash", domain, user, userHash, dcName, sid)) return self.uniquify_tuples(creds)
def do_creds(self, line): filterTerm = line.strip() if filterTerm == "": creds = self.db.get_credentials() self.display_creds(creds) elif filterTerm.split()[0].lower() == "add": # add format: "domain username password <notes> <credType> <sid> args = filterTerm.split()[1:] if len(args) == 3: domain, username, password = args if validate_ntlm(password): self.db.add_credential("hash", domain, username, password) else: self.db.add_credential("plaintext", domain, username, password) else: print("[!] Format is 'add domain username password") return elif filterTerm.split()[0].lower() == "remove": args = filterTerm.split()[1:] if len(args) != 1: print("[!] Format is 'remove <credID>'") return else: self.db.remove_credentials(args) self.db.remove_admin_relation(userIDs=args) elif filterTerm.split()[0].lower() == "plaintext": creds = self.db.get_credentials(credtype="plaintext") self.display_creds(creds) elif filterTerm.split()[0].lower() == "hash": creds = self.db.get_credentials(credtype="hash") self.display_creds(creds) else: creds = self.db.get_credentials(filterTerm=filterTerm) if len(creds) != 1: self.display_creds(creds) elif len(creds) == 1: data = [['CredID', 'CredType', 'Pillaged From HostID', 'Domain', 'UserName', 'Password']] credIDList = [] for cred in creds: credID = cred[0] credIDList.append(credID) domain = cred[1] username = cred[2] password = cred[3] credtype = cred[4] pillaged_from = cred[5] data.append([credID, credtype, pillaged_from, domain, username, password]) self.print_table(data, title='Credential(s)') data = [['GroupID', 'Domain', 'Name']] for credID in credIDList: links = self.db.get_group_relations(userID=credID) for link in links: linkID, userID, groupID = link groups = self.db.get_groups(groupID) for group in groups: groupID = group[0] domain = group[1] name = group[2] data.append([groupID, domain, name]) self.print_table(data, title='Member of Group(s)') data = [['HostID', 'IP', 'Hostname', 'Domain', 'OS']] for credID in credIDList: links = self.db.get_admin_relations(userID=credID) for link in links: linkID, credID, hostID = link hosts = self.db.get_computers(hostID) for host in hosts: hostID = host[0] ip = host[1] hostname = host[2] domain = host[3] os = host[4] data.append([hostID, ip, hostname, domain, os]) self.print_table(data, title='Admin Access to Host(s)')
def do_creds(self, line): filterTerm = line.strip() if filterTerm == "": creds = self.db.get_credentials() self.display_creds(creds) elif filterTerm.split()[0].lower() == "add": args = filterTerm.split()[1:] if len(args) == 3: domain, username, password = args if validate_ntlm(password): self.db.add_credential("hash", domain, username, password) else: self.db.add_credential("plaintext", domain, username, password) else: print "[!] Format is 'add domain username password" return elif filterTerm.split()[0].lower() == "remove": args = filterTerm.split()[1:] if len(args) != 1: print "[!] Format is 'remove <credID>'" return else: self.db.remove_credentials(args) self.db.remove_links(credIDs=args) elif filterTerm.split()[0].lower() == "plaintext": creds = self.db.get_credentials(credtype="plaintext") self.display_creds(creds) elif filterTerm.split()[0].lower() == "hash": creds = self.db.get_credentials(credtype="hash") self.display_creds(creds) else: creds = self.db.get_credentials(filterTerm=filterTerm) data = [['CredID', 'CredType', 'Domain', 'UserName', 'Password']] credIDList = [] for cred in creds: credID = cred[0] credIDList.append(credID) credType = cred[1] domain = cred[2] username = cred[3] password = cred[4] data.append([ credID, credType, domain.decode('utf-8'), username.decode('utf-8'), password.decode('utf-8') ]) self.print_table(data, title='Credential(s)') data = [['HostID', 'IP', 'Hostname', 'Domain', 'OS']] for credID in credIDList: links = self.db.get_admin_relations(userID=credID) for link in links: linkID, credID, hostID = link hosts = self.db.get_computers(hostID) for host in hosts: hostID = host[0] ip = host[1] hostname = host[2] domain = host[3] os = host[4] data.append([ hostID, ip, hostname.decode('utf-8'), domain.decode('utf-8'), os ]) self.print_table(data, title='Admin Access to Host(s)')
def do_creds(self, line): filterTerm = line.strip() if filterTerm == "": creds = self.db.get_credentials() self.display_creds(creds) elif filterTerm.split()[0].lower() == "add": args = filterTerm.split()[1:] if len(args) == 3: domain, username, password = args if validate_ntlm(password): self.db.add_credential("hash", domain, username, password) else: self.db.add_credential("plaintext", domain, username, password) else: print "[!] Format is 'add domain username password" return elif filterTerm.split()[0].lower() == "remove": args = filterTerm.split()[1:] if len(args) != 1: print "[!] Format is 'remove <credID>'" return else: self.db.remove_credentials(args) self.db.remove_links(credIDs=args) elif filterTerm.split()[0].lower() == "plaintext": creds = self.db.get_credentials(credtype="plaintext") self.display_creds(creds) elif filterTerm.split()[0].lower() == "hash": creds = self.db.get_credentials(credtype="hash") self.display_creds(creds) else: creds = self.db.get_credentials(filterTerm=filterTerm) data = [['CredID', 'CredType', 'Domain', 'UserName', 'Password']] credIDList = [] for cred in creds: credID = cred[0] credIDList.append(credID) credType = cred[1] domain = cred[2] username = cred[3] password = cred[4] data.append([credID, credType, domain.decode('utf-8'), username.decode('utf-8'), password.decode('utf-8')]) self.print_table(data, title='Credential(s)') data = [['HostID', 'IP', 'Hostname', 'Domain', 'OS']] for credID in credIDList: links = self.db.get_admin_relations(userID=credID) for link in links: linkID, credID, hostID = link hosts = self.db.get_computers(hostID) for host in hosts: hostID = host[0] ip = host[1] hostname = host[2] domain = host[3] os = host[4] data.append([hostID, ip, hostname.decode('utf-8'), domain.decode('utf-8'), os]) self.print_table(data, title='Admin Access to Host(s)')
def parse_mimikatz(self, data): """ Parse the output from Invoke-Mimikatz to return credential sets. This was directly stolen from the Empire project as well. """ # cred format: # credType, domain, username, password, hostname, sid creds = [] # regexes for "sekurlsa::logonpasswords" Mimikatz output regexes = ["(?s)(?<=msv :).*?(?=tspkg :)", "(?s)(?<=tspkg :).*?(?=wdigest :)", "(?s)(?<=wdigest :).*?(?=kerberos :)", "(?s)(?<=kerberos :).*?(?=ssp :)", "(?s)(?<=ssp :).*?(?=credman :)", "(?s)(?<=credman :).*?(?=Authentication Id :)", "(?s)(?<=credman :).*?(?=mimikatz)"] hostDomain = "" domainSid = "" hostName = "" lines = data.split("\n") for line in lines[0:2]: if line.startswith("Hostname:"): try: domain = line.split(":")[1].strip() temp = domain.split("/")[0].strip() domainSid = domain.split("/")[1].strip() hostName = temp.split(".")[0] hostDomain = ".".join(temp.split(".")[1:]) except: pass for regex in regexes: p = re.compile(regex) for match in p.findall(data): lines2 = match.split("\n") username, domain, password = "", "", "" for line in lines2: try: if "Username" in line: username = line.split(":",1)[1].strip() elif "Domain" in line: domain = line.split(":",1)[1].strip() elif "NTLM" in line or "Password" in line: password = line.split(":",1)[1].strip() except: pass if username != "" and password != "" and password != "(null)": sid = "" # substitute the FQDN in if it matches if hostDomain.startswith(domain.lower()): domain = hostDomain sid = domainSid if validate_ntlm(password): credType = "hash" else: credType = "plaintext" # ignore machine account plaintexts if not (credType == "plaintext" and username.endswith("$")): creds.append((credType, domain, username, password, hostName, sid)) if len(creds) == 0: # check if we have lsadump output to check for krbtgt # happens on domain controller hashdumps for x in xrange(8,13): if lines[x].startswith("Domain :"): domain, sid, krbtgtHash = "", "", "" try: domainParts = lines[x].split(":")[1] domain = domainParts.split("/")[0].strip() sid = domainParts.split("/")[1].strip() # substitute the FQDN in if it matches if hostDomain.startswith(domain.lower()): domain = hostDomain sid = domainSid for x in xrange(0, len(lines)): if lines[x].startswith("User : krbtgt"): krbtgtHash = lines[x+2].split(":")[1].strip() break if krbtgtHash != "": creds.append(("hash", domain, "krbtgt", krbtgtHash, hostName, sid)) except Exception as e: pass if len(creds) == 0: # check if we get lsadump::dcsync output if '** SAM ACCOUNT **' in lines: domain, user, userHash, dcName, sid = "", "", "", "", "" for line in lines: try: if line.strip().endswith("will be the domain"): domain = line.split("'")[1] elif line.strip().endswith("will be the DC server"): dcName = line.split("'")[1].split(".")[0] elif line.strip().startswith("SAM Username"): user = line.split(":")[1].strip() elif line.strip().startswith("Object Security ID"): parts = line.split(":")[1].strip().split("-") sid = "-".join(parts[0:-1]) elif line.strip().startswith("Hash NTLM:"): userHash = line.split(":")[1].strip() except: pass if domain != "" and userHash != "": creds.append(("hash", domain, user, userHash, dcName, sid)) return self.uniquify_tuples(creds)