In When Environmental Keying meets DPAPI I went over an example of using the Data Protection API (DPAPI) to encrypt data. Its cool, I guess, but I wanted to look at Environmental keying from a different perspective. So, I spent a day building a small/POC Python project to take in a bunch of environmental data in json, and recursively encrypt. In this post I want to touch on that a little.
There's no problem with taking a string, say the hostname, and passing it to some sort of AES encryption tool and then using the GetComputerNameA as the AES Key on the target. But that's not fun.
So, before I go into my horrible C++ and a bit of python, there are some older projects that can do this far more intelligently, as detailed in Keying Payloads for Scripting Languages:
One other disclaimer, I am terrible with cryptography. Please do not expect fancy Key Derivation Functions. The AES I use within this project is a PoC, so I just used the WinAPI encryption (more on that later).
Note on Guardrails
Execution Guardrails: Environmental Keying (T1480/001), is important because it causes the malware to remain in the scope of the engagement, as well as protect it from reverse engineering. For example, if Jim in HR sends it to Karen in Finance because it looks funny, and she opens it on her home machine, then we don't want that to execute, its probably out of scope. The more obvious benefit is that if the data is moved from the target environment, it will be difficult to reverse.
Typical Example
If you're on a target machine, the environmental keying used is almost entirely down to creativity. Some of which will make more sense than others, but generally speaking its down to being creative. With that said, the two obvious sources are Registry Keys and Environmental Variables, so they will be the ones I cover in this post.
Looking at the environmental variables, there is a whole bunch of data:
Same for the Registry, but that's way too awkward to show in one screenshot. As an example, I'll show a quick implementation of grabbing an environmental variable, using it as a key, and wrapping it all in python.
For the small POC, I'll just use an environmental variable. To grab that, there are several implementations:
I won't look into this too much because these set of calls are considered deprecated and are quite frankly just additional imports the PE doesn't need.
For some better C++ AES Libraries, see the following:
To make this a bit easier to work with, std::string is now being used, lets add this into the POC. Below is the updated code (with the AES component ignored:
As an example, this one grabs 4 environmental variables and two registry values. So the goal was to go through each of these and recursively encrypt. Like so:
A becomes B
B becomes C
C becomes D
And so on. Honestly, I don't see this having much more impact that decrypting with one environmental variable, but it was a fun project. A more ideal approach could be to combine them into one long key, XOR them all together, or use them all as valid keys as backup for one of the environmental keys changing.
PoC Project: Greta
This is where Greta is introduced. Below is the -h:
usage: greta.py [-h] [--debug] [--no-prints] [--output OUTPUT] [--sleep SLEEP] input configConvert environmental data to multiple layers of AES!positional arguments: input File to encrypt config Config file to parseoptional arguments:-h, --help show this help message and exit--debug Enable debug prints in output file--no-prints Remove all printfs--output OUTPUT Output file--sleep SLEEP Sleep for random time between 0 and arg (between "substantial ops")
When the required flags are set, Greta will produce a .cpp file with all the logic, and then embed all the environmental specific components. Check src/greta.cpp for the static logic.
Right off the bat, there are a few opsec weaknesses for it:
The strings are not masked, they're just there. An example:
The dynamic functions are just pulled from GetProcAddress and GetModuleHandle. I don't see this project actually being too useful, but if it did, something like DarkLoadLibrary would be a good project to replace some of that functionality. Here is the current function resolving:
The one type of string that isn't in the project, however, is the actual value being used to decrypt. To identify whether the string is in fact the correct one for decryption, Fowler–Noll–Vo hash function is being used; I also used this in Dynamically resolving hashed-NTAPI Calls. The code:
intfowler_noll_vo(std::string s){if (s.size() ==0) {return0; }int hva =38395996;int prime =61037065;for (int i =0; i <s.size(); i++) { hva = hva ^ (s.data()[i]); hva = hva * prime; }return hva;}BOOLcompare_fnv(int a,int b){if (a == b) {return TRUE; }else {return FALSE; }}
When it comes time to check the hashes, it is done like so:
One feature I do like to add into my tooling was inspired from DripLoader. Essentially just adding random Sleep() calls between actions. That is what --sleep does, it sleeps between 0 and the given argument (miliseconds):
Sleep is dynamically resolved and replaced with zzSleep:
This was a quick one on using AES and Environmental keys to guardrail some payloads. Greta was produced for this blog, but honestly it isn't needed for the recursive feature, one key is enough. As someone who is terrible at both crypto and c++, I'd probably suggest another mechanism for the key which gives a bit more control and redundancy in case any of these keys change during the implants lifetime. If there is some research I've missed, and haven't already linked to in this post, I'd love to see it.
If you end up using this recursive approach and want to make my c++ not terrible, I'd also love to see that.