 Okay, so, well, there's been a lot of, well, should I say, there's not been a lot of information about the Windows boot system, just mainly diagrams at a high level really, some stuff in Windows internals, that kind of thing, so basically what I'm going to do is I'm going to basically mention exactly what a Windows boot application is, basically explain what security features there are, namely security mitigations and actual features added for security in chronological order, and I'm going to go through all the bugs that have ever been found. And here I'm talking about the Windows boot application starting from Windows Vista onwards, so anything explained before is out of scope here. So, the Windows boot environment contains a number of applications, they're just PE files with a special PE subsystem, but as you probably know, the boot manager can load straight from the EFI environment because it's linked with a stub that sets everything up from the EFI environment and then calls the actual entry point. And there's this library that everything's directly linked with, which contains everything it needs to do that isn't application specific. All boot applications officially released by Microsoft are linked with this library, which keeps getting bigger just in the next Windows 11 release. It's basically had its biggest increase since Windows 8. So, let's talk about where security mitigations aren't. You may have seen a tweet going around about how if you were exploit God in the 90s, your old skills are still useful because bootloaders don't have any of this stuff. Well, it has no stack cookies. There's also no physical ASLR. Well, kinder. It depends what the UEFI firmware does, really. But even then, when a boot application knows another, it'll just load it at the lowest possible address, which can be changed. You can, by settings. Until very recently, if a boot application knows another, there's no memory protection. Even then, even though it's been added in the latest release of Windows 11 that's yet to be released but has RTN, it relies on some API that's in Mew. And as far as I can tell, not in EDK 2 yet. So, if a lot of systems still won't have memory protection there. But, however, there are some things that have been done well. For example, the heap implementation is actually hardened. And all heap buffers are zeroed when they're freed, which is good. Well, bad if you're trying to exploit something. However, if you do get a heap overflow, then there's no panic. It just says, oh, this is corrupt. Let's just allocate some more physical memory. Static analysis also gets performed on the code base and probably fuzzling as well. I've looked, there's no easy exploitable low-hanging fruit, stack overflows, et cetera, which is good because if there was one, you'd be just exploiting it like it's the 90s. So, let's talk about features here. In chronological order, first implemented was signature verification, then bit locker during visitor development, then measured boot during Windows 7, and finally UEFI secure boot during Windows 8. See, the verification is done using a common library that is shared between boot applications and ci.dll, but the slightly different implementation is used there. All signature checking leads to one function that passes the structure and verifies everything and goes into another function that validates all certificates in the chain. Root certificates are pinned by name. If your certificate chains back to a certificate with a name that's in the root certificate list, it will use that public key. And if everything is valid, then the information gets passed back to the caller, so the caller knows who signed this, is it a test signature, is it production, et cetera, was it a UEFI key, et cetera, et cetera. Since Windows 8, one certificate is revoked always, well, I say always, the pre-release certificate was used before the release candidate and is still used today for certain purposes. I believe all checked bug builds of Windows from Windows 8 also use it. If test signing is enabled, it's not revoked, and if a secure boot policy says it shouldn't be revoked, then it won't be revoked. However, if your binary is flight signed, then it will ignore that revocation and in fact will ignore any certificate revocation if it chains back to that certificate, even if it's revoked by DBX or something. So, let's talk about revocation separately because the original way to revoke stuff was a revocation list signed by a certain certificate that can revoke stuff by hash and can also revoke all flight signed binaries prior a certain time, but that's never been used as far as I can tell. The support is there, though. When secure boot is enabled, it's stored in UEFI variable that isn't signed, so if you have a secure boot bypass or code execution and before exit boot services at all, you can change it, but at least it gets measured to the TPM. DBX is only used for everything starting with Windows 10. Before then, DBX was only ever used when loading secure boot policies, which I'll get to. The revocation list of choice today is the SI policy. SI policy has got a load of names. I think it's now called the Windows Defender Application Guard or something, but the internal name is SI policy or CI policy, both are used. I think that's system integrity or code integrity policy. Now, when you have bitlocker enabled with a TPM in use, the on-disk metadata contains hashes for every boot configuration element for each boot entry and hashes of all allowed boot applications to run except for certain things. Certain elements starting from Windows 8 basically don't have a hash. They just have, oh, this needs to be present, so if you add an element that isn't in the list, then bitlocker goes into recovery mode, same if you change the element that's hashed. However, when secure boot is enabled, then it uses the secure boot policy instead. Again, I'll get to that, but that means it's now a strict block list rather than an allow list and you can change boot elements however you like. The key table is stored in memory and its physical address is passed across by an internal boot element. One of the good things that happens here is if you set up a boot debugger or if you open the advanced options menu somehow or the edit options menu somehow without going through the boot manager stuff which asks for recovery mode, then that key table gets completely zero even all copies of keys are wiped from memory. When loading a boot application, the boot manager will cap PCR 11, so only the first instance of a boot manager can unseal the VMK from the TPM, which means you can only derive the key if you've got code execution inside boot manager or if you get code execution afterwards with the key still in memory. Now, measured boot is interesting because everything gets added to a linked list in memory at first and then when the library is getting freed then everything in memory gets actually measured, which means if you get code execution in a boot application then it's before any events here measures actually get measured to the TPM. However, boot debugging will instantly extend everything because boot debugging was implemented really early and they actually cared about security then it seems. Now, UEFI secure boot is an interesting one because the way it was implemented was with a secure boot policy that I've previously mentioned. It's signed by Microsoft from either UEFI variable, boot services only, or from disk after 2016 or if none of those are present, it uses a default one that's from the boot manager's resources. On Windows 10 before 2016, so the original release and the November update, you can actually sign a policy by your systems platform key. This was originally intended for Windows on ARM V7 OEM, so service RT, et cetera, so they could disable UMCI for repair purposes, et cetera. They got a executable that basically had two policies in it and basically they'd run it on a system, it's bit out of policy for a specific device and they could sign it. Again, before 2016, for all Windows versions at this point, if a policy is signed by Microsoft, it must came back to a certificate that's allowed by secure boot. This was to prevent Windows phone policies from being used on non-Windows phones and vice versa, but this code got removed in 2016 for whatever reason. Since 2016, it can load multiple policies and build them up. So you'd have a base policy that allows a number of additional policies to be loaded. Before then, but Windows 10 before then, can still load one additional policy from disk which was used on Windows phones. Again, a policy can be tied to a specific device by either a 64-bit copy of device ID variable or 256-bit unlock ID. If the policy is signed by a systems platform key, then the policy must be device unique. However, if you're in a position to install such a policy, you're also in a position to change the copy of device ID anyway. The policy gets passed across boot as a block of physical memory with type persistent data which is used for that and a couple of other things. If a custom policy is loaded, as in the policy loaded isn't the one from the boot manager resources, it gets extended immediately to PCR7 which contains basically the state of secure boot that it's enabled and the certificate of whatever, the certificate that validated the load for the boot manager. So if you change the secure boot policy, then BitLock will go into recovery mode. Now, I've been talking about secure policy. What's in it? It's got a set of interesting flags. It could allow the pre-release signed binaries or kit signed binaries, that stuff for Windows 8.1 and R9-V7 which is specifically done to stop a jailbreak. It can enable UMCI unconditionally on systems that would not have enabled it otherwise. It can also prevent allowing a physically present user to enable curl debugging or disable signature verification that's used on all R9-V7 systems, Windows RT or Windows Phone or anything else actually. It can also enable flight signing unconditionally, no matter what the BCD says, if the CI policy allows it. There's also a list of BCD elements which basically overrides whatever is in the actual BCD so it can change what's there or it can be an element that says this isn't allowed, if it's present, then always return not found or it must be present, that is, from a running system, you can't delete it. This is used to prevent dangerous things from happening when secure boot is on. In your presence for a device element, that is, the operating system device or whatever will force the Maxi to be the device that the boot application was loaded from. If you change the device related to Windows Restore from Hibernate, it will instead get forced to the device that the WinResume application was loaded from. It also has a list of internal settings. The most interesting of those is the ability to change the allowed route to tip codes for every kind of binary which persists into the running system. Oh, now you can just sign your own WinTBCB protected process if you want to. So, let's start talking about the security issues that were found. The first one was found in 2015 by Miria in WinLoad. It's a unicode truncation bug. That is, the NT kernel allows has arbitrary arguments. Those are in ASCII format. The BCD string elements are unicode. WinLoad just stripped the high bytes after checking against the list of dangerous options. So, you can enable test signing post boot. This was fixed by converting to ASCII before checking against the list. This was mainly used for Windows on ARM jailbreaking. The second issue is a supplemental security policy issue that was found by Miria and a friend a few years ago. Note how it's got three CVEs. The first package is required to fix it. Namely, I said that supplemental policies were added in Redstone 1. They were originally signed using the same SM1 object identifier which means previous boot managers that didn't know anything about them could load them. There was no check. Initially, the check was added later. Earlier versions had no check anyway. And some production signed policies were uploaded to Windows update servers. Some of them had interesting settings, but one of them had none at all. That's enough to break secure boot. The first package revoked them all and then they started to use a different object identifier for them so older bootloaders couldn't load them. The second package revoked all the vulnerable boot managers that could load a policy from disk because they could actually do something about the UEFI variable because it was boot-surfed only, whereas they couldn't if it could load from disk. The third package rotated the variable so it uses a new name now. So any vulnerable binary cannot load any policy, but because the old one was revoked by writing an authenticated value to it, this relies on OEMs actually implementing UEFI firmware properly, and several did not. For example, on the Windows alarm side, the Tegra 3 UEFI firmware set variable implementation in trust zone only allows authenticated writes to a specific allow list of variables. Also, the package happened to brick some Lenovo servers at the time. Next up. Oh, no CVE. That's interesting. Basically, every once in a while, a bug gets fixed in newer Windows versions and doesn't get backported and it gets fixed silently. This one didn't make it to a final release of Windows. I noticed it when reversing and it was fun to explore. Basically, in 2016 a physical platform manifest was released. This was many to say, old phones can't load desktop stuff because phones need bare security. If you know anything about Windows phone security, then you're laughing already. If you don't, then even before the early boot load of bugs happened, it was very simple to get code execution as a system on a Windows phone. Anyway, the signature validation library was modified to pass something from authenticated attributes back to the caller. They put the code in the wrong place and overwrote the result of the certificate chain checking function before it got checked, which means you can easily fake sign. Now, here's the new one. There's a BTD element that's used before the security policy gets initialised. It may be in memory at this point, but the loading boot application doesn't know about it yet. It causes all memory above a specified physical address to be removed from consideration at all. Anything in that memory area is basically freed. You can just use it to remove a loaded security policy across boot applications. This was fixed by adding some checks, which basically ensures that a policy is loaded if it should be loaded. So, there's this bug. How is it exploited? The security policy needs to be allocated above a certain point. Before 2016, this was only possible by using a BitLocker encrypted operating system volume with TPM or something that fakes that. You can fake a VHD to look like that, because BitLocker plus TPM is just bit zero setting VMK key flags, and the boot applications will just consider that, oh, it's a TPM. The allocation happens after the boot application gets loaded since 2016, because of the feature I mentioned before. So, there's a VHD element that causes all physical memory allocations to be above a specified address. If virtualisation-based security is enabled, you can't use it, but it's used during memory management initialisation, so you just load a boot manager from boot manager. However, they've disallowed that now. That was part of the fix. So, when you're loading boot manager by boot manager, there's an undocumented BCD element that can be used to specify a different BCD path, so you can make it use a different BCD than the initial boot manager instance. The simplest proof of concept fits in a tweet, which was nice. And assuming you're on an X64 system of hardware virtualisation, if you load the Hyper-V loader with disabling integrity checks, then it will load a self-signed microcode update, DLL, and call its entry point in the context of the Hyper-V loader before exit boot services. I've already mentioned that basically prevents TPM-measured boot from happening. The only thing that the TPM will have measured is the Hyper-V loader executed, but nothing after that. Also, if you load a Windows loader from a major version of Windows before the original November updates of Windows 10, so the original release of Windows 10 or before, enabling test-signing will allow self-signed binaries if that certificate has the Windows file EKU. Again, this will load a self-signed microcode update. It will also load it if you're not on X86 or X64. You just need to patch a file to import from mcupdate.dll and it will load it and then run it. But I've not talked about Bitlocker yet. The microcode update DLL will after all load from the operating system device and you don't have the keys for that. There's a few methods that you can load from a different operating system device. I'm not going to mention any of them because none of the vulnerable binaries have been revoked yet. I don't want to give an evil male attacker a free lunch here. After all, they can just bring their own vulnerable bootloaders. Of course, if all the vulnerable binaries get revoked, that's almost 10 years of vulnerable binaries, including Windows installation and recovery media and backups. Because I mentioned DBX was only used dying with Windows 10, that's two times revocation and DBX is already almost half full thanks to the boothole grubbugs. Given that code execution is obtaining a second-stage boot application, it's essentially a boot that is executed after the user has entered any second factor for a bitlocker volume. Also, when the TPM is used as a bitlocker key protector, you can't swap a Windows 10 boot manager of a Windows 8 one because Windows 10 caps all PCRs so the unseal will fail. However, you can gain code execution in Windows 8 boot manager, disable virtualisation-based security and then exploit it with Windows 10 one. I'm going to switch to a video that shows bitlocker key dumping in a VM. Bitlocker keys dumped. Additionally, I said that the boot manager was disallowed to be loaded for a boot manager. They also disallowed the Hyper-V loader except they changed the original file name in 2016. That patch caused Hyper-V loader to fail because they stopped it from running. Also, that fixed another trivially exploitable issue. The only use for it is bitlocker key dumping. Anyone who's bothered to bind if that patch probably knows about this already just by figuring out what could be done with this. But anyway, boot manager, when initialising set a specific bit flag which causes any... Basically, it means don't use the bitlocker keytapel in memory, create a new one, it leaves the old one in memory. So, you can then boot to WinPE and use a known vulnerable driver to find your existing keytapel and dump it. Not only that, you can fiddle around with the WinPE and get the drive to mount there. As you can see, there's WinPE with the operating system volume unlocked. Yeah, it's only got TPM as key protector. So, what can be done with this? You always want to use legacy integrity validation for bitlocker. There's a registry entry. And you want to configure it to use PCR0247. That's a non-default one, and 11. So, any change will cause bitlocker to go into recovery mode and Secure Boot will also be enabled providing its benefits. If you trust Microsoft, Secure Boot will always be bypassable unless all vulnerable binaries are evoked. Of course, Microsoft is in charge of all the revocation lists, but the keys will be rotated in 2026. So, maybe we can wait for that. Oh, and there was a bug that was fixed last month. Let's take a look into that. It's an issue in legacy bitlocker integrity validation. Somehow I didn't notice it before the patch, amazingly, because the implementation was completely incorrect. They walked associated options and used the wrong base for the offset. So, it was reading some other data. So, potentially a tag. You could add boot options for an application entry without them being hashed or known about by bitlocker. That bug seemed to date back to Vista Service Pack 1. I have no idea who discovered it. There was no mention of any discoverer. Probably was just revealed anonymously. I've been diffed in five minutes. If you have questions, then I'll be around... What? How much? Okay. So, I'll be around Milaway's and Oram field effects.