Home

Awesome

Hermes

Hermes was a master communicator, and thus he was able to persuade everyone, god or mortal being.

Table of contents

Intro

Hermes is a PoC demonstrating how a UEFI module running in System Management Mode (SMM) can be used by a user mode process to elevate its own privileges higher than the kernel itself. This module is a continuation work on our previous UEFI module, which was a simple SMM rootkit.

If you want to read about SMM (rootkits) in general, please read the old blog post!

This version of the UEFI module contains the basic components to interact with the Windows kernel (find processes, get all modules of a process, get information about a process module and dump a memory range to file) or the basic memory procedures (read/write virtual & physical memory and convert virtual to physical memory). It can be expanded to include automatic forensic actions as example. A drawback of Hermes is the current timer execution. The chipset timer allows a execution every 64 seconds, which is enough for demonstration purposes. Finding another way to generate more frequent SMIs (System management interrupts) is left as an exercise to the reader.

Supports (at least):

As the user mode application itself does not interact with any of the processes or the memory itself as the SMM module is doing everything while the processor is in the system management mode, antiviruses or even the kernel itself won't notice the behavior but only the effects that were done (for example, through DKOM).

Created by Jussi Hietanen (Aalto University, Espoo FI) and Diego Caminada (HF-ICT, Muttenz CH).

Commands

CommandDescriptionInputOutput
gdReturns the directory base of the requested processProcess nameDirectory Base
gmdReturns essential information of the requested module in a processProcess name & Module nameModule name & Size
gmReturns all module names of the requested processProcess nameName of every module in a process
vrReads the memory at the requested virtual memory addressSource Virtual address, Directory Base & SizeMemory read at the address
vwWrites the supplied integer to the requested virtual memory addressDestination Virtual address, Directory Base, Size & Value-
prReads the memory at the requested physical memory addressSource Physical address, Directory Base & SizeMemory read at the address
pwWrites the supplied integer to the requested physical memory addressDestination Physical address, Directory Base, Size & Value-
vtoConverts a virtual memory address to physicalSource Virtual address & Directory BaseConverted Physical address
dmDumps the requested memory areaSource Virtual address, Directory Base, Size & File nameMemory read is written into the file
exitExits the client process--
helpDisplays the help about the commands--

Example videos

The following examples show basic usage of Hermes suite.

Dumping process memory

Hermes can be used to dump a memory range of a file, this is useful for reverse engineering of otherwise protected processes which can't be read normally or close automatically as soon as they detect a debugger or reverse engineering toolkit.

The following video shows Hermes in action dumping putty.exe:

https://github.com/pRain1337/Hermes/assets/26672236/61bbe457-ccd8-42e3-85d3-6191a58dc3ae

Reading Credential Guard protected memory

LsaIso.exe is the credential guard protected version of Lsass.exe which stores and protects credentials. Normal toolkits (for example cheat engine) are unable to read the virtual memory of LsaIso.exe as the windows hypervisor is blocking their access, Hermes fully bypasses this protection as it is not running under the hypervisor.

The following video shows Hermes reading LsaIso.exe memory:

https://github.com/pRain1337/Hermes/assets/26672236/f333d26c-bab3-4ffd-8b56-e47c612ac300

Detection

The following examples show ideas and approaches to detect the activities of SMM, but not in general malicious behavior. Most of these could be evaded by utilizing additional components in the SMM module.

MSR_SMI_COUNT

How it works

The MSR_SMI_COUNT increases every time there is a active System management interrupt. For the best functionality, an SMM module (rootkit) would want to get regular execution, which is not usual behavior.

By checking the counter, one can notice if an SMM module has enabled a timer and hence SMM gets more executions than it would normally get.

For instructions on how to read the MSR_SMI_COUNT see chipsec which also provides other useful information for analyzing UEFI/SMM.

How to prevent it

Spoofing an MSR is not easily done with SMM, the easiest approach would be to utilize a hypervisor to spoof the results of the MSR.

Using a hypervisor will of course end in a lot of more flags.

Side channel cache detection

How it works

Based on the idea of Nick Peterson which he presented in a Tweet to use side channels to detect reads of a memory.

H33p has created a replication of this project in rust, to test this claim.

The initial tweet only claimed detection from os or hypervisor, but we've tested it from SMM, and it was also able to detect it. It basically works by checking the access time to a predefined memory location. As long as no other application touches the memory, the cache duration should stay the same.

The test itself can introduce false positives if antivirus or similar applications are running on the system.

Old video with the private version of hermes (named atlas):

https://github.com/pRain1337/Hermes/assets/26672236/882325d2-1416-4c17-a36b-e7e73a517f1d

How to prevent it

This detection can be bypassed using the control register 0.

By setting the Cache disable and Not-write through bit before performing a read and disabling these afterward.

This results in a big performance hit as no caching is used anymore but the reads themselves won't be detected anymore.

UEFI Image analysis

How it works

The SPI chip holds the image which contains the SMM rootkit module, the chip itself can be read using manufacturer provided tools (for example afudos).

These images can then be analyzed using as example UEFITool.

