In recent times i have become interested in how infostealers work so well even with modern systems security features, so i took a look at how underground market infostealers operate and tried to reproduce some of the most important features. In this post im going to show how i wrote a working proof of concept of an infostealer in CGO.

This is just for educational purposes only, you should not use it without authorization... Foremost as the author im saying this is just a POC and it lacks of sophistication so its not a good idea to use it in real world enviroments, you are more than welcome to fork it and recreate your own, as you will se trought the post the code is very comprehensive as its majority is written in golang

Hurdles

The biggets hurdle to overcome while developing such software is probabily encryption. Modern version of OSs and browsers all use encryption to safely store sensitive data, the great news is that everything is stored locally in the machine, you dont need to breach into nothing you just have to bypass the encryption mechanism of your machine/browser

There are obviusly other obstacle to overcome but those are generally more related to the concept of malware.

Microsoft DPAPI

Windows by itself implement Data Protection API for data storage security

Every application inside the system can have access to this API and use it to secure store their data, however dpapi has a big weakness: In order to access it someone only need to work from the user context, this mean that every medium-integrity process running in the user session can easily decrypt data using CryptUnprotectData function

DPAPI key generation:

User log in -> DPAPI generate master key -> m.key encrypted with users password hash

Encryption:

CryptProtectData() -> Gen random sess. key -> encrypt data with sess. key -> return encrypted blob

Decryption:

CryptUnprotectData() -> decrypt sess. key with m.key -> decrypt data with sess.key -> return plain text

This was all that Chromium based browser were doing to store data inside PCs before v20

App Bound Encryption

Google has rised the bar introducing App Bound Encryption

This ensure that only the elevated services can decrypt the stored data and only the browser process can request to decrypt the data.

Now, google recognize the fact that this architecture is not 100% secure, they them self said that a succesfull bypass would be process injection or an elevated instance of the malware, but as it is right now this work fine and achive its purpose

This is a high level overview of how ABE encryption work:

To better understand we can have a look chromium source code

Usage of validation_data:

Usage of data_to_encrypt:

Double layer of DPAPI encryption:

The decryption is what we have just said but in reverse + the path validation if specified. Everything is then stored inside \Local State file as os_crypt.app_bound_encrypted_key.

There are some known bypass to this:

As you will my program use a simple implementation of dll injection

Bypassing ABE using injection

The plan for bypassing ABE encryption includes 2 components: A function working as injector and the dll to inject. What the program will achive is decrypting sensitive informations stored inside browsers appdata folder using the IElevator COM object

This methodology is highly effective beacouse it allows the dll to initialize the COM instance using chrome CLSID_Elevator from the browser context

Injector function:

Dll injected:

Dll Injection

This function is pretty straightforward, you inject a dll inside browser process spawned with the --headless argument

InjectDll will then get the handle to the new instance of the browser, allocate as much memory as the length of the dll path, write the dll inside the allocated memory and load it creating a new thread with LoadLibraryA as a argument

To make this more sophisticated someone could try some sort of Dll hijack or reflective Dll injection

Payload Dll

Majority of the dll code i have used is been taken from this public POC

The first thing (and probably the last) you want to do inside DllMain is to call CreateRemoteThread to execute the main logic. The routine executed by the thread will:

In order to start the ABE key extraction you need to **initialize the COM instance** for the IElevator object

You initialize the COM interface with CoCreateInstance specifying the CLSID for the ChromeElevator class and the IID for the IElevator interface. The CLSID is not the same for every chromium based browsers.

After that a proxy is initialized, this allows comunications between chrome.exe and the COM object of the elevation service

Now its time to extract the ABE key from its original position

This function will retrieve the folder of Local State (%LOCALAPPDATA%\Google\Chrome\User Data\) copy its content inside an allocated buffer and start parsing its JSON content in search for the value of the app_bound_encrypted_key, finded the encrypted blob is base 64 decoded and saved inside the heap.

Using the encrypted blob now its time to decrypt it using IElevator::DecryptData

This will return a 32 byte AES key

Finally its time to extract logins, cookies, cards...

Browsers store sensitive data in AppData folder (%LOCALAPPDATA%\Google\Chrome\User Data\Default\) inside sqlite databases, accordingly we will need to interact with it trough the C code. For this you can just use the sqlite3.c and sqlite3.h of this repository.

All encrypted data blobs have a specific format:

| prefix: "v10/v11/v20" | | nonce: 12 byte | | Ciphertext | | Auth tag: 16 byte GCM auth tag |

Here you can clearly see the "v20" prefix, we can use this inside the code to see which version of chromium the browser is using and adapt the extraction strategy based on that.

This is the classic way to interact with a sqlite database in C:

The executed query to retrieve logins is the follow:

SELECT action_url, username_value, password_value FROM logins

Rows and tables name remain the same for every chromium based browsers

Now its time to decrypt the values returned by the query

First we are going to parse the encrypted blob of AES-GCM

We are using the decrypted ABE key with the Windows Cryptography API: Next Generation, for this you will need to import bcrypt.h in your code

After this everything is done and we have finally the decrypted logins.

Adding support for other browsers

For adding support to more browser we can compile as many dll as browsers we want to support, once the program start it will enumerate all the browsers on the file system and request only the necessary dlls from a remote server

There are a few minor differences to watch out for from one browser to another, one of them is the CLSID and IID, to make sure you are using the right one you can check the specifics for the browser with OleView

Other than this remember to change the %APPDATA% in order to match the one with the supported browser

Conclusion

There are more things to cover but i wont do that now, you can find the full program code here

Other functionalities not described in this post are inside the program on Github, go check it if you are interest!

Useful links: