skelsec / pypykatz

Mimikatz implementation in pure Python
MIT License
2.81k stars 371 forks source link

Add support for Windows 10 x86 #96

Closed physics-sec closed 2 years ago

physics-sec commented 2 years ago

I noticed that Windows 10 x86 build 19043 does not work (neither does in mimikatz, to be fair) I intended to make a PR but I just lack the understanding to provide you with fully functional code, I can give you some suggestions though.

First of all, some background:

== System Info ==
ProcessorArchitecture PROCESSOR_ARCHITECTURE.INTEL
OperatingSystem -guess- Windows 10
ProcessorLevel 6
ProcessorRevision 0x8e0c
NumberOfProcessors 2
ProductType PRODUCT_TYPE.VER_NT_WORKSTATION
MajorVersion 10
MinorVersion 0
BuildNumber 19043
PlatformId PLATFORM_ID.VER_PLATFORM_WIN32_NT
CSDVersion:
SuiteMask SUITE_MASK.VER_SUITE_SINGLEUSERTS
VendorId 0x756e6547 0x49656e69 0x6c65746e
VersionInformation 526060
FeatureInformation 395049983
AMDExtendedCpuFeatures 130023424
ProcessorFeatures

Encryption keys (AES and DES)

in pypykatz/lsadecryptor/lsa_template_nt6.py:296 we can find this structure:

class KIWI_BCRYPT_KEY81:
    def __init__(self, reader):
        self.size = ULONG(reader).value
        self.tag  = reader.read(4)  # 'MSSK'
        self.type = ULONG(reader).value
        self.unk0 = ULONG(reader).value
        self.unk1 = ULONG(reader).value
        self.unk2 = ULONG(reader).value 
        self.unk3 = ULONG(reader).value
        self.unk4 = ULONG(reader).value
        reader.align()
        self.unk5 = PVOID(reader).value #before, align in x64
        self.unk6 = ULONG(reader).value
        self.unk7 = ULONG(reader).value
        self.unk8 = ULONG(reader).value
        self.unk9 = ULONG(reader).value
        self.hardkey = KIWI_HARD_KEY(reader)

Once parsed, the hardkey ends up being empty and that breaks every calculation that follows. I found that adding an unknown field number 10 appears to "fix" this:

class KIWI_BCRYPT_KEY81:
    def __init__(self, reader):
        self.size = ULONG(reader).value
        self.tag  = reader.read(4)  # 'MSSK'
        self.type = ULONG(reader).value
        self.unk0 = ULONG(reader).value
        self.unk1 = ULONG(reader).value
        self.unk2 = ULONG(reader).value 
        self.unk3 = ULONG(reader).value
        self.unk4 = ULONG(reader).value
        reader.align()
        self.unk5 = PVOID(reader).value #before, align in x64
        self.unk6 = ULONG(reader).value
        self.unk7 = ULONG(reader).value
        self.unk8 = ULONG(reader).value
        self.unk9 = ULONG(reader).value
        self.unk10 = ULONG(reader).value # new field, added only for x86 build 19043
        self.hardkey = KIWI_HARD_KEY(reader)

wdigest signature

in pypykatz/lsadecryptor/packages/wdigest/decryptor.py:73 the signature is set with this piece of code:

elif sysinfo.buildnumber >= WindowsMinBuild.WIN_10.value:
    template.signature = b'\x74\x15\x8b\x0a\x39\x4e\x10'
    template.first_entry_offset = -6
    template.primary_offset = 32
    template.list_entry = PWdigestListEntry

else:
    template.signature = b'\x74\x15\x8b\x17\x39\x56\x10'
    template.first_entry_offset = -6
    template.primary_offset = 32
    template.list_entry = PWdigestListEntry

Notice that the elif will be true if the build number is greater than 9800, which it is since this Windows build is 19043 The final "else" branch will never be called. I found that if that branch is instead used, the signature is properly found and the wdigest data is parsed without errors.

result

You go from crashing with this:

== Errors ==
msv_exception_please_report b2JqZWN0IG9mIHR5cGUgJ05vbmVUeXBlJyBoYXMgbm8gbGVuKCkNCiAgRmlsZSAiL3Vzci9saWIvcHl0aG9uMy45L3NpdGUtcGFja2FnZXMvcHlweWthdHovcHlweWthdHoucHkiLCBsaW5lIDM1NSwgaW4gc3RhcnQKICAgIHNlbGYuZ2V0X2xvZ29uY3JlZHMoKQoNCiAgRmlsZSAiL3Vzci9saWIvcHl0aG9uMy45L3NpdGUtcGFja2FnZXMvcHlweWthdHovcHlweWthdHoucHkiLCBsaW5lIDI0MiwgaW4gZ2V0X2xvZ29uY3JlZHMKICAgIGxvZ29uY3JlZF9kZWNyeXB0b3Iuc3RhcnQoKQoNCiAgRmlsZSAiL3Vzci9saWIvcHl0aG9uMy45L3NpdGUtcGFja2FnZXMvcHlweWthdHovbHNhZGVjcnlwdG9yL3BhY2thZ2VzL21zdi9kZWNyeXB0b3IucHkiLCBsaW5lIDQyNCwgaW4gc3RhcnQKICAgIHNlbGYud2Fsa19saXN0KGVudHJ5X3B0ciwgc2VsZi5hZGRfZW50cnkpCg0KICBGaWxlICIvdXNyL2xpYi9weXRob24zLjkvc2l0ZS1wYWNrYWdlcy9weXB5a2F0ei9sc2FkZWNyeXB0b3IvcGFja2FnZV9jb21tb25zLnB5IiwgbGluZSAxODIsIGluIHdhbGtfbGlzdAogICAgY2FsbGJhY2soZW50cnkpCg0KICBGaWxlICIvdXNyL2xpYi9weXRob24zLjkvc2l0ZS1wYWNrYWdlcy9weXB5a2F0ei9sc2FkZWNyeXB0b3IvcGFja2FnZXMvbXN2L2RlY3J5cHRvci5weSIsIGxpbmUgMzA5LCBpbiBhZGRfZW50cnkKICAgIHNlbGYud2Fsa19saXN0KGVudHJ5LkNyZWRlbnRpYWxzX2xpc3RfcHRyLCBzZWxmLmFkZF9jcmVkZW50aWFscykKDQogIEZpbGUgIi91c3IvbGliL3B5dGhvbjMuOS9zaXRlLXBhY2thZ2VzL3B5cHlrYXR6L2xzYWRlY3J5cHRvci9wYWNrYWdlX2NvbW1vbnMucHkiLCBsaW5lIDE4MiwgaW4gd2Fsa19saXN0CiAgICBjYWxsYmFjayhlbnRyeSkKDQogIEZpbGUgIi91c3IvbGliL3B5dGhvbjMuOS9zaXRlLXBhY2thZ2VzL3B5cHlrYXR6L2xzYWRlY3J5cHRvci9wYWNrYWdlcy9tc3YvZGVjcnlwdG9yLnB5IiwgbGluZSAzMTYsIGluIGFkZF9jcmVkZW50aWFscwogICAgc2VsZi53YWxrX2xpc3QoCg0KICBGaWxlICIvdXNyL2xpYi9weXRob24zLjkvc2l0ZS1wYWNrYWdlcy9weXB5a2F0ei9sc2FkZWNyeXB0b3IvcGFja2FnZV9jb21tb25zLnB5IiwgbGluZSAxODIsIGluIHdhbGtfbGlzdAogICAgY2FsbGJhY2soZW50cnkpCg0KICBGaWxlICIvdXNyL2xpYi9weXRob24zLjkvc2l0ZS1wYWNrYWdlcy9weXB5a2F0ei9sc2FkZWNyeXB0b3IvcGFja2FnZXMvbXN2L2RlY3J5cHRvci5weSIsIGxpbmUgMzYxLCBpbiBhZGRfcHJpbWFyeV9jcmVkZW50aWFscwogICAgc3RydWN0X3JlYWRlciA9IEdlbmVyaWNSZWFkZXIoZGVjX2RhdGEsIHNlbGYuc3lzaW5mby5hcmNoaXRlY3R1cmUpCg0KICBGaWxlICIvdXNyL2xpYi9weXRob24zLjkvc2l0ZS1wYWNrYWdlcy9weXB5a2F0ei9jb21tb25zL2NvbW1vbi5weSIsIGxpbmUgMjksIGluIF9faW5pdF9fCiAgICBzZWxmLmVuZF9hZGRyZXNzID0gbGVuKGRhdGEpCg==
dpapi_exception_please_report b2JqZWN0IHN1cHBvcnRpbmcgdGhlIGJ1ZmZlciBBUEkgcmVxdWlyZWQNCiAgRmlsZSAiL3Vzci9saWIvcHl0aG9uMy45L3NpdGUtcGFja2FnZXMvcHlweWthdHovcHlweWthdHoucHkiLCBsaW5lIDM5MCwgaW4gc3RhcnQKICAgIHNlbGYuZ2V0X2RwYXBpKCkKDQogIEZpbGUgIi91c3IvbGliL3B5dGhvbjMuOS9zaXRlLXBhY2thZ2VzL3B5cHlrYXR6L3B5cHlrYXR6LnB5IiwgbGluZSAzMTYsIGluIGdldF9kcGFwaQogICAgZGVjLnN0YXJ0KCkKDQogIEZpbGUgIi91c3IvbGliL3B5dGhvbjMuOS9zaXRlLXBhY2thZ2VzL3B5cHlrYXR6L2xzYWRlY3J5cHRvci9wYWNrYWdlcy9kcGFwaS9kZWNyeXB0b3IucHkiLCBsaW5lIDc0LCBpbiBzdGFydAogICAgc2VsZi53YWxrX2xpc3QoZW50cnlfcHRyLCBzZWxmLmFkZF9lbnRyeSkKDQogIEZpbGUgIi91c3IvbGliL3B5dGhvbjMuOS9zaXRlLXBhY2thZ2VzL3B5cHlrYXR6L2xzYWRlY3J5cHRvci9wYWNrYWdlX2NvbW1vbnMucHkiLCBsaW5lIDE4MiwgaW4gd2Fsa19saXN0CiAgICBjYWxsYmFjayhlbnRyeSkKDQogIEZpbGUgIi91c3IvbGliL3B5dGhvbjMuOS9zaXRlLXBhY2thZ2VzL3B5cHlrYXR6L2xzYWRlY3J5cHRvci9wYWNrYWdlcy9kcGFwaS9kZWNyeXB0b3IucHkiLCBsaW5lIDU2LCBpbiBhZGRfZW50cnkKICAgIHNoYV9tYXN0ZXJrZXkgPSBoYXNobGliLnNoYTEoZGVjX21hc3RlcmtleSkuaGV4ZGlnZXN0KCkK

To presenting what it appears to be legitimate information. I can't say for sure that the output is indeed correct or if these changes work for many other builds of Windows. I hope you find this helpful and that I made it a little easier to better implement support for 32-bit Windows machines 😄

I have uploaded the minidump file that I used for this with the name: windows_10_x86_build_19043.dmp Let me know if I can help you with anything.

skelsec commented 2 years ago

Thank you very much for the detailed issue description and the minidump file. Functionality has been added in the newest release