How to prevent it

The easiest way is to simply just block the reading of the SPI chip utilizing the protected range registers.

For more information about how to achieve this, check out the x86-64 Intel Firmware Attack & Defense course by Xeno Kovah.

Blocking it of course leaves a red flag, as this is not expected behavior.

A better looking approach would be utilizing SMM as a Mitm to modify the read SPI data before it's passed to the user mode application.

This was already done by TakahiroHaruyama, for further information see SpiMitm.

Repository Contents

Hermes-SMM

Hermes-SMM is the SMM-side "server" component which allows client applications to elevate their rights.

Hermes-Client

Hermes-Client is a interactive console application which can be used to communicate with the Hermes SMM module.

Building Hermes-SMM

Prerequisites: docker, git

First time setup

Please skip to "Building Hermes-SMM" if you've done the first time setup already.

  1. Inside this git repo, clone the EDK2 submodule, it will init the right tag (vUDK2018) automatically:
git submodule update --init
  1. Pull the official "edk-builder" docker image
sudo docker pull jussihi/edk-builder

OR

Inside the Hermes-SMM -directory, run

docker build --no-cache -t edk-builder/edk-builder .

to build the edk-builder image locally.

  1. Inside the Hermes-SMM -directory, start the docker by running:
docker run -it --privileged -v .:/root/ -u root -w /root jussihi/edk-builder /bin/bash

or if you built the docker image locally:

docker run -it --privileged -v .:/root/ -u root -w /root edk-builder/edk-builder /bin/bash

Now inside the docker container, run

# cd edk2 
# make -C BaseTools
# . edksetup.sh

To set up the base tools. First time setup is done!

Compiling Hermes-SMM

To build the Hermes SMM module, start the docker instance again in Hermes-SMM directory with the following command:

docker run -it --privileged -v .:/root/ -u root -w /root jussihi/edk-builder /bin/bash

or if you built the docker image locally:

docker run -it --privileged -v .:/root/ -u root -w /root edk-builder/edk-builder /bin/bash

Inside docker container, copy Hermes source files to the edk2 folder:

# cp -r Hermes-src/* edk2/

Still inside the running docker instance, you can proceed to building the edk2's OVMF with SMM modules enabled

# cd edk2
# . edksetup.sh
# build -DSMM_REQUIRE

The resulting OVMF firmware will be inside edk2/Build/OvmfX64/RELEASE_GCC5/FV.

For running it on real hardware, you'll have to patch PiSmmCpuDxeSmm. Modern SMM protections setup by edk2 will produce a fault otherwise when accessing normal OS memory. Check out How to patch PiSmmCpuDxeSmm

Building Hermes-Client

To build the Hermes-Client you need to use visual studio instead of docker.

Simply open the Solution file and compile, you might need platform/sdk/toolset on the project file first.

The default settings compile a x64-86 application for windows.

Troubleshooting

This version was developed for and tested on the Intel z690 chipset, it should still work on older/newer chipsets as very few offsets are changed.

The SMM module itself also works in a virtualized environment, although some of the native chipset feature it uses (SMI timer) are not available there.

If the SMM module is not working as expected, you can use the inbuilt serial functions to send text/numbers out. This even works, if the SMM module produces a General Exception which halts the system.

FAQ

How to patch PiSmmCpuDxeSmm

If you are trying to run this SMM module on real hardware, you need to patch your motherboard's PiSmmCpuDxeSmm module from the UEFI firmware. You can mimick our patch by Patching this variable initialization out and hard code the variable itself to 0 with your favorite disassembler (IDA or similar):

https://github.com/tianocore/edk2/blob/master/UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c#L352

Easiest way to find that function (SmmInitPageTable) is to search for the strings of the error messages:

https://github.com/tianocore/edk2/blob/master/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c#L265

Which is referenced multiple times in the SMI Page fault handler:

https://github.com/tianocore/edk2/blob/master/UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c#L1003

And the page fault handler is initialized in the same function as the variable initialization (SmmInitPageTable):

https://github.com/tianocore/edk2/blob/master/UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c#L442

No serial output after boot

Sometimes the serial traffic is blocked because of the operating system's own serial driver. This is at least the case in Windows systems when not booting inside a (QEMU/KVM) virtual machine.

There are two ways to get serial working on this sort of situation:

On GNU+Linux, you can disable the driver completely if one is loaded. On Windows systems, you might need to rename/delete the system's serial driver. The default path to the driver executable is C:\Windows\System32\drivers\serial.sys.

You can also open the connection to the local serial port using your favorite serial client. At least on Windows this will prevent Windows own driver from suppressing the serial output.

Sources

Sources used while building the rootkit as inspiration and their usage: Basic inspiration for this project - SmmBackdoor

Used for windows structures and memory functions - vmread

Interaction with the os and interacting with it - pcileech

License

All of the code in this repo (excluding other work from pcileech, vmread..) is licensed under GPLv3, since this repo is for educational purposes only.

This means that any project using even parts of the code presented this repo should also be open-sourced following the guidance found from the GPLv3 license.