Skip to content

Commit

Permalink
vault passwords retrieved using pure python
Browse files Browse the repository at this point in the history
  • Loading branch information
AlessandroZ committed Apr 24, 2017
1 parent 4f5ecb5 commit 3157934
Show file tree
Hide file tree
Showing 6 changed files with 245 additions and 105 deletions.
178 changes: 170 additions & 8 deletions Windows/lazagne/config/WinStructure.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
# Vault Structure has been taken from mimikatz
from ctypes.wintypes import *
from ctypes import *

LPBYTE = POINTER(BYTE)
LPTSTR = LPSTR
LPCTSTR = LPSTR
LPTSTR = LPSTR
LPCTSTR = LPSTR
PHANDLE = POINTER(HANDLE)
HANDLE = LPVOID
LPDWORD = POINTER(DWORD)
INVALID_HANDLE_VALUE = c_void_p(-1).value
NTSTATUS = ULONG()
PWSTR = c_wchar_p
LPWSTR = c_wchar_p
PBYTE = POINTER(BYTE)
LPBYTE = POINTER(BYTE)

# ------------------ Constants ------------------

vaultcli = windll.vaultcli
kernel32 = windll.kernel32

##############################- Constants ##############################

# Credential Manager
CRYPTPROTECT_UI_FORBIDDEN = 0x01
Expand All @@ -21,7 +34,7 @@
# custom key to read registry (not from msdn)
ACCESS_READ = KEY_READ | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE

# ------------------ Structures ------------------
############################## Structures ##############################

class CREDENTIAL_ATTRIBUTE(Structure):
_fields_ = [
Expand Down Expand Up @@ -56,7 +69,123 @@ class DATA_BLOB(Structure):
('pbData', POINTER(c_char))
]

# ------------------ Functions ------------------
class GUID(Structure):
_fields_ = [
("data1", DWORD),
("data2", WORD),
("data3", WORD),
("data4", BYTE * 6)
]
LPGUID = POINTER(GUID)

class VAULT_CREDENTIAL_ATTRIBUTEW(Structure):
_fields_ = [
('keyword', LPWSTR),
('flags', DWORD),
('badAlign', DWORD),
('valueSize', DWORD),
('value', LPBYTE),
]
PVAULT_CREDENTIAL_ATTRIBUTEW = POINTER(VAULT_CREDENTIAL_ATTRIBUTEW)

class VAULT_BYTE_BUFFER(Structure):
_fields_ = [
('length', DWORD),
('value', PBYTE),
]

class DATA(Structure):
_fields_ = [
# ('boolean', BOOL),
# ('short', SHORT),
# ('unsignedShort', WORD),
# ('int', LONG),
# ('unsignedInt', ULONG),
# ('double', DOUBLE),
('guid', GUID),
('string', LPWSTR),
('byteArray', VAULT_BYTE_BUFFER),
('protectedArray', VAULT_BYTE_BUFFER),
('attribute', PVAULT_CREDENTIAL_ATTRIBUTEW),
# ('Sid', PSID)
('sid', DWORD)
]

class Flag(Structure):
_fields_ = [
('0x00', DWORD),
('0x01', DWORD),
('0x02', DWORD),
('0x03', DWORD),
('0x04', DWORD),
('0x05', DWORD),
('0x06', DWORD),
('0x07', DWORD),
('0x08', DWORD),
('0x09', DWORD),
('0x0a', DWORD),
('0x0b', DWORD),
('0x0c', DWORD),
('0x0d', DWORD)
]

class VAULT_ITEM_DATA(Structure):
_fields_ = [
# ('schemaElementId', DWORD),
# ('unk0', DWORD),
# ('Type', VAULT_ELEMENT_TYPE),
# ('type', Flag),
# ('type', DWORD * 14),
# ('unk1', DWORD),
('data', DATA),
]
PVAULT_ITEM_DATA = POINTER(VAULT_ITEM_DATA)

