Shellcode Execution via EnumSystemLocalA
This post covers a shellcode execution technique that leverages the UuidFromStringA and EnumSystemLocalA APIs to load and execute shellcode
Last updated
This post covers a shellcode execution technique that leverages the UuidFromStringA and EnumSystemLocalA APIs to load and execute shellcode
Last updated
NCCGroup published an excellent research article covering a mostly unknown shellcode execution technique that was being used as part of campaign which is believed to related to the Lazarus Group. The shellcode execution technique uses the UuidFromStringA
and EnumSystemLocalA
APIs to load shellcode into memory and then execute it. This approach avoids the use of suspicious API calls such as WriteProcessMemory
, CreateThread
and VirtualAlloc
.
The full blog post from NCCGroup can be found here:
The rest of this blog post is about experimenting with the technique covered by NCCGroup. For the most part there is no additional insight/information than is already covered in the references blog post.
The shellcode execution technique revolves around the following steps:
Allocate Target Memory via HeapAlloc
(or VirtualAlloc directly if you wanted to)
Use UuidFromStringA
to convert UUID strings their binary format and store in memory
Use EnumSystemLocalA
to execute the shellcode previously loaded into memory
HeapAlloc
is a common API call to allocate a block of memory on the heap. My understanding of this API is that is allows you to allocate specific amount of memory on the heap, unlike the blocks of memory that you get by using the VirtualAlloc API. However, documentation suggests that HeapAlloc
can still call VirtualAlloc
itself if required.
As noted in the NCCGroup blog post this API call:
Takes a pointer to a UUID, which will be used to return the converted binary data. By providing a pointer to an heap address, this function can be (ab)used to both decode data and write it to memory without using common functions such as
memcpy
orWriteProcessMemory
So by calling this API and providing a pointer to a memory address - instead of a pointer to a UUID - the resulting binary representation of the provided UUID will be stored in memory. By chaining a series of calls to this API together and providing specifically crafted UUIDs we can load our desired content (shellcode) into the specified memory region.
To examine how this works, we use the UUIDs used in the NCCGroup blog post as an example and decode them manually. We can run a quick and dirty python script to convert them into their binary representation:
After running the script and opening the resulting output.bin
file in radare2, we can see that it appears to be valid 64bit shellcode which will use the WinExec API to execute calc:
If you interested in what this shellcode does line by line you can find a commented version of the shellcode here.
Now that we know how the shellcode is loaded into memory from the UUID strings, we can look at how the EnumSystemLocalA
API call is utilised to execute the shellcode:
Looking at the documentation for the API call we can see that it essentially takes a pointer to a callback function. By providing the memory address of our shellcode we can use this function execute it.
Now that we know how the technique works, we can pull together some PoC code. However, before we do that we need to be able to convert our desired shellcode into valid UUID strings. Fortunately this is easy to do with the following python code:
We can generate some example shellcode - which will execute notepad - by using msfvenom
and then converting the shellcode into UUIDs using the python script above:
Now that we have our shellcode in UUID format, we can write our PoC code to test:
In the PoC code above we still use OpenProcess, VirtualAlloc and VirtualProtect which are typically viewed as suspicious. In the Lazarus samples these calls were replaced with a reference to HeapAlloc. The NCCGroup blog post contains code showing how this is done.
Compiling and executing our code shows that the technique is successful and notepad is successfully executed: