Here's an implementation of a persistence technique found in Vault 7 that stores data in NVRAM variables. Data can survive OS re-imaging and cannot be enumerated with OS-level APIs. Requires admin.https://t.co/zyc4OnUZMO pic.twitter.com/58xeVkb9e3
— Jackson T. (@Jackson_T) November 17, 2019
Click on the URL in the above Twitter URL, as WordPress chokes on Github Gist URLs.
GospelRoom: Data Storage in UEFI NVRAM Variables
Behaviour
Persist data in UEFI NVRAM variables.
Benefits
- Stealthy way to store secrets and other data in UEFI.
- Will survive a reimaging of the operating system.
- NVRAM variables cannot be directly enumerated with OS-level APIs.
- Enumeration requires exact knowledge of variable names and their GUIDs.
Caveats
- Computer must have UEFI enabled, legacy BIOS will not work.
- Administrative access required (
SE_SYSTEM_ENVIRONMENT_NAME
privilege). - Buffer size is limited up to the size of the flash chip.
- Possible to enumerate from kernel mode.
Example Output
[SET] TestVariable: Hello, NVRAM!
[GET] TestVariable: Hello, NVRAM!
References
/** | |
* Codename: GospelRoom | |
* Technique: Data Storage in UEFI NVRAM Variables | |
* Author: @Jackson_T | |
* | |
* Behaviour: Persist data in UEFI NVRAM variables. | |
* | |
* Benefits: | |
* 1. Stealthy way to store secrets and other data in UEFI. | |
* 2. Will survive a reimaging of the operating system. | |
* 3. NVRAM variables cannot be directly enumerated with | |
* OS-level APIs. Enumeration requires exact knowledge of | |
* variable names and their GUIDs. | |
* | |
* Caveats: | |
* 1. Computer must have UEFI enabled, legacy BIOS will not work. | |
* 2. The user account that the app is running under must have | |
* the SE_SYSTEM_ENVIRONMENT_NAME privilege (admin required). | |
* 3. Buffer size is limited up to the size of the flash chip. | |
* | |
* Example output: | |
* – [SET] TestVariable: Hello, NVRAM! | |
* [GET] TestVariable: Hello, NVRAM! | |
* | |
* References: | |
* – https://wikileaks.org/ciav7p1/cms/page_31227915.html | |
* – https://wikileaks.org/ciav7p1/cms/page_26968084.html | |
* – https://docs.microsoft.com/en-us/windows/desktop/api | |
* /winbase/nf-winbase-getfirmwareenvironmentvariablea | |
* – https://www.youtube.com/watch?v=q2KUufrjoRo | |
* – https://github.com/perturbed-platypus | |
*/ | |
#include "stdafx.h" | |
#include <Windows.h> | |
// Caveat #1: Check if system supports UEFI. | |
int IsFeatureSupported() | |
{ | |
int buffer; | |
GetFirmwareEnvironmentVariable(L"", L"{00000000-0000-0000-0000-000000000000}", &buffer, sizeof(buffer)); | |
return (GetLastError() == ERROR_INVALID_FUNCTION) ? 0 : 1; | |
} | |
// Caveat #2: SeSystemEnvironmentPrivilege needs to be set. | |
int SetSystemEnvironmentPrivilege() | |
{ | |
typedef NTSTATUS(WINAPI* RTLADJUSTPRIVILEGE)( | |
_In_ ULONG Privilege, | |
_In_ BOOLEAN Enable, | |
_In_ BOOLEAN CurrentThread, | |
_Out_ PBOOLEAN Enabled); | |
HMODULE hnd_module = LoadLibrary(_T("ntdll.dll")); | |
RTLADJUSTPRIVILEGE RtlAdjustPrivilege = (RTLADJUSTPRIVILEGE)GetProcAddress(hnd_module, "RtlAdjustPrivilege"); | |
ULONG SeSystemEnvironmentPrivilege = 22; | |
BOOLEAN enabled = false; | |
RtlAdjustPrivilege(SeSystemEnvironmentPrivilege, true, false, &enabled); | |
return (int)enabled; | |
} | |
// Convert the variable name to GUID for convenience. | |
// Modify this function as appropriate. | |
wchar_t* ConvertNameToGuid(wchar_t* name) | |
{ | |
// Compute DJB2 hash of name. | |
DWORD hash = 5381, c; | |
while (c = *name++) | |
hash = ((hash << 5) + hash) + c; | |
wchar_t* guid = (wchar_t*)malloc(100); | |
swprintf_s(guid, 100, L"{%08X-1337-1337-1337-1337%08X}", hash, hash); | |
return guid; | |
} | |
// Persist a buffer in NVRAM. | |
int SetVariable(wchar_t* name, void* buffer, size_t size) | |
{ | |
wchar_t* guid = ConvertNameToGuid(name); | |
return SetFirmwareEnvironmentVariable(name, guid, buffer, (DWORD)size); | |
} | |
// Retrieve a buffer from NVRAM. | |
size_t GetVariable(wchar_t* name, void* buffer, size_t size) | |
{ | |
wchar_t* guid = ConvertNameToGuid(name); | |
return GetFirmwareEnvironmentVariable(name, guid, buffer, (DWORD)size); | |
} | |
int main() | |
{ | |
wprintf(L"GospelRoom: Data Storage in UEFI NVRAM Variables\n\n"); | |
if (IsFeatureSupported()) | |
{ | |
SetSystemEnvironmentPrivilege(); | |
wchar_t* set_buffer = L"Hello, NVRAM!"; | |
wchar_t* get_buffer = (wchar_t*)calloc(wcslen(set_buffer), sizeof(wchar_t)); | |
SetVariable(L"TestVariable", set_buffer, wcslen(set_buffer) * sizeof(wchar_t)); | |
wprintf(L"[SET] TestVariable: %ls\n", set_buffer); | |
GetVariable(L"TestVariable", get_buffer, wcslen(set_buffer) * sizeof(wchar_t)); | |
wprintf(L"[GET] TestVariable: %ls\n", get_buffer); | |
} else { | |
printf("ERROR: This feature is not supported."); | |
} | |
return 0; | |
} |