class VAULT_ITEM_WIN8(Structure):
_fields_ = [
('id', GUID),
('pName', PWSTR),
('pResource', PVAULT_ITEM_DATA),
('pUsername', PVAULT_ITEM_DATA),
('pPassword', PVAULT_ITEM_DATA),
('unknown0', PVAULT_ITEM_DATA),
('LastWritten', FILETIME),
('Flags', DWORD),
('cbProperties', DWORD),
('Properties', PVAULT_ITEM_DATA),
]
PVAULT_ITEM_WIN8 = POINTER(VAULT_ITEM_WIN8)

# class VAULT_ITEM_WIN7(Structure):
# _fields_ = [
# ('id', GUID),
# ('pName', PWSTR),
# ('pResource', PVAULT_ITEM_DATA),
# ('pUsername', PVAULT_ITEM_DATA),
# ('pPassword', PVAULT_ITEM_DATA),
# ('LastWritten', FILETIME),
# ('Flags', DWORD),
# ('cbProperties', DWORD),
# ('Properties', PVAULT_ITEM_DATA),
# ]
# PVAULT_ITEM_WIN7 = POINTER(VAULT_ITEM_WIN7)

class OSVERSIONINFOEXW(Structure):
_fields_ = [
('dwOSVersionInfoSize', c_ulong),
('dwMajorVersion', c_ulong),
('dwMinorVersion', c_ulong),
('dwBuildNumber', c_ulong),
('dwPlatformId', c_ulong),
('szCSDVersion', c_wchar*128),
('wServicePackMajor', c_ushort),
('wServicePackMinor', c_ushort),
('wSuiteMask', c_ushort),
('wProductType', c_byte),
('wReserved', c_byte)
]

############################## Functions ##############################

CredEnumerate = windll.advapi32.CredEnumerateA
CredEnumerate.restype = BOOL
Expand All @@ -71,7 +200,29 @@ class DATA_BLOB(Structure):
CryptUnprotectData = windll.crypt32.CryptUnprotectData


# ------------------ Custom functions ------------------
prototype = WINFUNCTYPE(ULONG, DWORD, LPDWORD, POINTER(LPGUID))
vaultEnumerateVaults = prototype(("VaultEnumerateVaults", windll.vaultcli))

prototype = WINFUNCTYPE(ULONG, LPGUID, DWORD, HANDLE)
vaultOpenVault = prototype(("VaultOpenVault", windll.vaultcli))

prototype = WINFUNCTYPE(ULONG, HANDLE, DWORD, LPDWORD, POINTER(c_char_p))
vaultEnumerateItems = prototype(("VaultEnumerateItems", windll.vaultcli))

prototype = WINFUNCTYPE(ULONG, HANDLE, LPGUID, PVAULT_ITEM_DATA, PVAULT_ITEM_DATA, PVAULT_ITEM_DATA, HWND, DWORD, POINTER(PVAULT_ITEM_WIN8))
vaultGetItem8 = prototype(("VaultGetItem", windll.vaultcli))

# prototype = WINFUNCTYPE(ULONG, HANDLE, LPGUID, PVAULT_ITEM_DATA, PVAULT_ITEM_DATA, HWND, DWORD, POINTER(PVAULT_ITEM_WIN7))
# vaultGetItem7 = prototype(("VaultGetItem", windll.vaultcli))

prototype = WINFUNCTYPE(ULONG, LPVOID)
vaultFree = prototype(("VaultFree", windll.vaultcli))

prototype = WINFUNCTYPE(ULONG, PHANDLE)
vaultCloseVault = prototype(("VaultCloseVault", windll.vaultcli))


############################## Custom functions ##############################

def getData(blobOut):
cbData = int(blobOut.cbData)
Expand Down Expand Up @@ -100,4 +251,15 @@ def Win32CryptUnprotectData(cipherText, entropy=None):
if CryptUnprotectData(byref(blobIn), None, None, None, None, 0, byref(blobOut)):
return getData(blobOut)
else:
return False
return False

# return major anr minor version
# https://msdn.microsoft.com/en-us/library/windows/desktop/ms724832(v=vs.85).aspx
def get_os_version():
os_version = OSVERSIONINFOEXW()
os_version.dwOSVersionInfoSize = sizeof(os_version)
retcode = windll.Ntdll.RtlGetVersion(byref(os_version))
if retcode != 0:
return False

return '%s.%s' % (str(os_version.dwMajorVersion.real), str(os_version.dwMinorVersion.real))
2 changes: 2 additions & 0 deletions Windows/lazagne/config/manageModules.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
# windows
from lazagne.softwares.windows.system_hash import Hashes
from lazagne.softwares.windows.credman import Credman
from lazagne.softwares.windows.vault import Vault
# sysadmin
from lazagne.softwares.sysadmin.filezilla import Filezilla
from lazagne.softwares.sysadmin.cyberduck import Cyberduck
Expand Down Expand Up @@ -95,6 +96,7 @@ def get_modules():
SQLDeveloper(),
Squirrel(),
Turba(),
Vault(),
Wifi(),
WinSCP(),
Composer()
Expand Down
2 changes: 1 addition & 1 deletion Windows/lazagne/config/write_output.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
# -*- coding: utf-8 -*-from constant import constantfrom time import gmtime, strftimeimport os, getpass, socketimport loggingimport jsonimport tempfilefrom lazagne.config.header import Header, setColor# --------------------------- Functions used to write ---------------------------def write_header(): time = strftime("%Y-%m-%d %H:%M:%S", gmtime()) header = '''|====================================================================|\r\n| |\r\n| Credentials discovery |\r\n| |\r\n| ! BANG BANG ! |\r\n| |\r\n|====================================================================|\r\n\r\n- Date: ''' + time + '''\n\r- Username: ''' + getpass.getuser() + ''' \r\n- Hostname: ''' + socket.gethostname() + ''' \r\n\r\n------------------------------ Results ------------------------------\r\n\r\n''' open(constant.folder_name + os.sep + constant.file_name_results + '.txt',"a+b").write(header)def write_footer(): footer = '\n[+] %s passwords have been found.\r\n\r\n' % str(constant.nbPasswordFound) open(constant.folder_name + os.sep + constant.file_name_results + '.txt',"a+b").write(footer) def write_credentials(pwdFound, category, filePath): tmp = "############ %s passwords ############\r\n\r\n" % category for pwd in pwdFound: for p in pwd.keys(): tmp = str(tmp) + str(p) + ": " + str(pwd[p].encode('utf-8')) + "\r\n" tmp = str(tmp) + "\r\n" open(filePath,"a+b").write(tmp) def checks_write(values, category): if values: if "Passwords" not in constant.finalResults: constant.finalResults["Passwords"] = [] constant.finalResults["Passwords"].append([{"Category": category}, values])# --------------------------- End of functions used to write ---------------------------# --------------------------- Output functions ---------------------------def print_footer(): footer = '\n[+] %s passwords have been found.\n' % str(constant.nbPasswordFound) if logging.getLogger().isEnabledFor(logging.INFO) == False: footer += 'For more information launch it again with the -v option\n' print footer# print output if passwords have been founddef print_output(software_name, pwdFound, title1 = False): if pwdFound: # if the debug logging level is not apply => print the title if logging.getLogger().isEnabledFor(logging.INFO) == False: if not title1: Header().title(software_name) toWrite = [] password_category = False for pwd in pwdFound: # detect which kinds of password has been found lower_list = [s.lower() for s in pwd.keys()] password = [s for s in lower_list if "password" in s] if password: password_category = password else: key = [s for s in lower_list if "key" in s] # for the wifi if key: password_category = key else: hash = [s for s in lower_list if "hash" in s] if hash: password_category = hash # No password found if not password_category: print_debug("FAILED", "Password not found !!!") else: print_debug("OK", '%s found !!!' % password_category[0].title()) toWrite.append(pwd) # Store all passwords found on a table => for dictionary attack if master password set constant.nbPasswordFound += 1 try: constant.passwordFound.append(pwd[password_category[0]]) except: pass for p in pwd.keys(): try: print '%s: %s' % (p, pwd[p]) except Exception,e: print_debug('DEBUG', '{0}'.format(e)) print '%s: %s' % (p.encode('utf-8'), pwd[p].encode('utf-8')) print # write credentials into a text file checks_write(toWrite, software_name) else: logging.info("[!] No passwords found\n")def print_debug(error_level, message): GREEN = '\x1b[32m' RED = '\x1b[31m' RESET_COLOR = '\x1b[0m' BRIGHT = '\x1b[1m' CYAN = '\x1b[36m' # print when password is found if error_level == 'OK': setColor('green') print message setColor() # print when password is not found elif error_level == 'FAILED': setColor('red', True) print message setColor() # print messages depending of their criticism elif error_level == 'CRITICAL': setColor('red', True) logging.critical('[CRITICAL] %s\n' % message) setColor() elif error_level == 'ERROR': setColor('red', True) logging.error('[ERROR] %s\n' % message) setColor() elif error_level == 'WARNING': setColor('cyan') logging.warning('[WARNING] %s\n' % message) setColor() elif error_level == 'DEBUG': logging.debug('[DEBUG] %s\n' % message) elif error_level == 'INFO': logging.info('%s\n' % message) else: logging.info('[%s] %s' % (error_level, message))# --------------------------- End of output functions ---------------------------def parseJsonResultToBuffer(jsonString, color=False): green = '' reset = '' title = '' # if color: # green = Fore.GREEN # title = BRIGHT + Fore.WHITE # reset = RESET_COLOR buffer = '' try: for json in jsonString: if json: buffer += '\r\n\r\n{title_color}########## User: {username} ##########{reset_color}\r\n\r\n'.format(title_color=title, username=json['User'], reset_color=reset) if 'Passwords' not in json: buffer += 'No passwords found for this user !' else: for all_passwords in json['Passwords']: buffer += '{title_color}------------------- {password_category} -----------------{reset_color}\r\n'.format(title_color=title, password_category=all_passwords[0]['Category'], reset_color=reset) for password_by_category in all_passwords[1]: buffer += '\r\n{green_color}Password found !!!{reset_color}\r\n'.format(green_color=green, reset_color=reset) constant.nbPasswordFound += 1 for dic in password_by_category.keys(): try: buffer += '%s: %s\r\n' % (dic, password_by_category[dic].encode('utf-8')) except: buffer += '%s: %s\r\n' % (dic, password_by_category[dic].encode(encoding='utf-8',errors='replace')) buffer += '\r\n' except Exception as e: print_debug('ERROR', 'Error parsing the json results: %s' % e) print_debug('ERROR', 'json content: %s' % jsonString) return buffer
# -*- coding: utf-8 -*-from constant import constantfrom time import gmtime, strftimeimport os, getpass, socketimport loggingimport jsonimport tempfilefrom lazagne.config.header import Header, setColor# --------------------------- Functions used to write ---------------------------def write_header(): time = strftime("%Y-%m-%d %H:%M:%S", gmtime()) header = '''|====================================================================|\r\n| |\r\n| Credentials discovery |\r\n| |\r\n| ! BANG BANG ! |\r\n| |\r\n|====================================================================|\r\n\r\n- Date: ''' + time + '''\n\r- Username: ''' + getpass.getuser() + ''' \r\n- Hostname: ''' + socket.gethostname() + ''' \r\n\r\n------------------------------ Results ------------------------------\r\n\r\n''' open(constant.folder_name + os.sep + constant.file_name_results + '.txt',"a+b").write(header)def write_footer(): footer = '\n[+] %s passwords have been found.\r\n\r\n' % str(constant.nbPasswordFound) open(constant.folder_name + os.sep + constant.file_name_results + '.txt',"a+b").write(footer) def write_credentials(pwdFound, category, filePath): tmp = "############ %s passwords ############\r\n\r\n" % category for pwd in pwdFound: for p in pwd.keys(): tmp = str(tmp) + str(p) + ": " + str(pwd[p].encode('utf-8')) + "\r\n" tmp = str(tmp) + "\r\n" open(filePath,"a+b").write(tmp) def checks_write(values, category): if values: if "Passwords" not in constant.finalResults: constant.finalResults["Passwords"] = [] constant.finalResults["Passwords"].append([{"Category": category}, values])# --------------------------- End of functions used to write ---------------------------# --------------------------- Output functions ---------------------------def print_footer(): footer = '\n[+] %s passwords have been found.\n' % str(constant.nbPasswordFound) if logging.getLogger().isEnabledFor(logging.INFO) == False: footer += 'For more information launch it again with the -v option\n' print footer# print output if passwords have been founddef print_output(software_name, pwdFound, title1 = False): if pwdFound: # if the debug logging level is not apply => print the title if logging.getLogger().isEnabledFor(logging.INFO) == False: if not title1: Header().title(software_name) toWrite = [] for pwd in pwdFound: password_category = False # detect which kinds of password has been found lower_list = [s.lower() for s in pwd.keys()] password = [s for s in lower_list if "password" in s] if password: password_category = password else: key = [s for s in lower_list if "key" in s] # for the wifi if key: password_category = key else: hash = [s for s in lower_list if "hash" in s] if hash: password_category = hash # No password found if not password_category: print_debug("FAILED", "Password not found !!!") else: print_debug("OK", '%s found !!!' % password_category[0].title()) toWrite.append(pwd) # Store all passwords found on a table => for dictionary attack if master password set constant.nbPasswordFound += 1 try: constant.passwordFound.append(pwd[password_category[0]]) except: pass for p in pwd.keys(): try: print '%s: %s' % (p, pwd[p]) except Exception,e: print_debug('DEBUG', '{0}'.format(e)) print '%s: %s' % (p.encode('utf-8'), pwd[p].encode('utf-8')) print # write credentials into a text file checks_write(toWrite, software_name) else: logging.info("[!] No passwords found\n")def print_debug(error_level, message): GREEN = '\x1b[32m' RED = '\x1b[31m' RESET_COLOR = '\x1b[0m' BRIGHT = '\x1b[1m' CYAN = '\x1b[36m' # print when password is found if error_level == 'OK': setColor('green') print message setColor() # print when password is not found elif error_level == 'FAILED': setColor('red', True) print message setColor() # print messages depending of their criticism elif error_level == 'CRITICAL': setColor('red', True) logging.critical('[CRITICAL] %s\n' % message) setColor() elif error_level == 'ERROR': setColor('red', True) logging.error('[ERROR] %s\n' % message) setColor() elif error_level == 'WARNING': setColor('cyan') logging.warning('[WARNING] %s\n' % message) setColor() elif error_level == 'DEBUG': logging.debug('[DEBUG] %s\n' % message) elif error_level == 'INFO': logging.info('%s\n' % message) else: logging.info('[%s] %s' % (error_level, message))# --------------------------- End of output functions ---------------------------def parseJsonResultToBuffer(jsonString, color=False): green = '' reset = '' title = '' # if color: # green = Fore.GREEN # title = BRIGHT + Fore.WHITE # reset = RESET_COLOR buffer = '' try: for json in jsonString: if json: buffer += '\r\n\r\n{title_color}########## User: {username} ##########{reset_color}\r\n\r\n'.format(title_color=title, username=json['User'], reset_color=reset) if 'Passwords' not in json: buffer += 'No passwords found for this user !' else: for all_passwords in json['Passwords']: buffer += '{title_color}------------------- {password_category} -----------------{reset_color}\r\n'.format(title_color=title, password_category=all_passwords[0]['Category'], reset_color=reset) for password_by_category in all_passwords[1]: buffer += '\r\n{green_color}Password found !!!{reset_color}\r\n'.format(green_color=green, reset_color=reset) constant.nbPasswordFound += 1 for dic in password_by_category.keys(): try: buffer += '%s: %s\r\n' % (dic, password_by_category[dic].encode('utf-8')) except: buffer += '%s: %s\r\n' % (dic, password_by_category[dic].encode(encoding='utf-8',errors='replace')) buffer += '\r\n' except Exception as e: print_debug('ERROR', 'Error parsing the json results: %s' % e) print_debug('ERROR', 'json content: %s' % jsonString) return buffer
Expand Down
Loading

0 comments on commit 3157934

Please sign in to comment.