Skip to content

Commit

Permalink
Merge pull request AlessandroZ#7 from AlessandroZ/master
Browse files Browse the repository at this point in the history
Update master
  • Loading branch information
MyLoginOnGitHub authored Jan 3, 2020
2 parents 7f62bc1 + b2c7ff3 commit 8baa73a
Show file tree
Hide file tree
Showing 11 changed files with 90 additions and 51 deletions.
2 changes: 2 additions & 0 deletions Linux/lazagne/softwares/browsers/chrome.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from lazagne.config.crypto.pyaes import AESModeOfOperationCBC
from lazagne.config.module_info import ModuleInfo
from lazagne.config import homes
from lazagne.softwares.browsers.mozilla import python_version


class Chrome(ModuleInfo):
Expand Down Expand Up @@ -88,6 +89,7 @@ def get_passwords(self, path):
dklen=self.enc_config['length'])

password = self.chrome_decrypt(password, key=enc_key, init_vector=self.enc_config['iv'])
password = password if python_version == 2 else password.decode()
except Exception:
print(traceback.format_exc())
if user:
Expand Down
4 changes: 2 additions & 2 deletions Windows/lazagne/config/DPAPI/blob.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,11 @@ def decrypt(self, masterkey, entropy=None, strongPassword=None):

if "AES" in self.cipherAlgo.name:
cipher = AESModeOfOperationCBC(key[:int(self.cipherAlgo.keyLength)],
iv="\x00" * int(self.cipherAlgo.ivLength))
iv=b"\x00" * int(self.cipherAlgo.ivLength))
self.cleartext = b"".join([cipher.decrypt(self.cipherText[i:i + AES_BLOCK_SIZE]) for i in
range(0, len(self.cipherText), AES_BLOCK_SIZE)])
else:
cipher = self.cipherAlgo.module(key, CBC, "\x00" * self.cipherAlgo.ivLength)
cipher = self.cipherAlgo.module(key, CBC, b"\x00" * self.cipherAlgo.ivLength)
self.cleartext = cipher.decrypt(self.cipherText)

padding = char_to_int(self.cleartext[-1])
Expand Down
4 changes: 2 additions & 2 deletions Windows/lazagne/config/DPAPI/credhist.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def __init__(self, raw=None):
def parse(self, data):
self.version = data.eat("B")
n = data.eat("B")
self.idAuth = struct.unpack(">Q", "\0\0" + data.eat("6s"))[0]
self.idAuth = struct.unpack(">Q", b"\0\0" + data.eat("6s"))[0]
self.subAuth = data.eat("%dL" % n)

def __str__(self):
Expand Down Expand Up @@ -90,7 +90,7 @@ def decrypt_with_key(self, enckey):
cleartxt = crypto.dataDecrypt(self.cipherAlgo, self.hashAlgo, self.encrypted, enckey,
self.iv, self.rounds)
self.pwdhash = cleartxt[:self.shaHashLen]
self.ntlm = cleartxt[self.shaHashLen:self.shaHashLen + self.ntHashLen].rstrip("\x00")
self.ntlm = cleartxt[self.shaHashLen:self.shaHashLen + self.ntHashLen].rstrip(b"\x00")
if len(self.ntlm) != 16:
self.ntlm = None

Expand Down
2 changes: 1 addition & 1 deletion Windows/lazagne/config/DPAPI/masterkey.py
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ def get_preferred_guid(self):
self.preferred_guid = "%s-%s-%s-%s-%s%s" % (
format(GUID[0], '08x'), format(GUID[1], '04x'), format(GUID[2], '04x'), format(GUID2[0], '04x'),
format(GUID2[1], '08x'), format(GUID2[2], '04x'))
return self.preferred_guid
return self.preferred_guid.encode()

return False

Expand Down
53 changes: 27 additions & 26 deletions Windows/lazagne/config/DPAPI/vault.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@

"""
Code based from these two awesome projects:
- DPAPICK : https://bitbucket.org/jmichel/dpapick
- DPAPILAB : https://github.com/dfirfpi/dpapilab
- DPAPICK : https://bitbucket.org/jmichel/dpapick
- DPAPILAB : https://github.com/dfirfpi/dpapilab
"""

import codecs
import struct

from .blob import DPAPIBlob
Expand Down Expand Up @@ -149,7 +150,8 @@ def parse(self, data):
self.attr_unknown_4 = data.eat("L")
self.size = data.eat("L")
if self.size > 0:
self.has_iv = char_to_int(data.eat("1s")) # To change for Python 3 compatibility
self.has_iv = ord(data.eat("1s"))

if self.has_iv == 1:
self.iv_size = data.eat("L")
self.iv = data.eat(str(self.iv_size)+ "s")
Expand Down Expand Up @@ -193,16 +195,15 @@ def __init__(self, raw=None):
DataStruct.__init__(self, raw)

def parse(self, data):
self.schema_guid = "%0x-%0x-%0x-%0x%0x-%0x%0x%0x%0x%0x%0x" % data.eat("L2H8B") # data.eat("16s")
self.schema_guid = b"%0x-%0x-%0x-%0x%0x-%0x%0x%0x%0x%0x%0x" % data.eat("L2H8B") # data.eat("16s")
self.vcrd_unknown_1 = data.eat("L")
self.last_update = data.eat("Q")
self.vcrd_unknown_2 = data.eat("L")
self.vcrd_unknown_3 = data.eat("L")
self.description = data.eat_length_and_string("L").decode("UTF-16LE").encode("utf-8") # Unicode
self.attributes_array_size = data.eat("L")
# 12 is the size of the VAULT_ATTRIBUTE_MAP_ENTRY
assert self.attributes_array_size % 12 == 0
self.attributes_num = int(self.attributes_array_size / 12)
self.attributes_num = self.attributes_array_size // 12
for i in range(self.attributes_num):
# 12: size of VaultAttributeMapEntry Structure
v_map_entry = VaultAttributeMapEntry(data.eat("12s"))
Expand Down Expand Up @@ -231,13 +232,13 @@ def parse(self, data):
self.schema_guid = "%0x-%0x-%0x-%0x%0x-%0x%0x%0x%0x%0x%0x" % data.eat("L2H8B")
self.vault_vsch_unknown_1 = data.eat("L")
self.count = data.eat("L")
self.schema_name = data.eat_length_and_string("L").decode("UTF-16LE").encode("utf-8").rstrip('\x00\x00')
self.schema_name = data.eat_length_and_string("L").decode("UTF-16LE").encode("utf-8").rstrip(b'\x00\x00')


class VaultAttributeItem(object):
def __init__(self, id_, item):
self.id = id_
self.item = item.encode('hex')
self.item = codecs.encode(item, 'hex')


class VaultSchemaGeneric(DataStruct):
Expand Down Expand Up @@ -300,9 +301,9 @@ def parse(self, data):
if self.sid_len > 0:
self.sid = data.eat_sub(self.sid_len)
self.id_resource = data.eat("L")
self.resource = data.eat_length_and_string("L").decode("UTF-16LE").encode("utf-8").rstrip('\x00\x00')
self.resource = data.eat_length_and_string("L").decode("UTF-16LE").encode("utf-8").rstrip(b'\x00\x00')
self.id_password = data.eat("L")
self.authenticator = data.eat_length_and_string("L").decode("UTF-16LE").encode("utf-8").rstrip('\x00\x00') # Password
self.authenticator = data.eat_length_and_string("L").decode("UTF-16LE").encode("utf-8").rstrip(b'\x00\x00') # Password
self.id_pin = data.eat("L")
self.pin = data.eat_length_and_string("L")

Expand All @@ -328,11 +329,11 @@ def parse(self, data):
self.count = data.eat("L")
self.vault_schema_web_password_unknown1 = data.eat("L")
self.id_identity = data.eat("L")
self.identity = data.eat_length_and_string("L").decode("UTF-16LE").encode("utf-8").rstrip('\x00\x00')
self.identity = data.eat_length_and_string("L").decode("UTF-16LE").encode("utf-8").rstrip(b'\x00\x00')
self.id_resource = data.eat("L")
self.resource = data.eat_length_and_string("L").decode("UTF-16LE").encode("utf-8").rstrip('\x00\x00')
self.resource = data.eat_length_and_string("L").decode("UTF-16LE").encode("utf-8").rstrip(b'\x00\x00')
self.id_authenticator = data.eat("L")
self.authenticator = data.eat_length_and_string("L").decode("UTF-16LE").encode("utf-8").rstrip('\x00\x00')
self.authenticator = data.eat_length_and_string("L").decode("UTF-16LE").encode("utf-8").rstrip(b'\x00\x00')


class VaultSchemaActiveSync(DataStruct):
Expand All @@ -356,18 +357,18 @@ def parse(self, data):
self.count = data.eat("L")
self.vault_schema_activesync_unknown1 = data.eat("L")
self.id_identity = data.eat("L")
self.identity = data.eat_length_and_string("L").decode("UTF-16LE").encode("utf-8").rstrip('\x00\x00')
self.identity = data.eat_length_and_string("L").decode("UTF-16LE").encode("utf-8").rstrip(b'\x00\x00')
self.id_resource = data.eat("L")
self.resource = data.eat_length_and_string("L").decode("UTF-16LE").encode("utf-8").rstrip('\x00\x00')
self.resource = data.eat_length_and_string("L").decode("UTF-16LE").encode("utf-8").rstrip(b'\x00\x00')
self.id_authenticator = data.eat("L")
self.authenticator = data.eat_length_and_string("L").decode("UTF-16LE").encode("utf-8").rstrip('\x00').encode('hex')
self.authenticator = data.eat_length_and_string("L").decode("UTF-16LE").encode("utf-8").rstrip(b'\x00').encode('hex')


# Vault Schema Dict
vault_schemas = {
u'ActiveSyncCredentialSchema' : VaultSchemaActiveSync,
u'PIN Logon Vault Resource Schema' : VaultSchemaPin,
u'Windows Web Password Credential' : VaultSchemaWebPassword,
b'ActiveSyncCredentialSchema' : VaultSchemaActiveSync,
b'PIN Logon Vault Resource Schema' : VaultSchemaPin,
b'Windows Web Password Credential' : VaultSchemaWebPassword,
}


Expand Down Expand Up @@ -406,7 +407,7 @@ def get_vault_schema(self, guid, base_dir, default_schema):
Helper to get the Vault schema to apply on decoded data.
"""
vault_schema = default_schema
schema_file_path = os.path.join(base_dir, guid + '.vsch')
schema_file_path = os.path.join(base_dir.encode(), guid + b'.vsch')
try:
with open(schema_file_path, 'rb') as fschema:
vsch = VaultVsch(fschema.read())
Expand Down Expand Up @@ -456,11 +457,11 @@ def decrypt(self, mkp):
fin.seek(attribute.offset)

v_attribute = VaultAttribute(fin.read())
# print '-id: ', v_attribute.id
# print '-size: ', v_attribute.size
# print '-data: ', repr(v_attribute.data)
# print '-has_iv: ', v_attribute.has_iv
# print '-iv: ', repr(v_attribute.iv)
# print('-id: ', v_attribute.id)
# print('-size: ', v_attribute.size)
# print('-data: ', repr(v_attribute.data))
# print('-has_iv: ', v_attribute.has_iv)
# print('-iv: ', repr(v_attribute.iv))

decrypted, is_attribute_ex = self.decrypt_vault_attribute(v_attribute, key_aes128, key_aes256)
if is_attribute_ex:
Expand All @@ -475,7 +476,7 @@ def decrypt(self, mkp):
}

# Parse value found
for k, v in sorted(attributes_data.iteritems()):
for k, v in sorted(attributes_data.items()):
# Parse decrypted data depending on its schema
dataout = v['schema'](v['data'])

Expand Down
37 changes: 35 additions & 2 deletions Windows/lazagne/config/winstructure.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,24 @@ class DATA(Structure):
]


class DATA2(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),
Expand Down Expand Up @@ -195,13 +213,28 @@ class VAULT_ITEM_DATA(Structure):
PVAULT_ITEM_DATA = POINTER(VAULT_ITEM_DATA)


class VAULT_ITEM_DATA2(Structure):
_fields_ = [
# ('schemaElementId', DWORD),
# ('unk0', DWORD),
# ('Type', VAULT_ELEMENT_TYPE),
# ('type', Flag),
# ('type', DWORD * 14),
# ('unk1', DWORD),
('data', DATA2),
]


PVAULT_ITEM_DATA2 = POINTER(VAULT_ITEM_DATA2)


class VAULT_ITEM_WIN8(Structure):
_fields_ = [
('id', GUID),
('pName', PWSTR),
('pResource', PVAULT_ITEM_DATA),
('pUsername', PVAULT_ITEM_DATA),
('pPassword', PVAULT_ITEM_DATA),
('pPassword', PVAULT_ITEM_DATA2),
('pPackageSid', PVAULT_ITEM_DATA),
('LastWritten', FILETIME),
('Flags', DWORD),
Expand All @@ -219,7 +252,7 @@ class VAULT_ITEM_WIN7(Structure):
('pName', PWSTR),
('pResource', PVAULT_ITEM_DATA),
('pUsername', PVAULT_ITEM_DATA),
('pPassword', PVAULT_ITEM_DATA),
('pPassword', PVAULT_ITEM_DATA2),
('LastWritten', FILETIME),
('Flags', DWORD),
('cbProperties', DWORD),
Expand Down
8 changes: 4 additions & 4 deletions Windows/lazagne/softwares/windows/creddump7/newobj.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def __new__(typ, name, address, space):
if name in globals():
# This is a bit of "magic"
# Could be replaced with a dict mapping type names to types
return globals()[name](name,address,space)
return globals()[name](name, address, space)
elif name in builtin_types:
return Primitive(name, address, space)
else:
Expand Down Expand Up @@ -94,9 +94,9 @@ def __getattribute__(self, attr):
a_off, a_tp = get_obj_offset(types, [self.name, attr, i])
if a_tp == 'pointer':
ptp = get_ptr_type(self.name, [attr, i])
l.append(Pointer(a_tp, self.address+a_off, self.space, ptp))
l.append(Pointer(a_tp, self.address + a_off, self.space, ptp))
else:
l.append(Obj(a_tp, self.address+a_off, self.space))
l.append(Obj(a_tp, self.address + a_off, self.space))
return l
elif tp == 'pointer':
# Can't just return a Obj here, since pointers need to also
Expand Down Expand Up @@ -128,7 +128,7 @@ def members(self):
# Could also just return the list
membs = [(k, v[0]) for k,v in types[self.name][1].items()]
membs.sort(key=itemgetter(1))
return map(itemgetter(0),membs) + self.extra_members
return list(map(itemgetter(0),membs)) + self.extra_members

def values(self):
"""Return a dictionary of this object's members and their values"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,11 @@ def decrypt_hash_vista(edata, nlkm, ch):
"""
aes = AESModeOfOperationCBC(nlkm[16:32], iv=ch)

out = ""
out = b""
for i in range(0, len(edata), 16):
buf = edata[i:i+16]
if len(buf) < 16:
buf += (16 - len(buf)) * "\00"
buf += (16 - len(buf)) * b"\00"
out += b"".join([aes.decrypt(buf[i:i + AES_BLOCK_SIZE]) for i in range(0, len(buf), AES_BLOCK_SIZE)])
return out

Expand All @@ -72,9 +72,9 @@ def parse_cache_entry(cache_data):

def parse_decrypted_cache(dec_data, uname_len, domain_len, domain_name_len):
uname_off = 72
pad = 2 * ((uname_len / 2) % 2)
pad = 2 * ((uname_len // 2) % 2)
domain_off = uname_off + uname_len + pad
pad = 2 * ((domain_len / 2) % 2)
pad = 2 * ((domain_len // 2) % 2)
domain_name_off = domain_off + domain_len + pad

data_hash = dec_data[:0x10]
Expand Down Expand Up @@ -108,13 +108,13 @@ def dump_hashes(sysaddr, secaddr, vista):
if not root:
return []

cache = open_key(root, ["Cache"])
cache = open_key(root, [b"Cache"])
if not cache:
return []

hashes = []
for v in values(cache):
if v.Name == "NL$Control":
if v.Name == b"NL$Control":
continue

data = v.space.read(v.Data.value, v.DataLength.value)
Expand Down
9 changes: 3 additions & 6 deletions Windows/lazagne/softwares/windows/creddump7/win32/hashdump.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,10 +134,7 @@ def get_bootkey(sysaddr):

bootkey_scrambled = b""
for i in range(len(bootkey)):
try:
bootkey_scrambled += bootkey[p[i]]
except TypeError:
bootkey_scrambled += bytes([bootkey[p[i]]])
bootkey_scrambled += bootkey[p[i]:p[i]+1]
return bootkey_scrambled


Expand All @@ -159,7 +156,7 @@ def get_hbootkey(samaddr, bootkey):
if not F:
return None

revision = ord(F[0x00])
revision = ord(F[0x00:0x01])
if revision == 2:
md5 = hashlib.md5(F[0x70:0x80] + aqwerty + bootkey + anum)
rc4_key = md5.digest()
Expand Down Expand Up @@ -223,7 +220,7 @@ def get_user_hashes(user_key, hbootkey):
rid = int(user_key.Name, 16)
V = None
for v in values(user_key):
if v.Name == 'V':
if v.Name == b'V':
V = samaddr.read(v.Data.value, v.DataLength.value)
if not V: return None
hash_offset = unpack("<L", V[0xa8:0xa8+4])[0] + 0xCC
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,10 @@ def decrypt_aes(secret, key):

data = b""
for i in range(60, len(secret), 16):
aes = AESModeOfOperationCBC(aeskey, iv="\x00" * 16)
aes = AESModeOfOperationCBC(aeskey, iv=b"\x00" * 16)
buf = secret[i: i + 16]
if len(buf) < 16:
buf += (16 - len(buf)) * "\00"
buf += (16 - len(buf)) * b"\00"

data += aes.decrypt(buf)

Expand All @@ -117,6 +117,9 @@ def get_secret_by_name(secaddr, name, lsakey, vista):
if not root:
return None

if isinstance(name, str):
name = name.encode()

enc_secret_key = open_key(root, [b"Policy", b"Secrets", name, b"CurrVal"])
if not enc_secret_key:
return None
Expand Down
Loading

0 comments on commit 8baa73a

Please sign in to comment.