Flare-On 2020: crackinstaller
crackinstaller.exe was a complicated binary that installed the Capcom.sys driver, and then exploited it to load another driver into memory. It also dropped and installed another DLL, a credential helper. I used kernel debugging to see how the second driver is loaded, and eventually find a password, which I can feed into the credential helper to get the flag. I spent over two of the six weeks working crackinstaller.exe, and unfortunately, I stopped taking meaningful notes very early in that process, so this won’t be much of a writeup, but rather a high level overview.
Challenge
What kind of crackme doesn’t even ask for the password? We need to work on our COMmunication skills.
- Bug Notice: Avoid a possible blue-screen by debugging this on a single core VM
root@kali# file ttt2.exe
ttt2.exe: PE32+ executable (GUI) x86-64, for MS Windows
Running It
I happened to be on a fresh Windows VM when I started this challenge, and on trying to run this, Windows Defender blocked it. Looking at the logs, it is calling this HackTool:Win64/CapRoot.A:
It also calls out crackinstaller.exe
as a containerfile, with the file in question being cfs.dll
.
Once I disable defender, running it pops a blank terminal for a second, and then it disappears.
General Notes
crackinstaller.exe
This binary drops a bunch of things. It has an init function that runs pre-main that will drop the famous Capcom.sys driver.
It then invokes the IOCTL call that basically loads user code into the kernel and runs it. I worked through both videos in this post and really learned a ton. Highly recommend.
For this binary, after installing the vulnerable driver, it uses it to load call code back in crackinstaller.exe
:
FUN_140002a10(?, 22B00BA7E00h, 5800h, 3170h)
In this function, there’s a lot of kernel memory pools functions to put a new driver into memory and an array of kernel functions into a second pool. these are passed to PsCreateSystemThread
:
PsCreateSystemThread(&hThread, GENERIC_ALL, 0x30, 0, 0, driver_in_memory.DriverBootloader, args[])
DriverBootloader
basically does some memory re-arrangements and calls IoCreateDriver(NULL, entry)
.
After installing the driver, it continues in main
, where it drops credhelper.dll
to disk:
Then it invokes the DllRegisterServer
export.
Unnamed Driver
I had to set up kernel debugging to see into the driver and what was happening. To do this, as I’m on a Linux host, I created two Windows VMs, and configured them according to this post.
The driver calls CmRegisterCallbackEx
which will register a callback function that will be invoked when the kernel conducts registry operations. It took a bunch of documentation reading to understand the various structs passed to this function, but eventually I figured out where the function that was invoked would be.
The callback handler checks that the operation is happening on a path containing {CEEACC6E-CCB2-4C4F-BCF6-D2176037A9A7}\Config
. It’s not totally clear to me what happens next, but a buffer is decrypted, and it contains what I’ll find is the password, H@n $h0t FiRst!
(a Star Wars reference).
Then it unloads the driver.
credhelper.dll
This DLL exports four functions and a main
:
The function called by crackinstaller.exe
is DllRegisterServer
. It basically creates a COM server with the following API calls:
RegCreateKeyExW(HKEY_CLASSES_ROOT, "CLSID\{CEEACC6E-CCB2-4C4F-BCF6-D2176037A9A7}", 0x0, 0x0, 0xf003f, 0x0, handle,)
RegSetValueExW(handle, NULL, 0, REG_SZ (1), "CredHelper", )
RegCreateKeyExW(handle, "InProcServer32", 0, 0, 0, 0xf003f, 0, hKey_InProcServer32, 0)
RegCreateKeyExW(handle, "Config", 0, 0, 0, 0xf003f, 0, hKey_Config, 0)
RegSetValue(hKey_InProcServer, NULL, 0, REG_SZ (1), fullpath_credhelper.dll, len(fullpath_credhelper.dll))
RegSetValue(hKey_InProcServer, "ThreadingModel", 0, REG_SZ (1), "Apartment", len("Apartment"))
It then creates two more keys:
RegSetValue(hKey_Config, "Password", 0, REG_SZ (1), [garbage], 2)
RegSetValue(hKey_Config, "Flag", 0, REG_SZ (1), [garbage], 2)
I spent some time playing with and understanding these functions. There’s a getPassword
function (offset 153c) that reads the password out of the password registry key, and generates crypto buffers in a global variable. There’s also a setFlag
function (offset 16d8) that uses the crypto buffer to decrypt something, and then writes that to the flag registry key.
The fastest way to get a flag is to debug in x64dbg
using rundll32.exe
(like here). It’s a bit hacky, but here’s the steps I took:
- Set debug to break on DLL load and run through loading
credHelper.dll
. - Run through
DllRegisterServer
by setting RIP manually and breaking on the return. - Manually set the Password registry key to using
regedit.exe
. - Set RIP to
getPassword
, set RCX to 0, and RDX to some address way up on the stack that’s not currently in use. As I step through this, I see how the 256 bytes of crypto stuff is generated at the address I set into RDX. - Set RIP to
setFlag
, RCX to 0, and RDX to that buffer address on the stack. Step for a bit, and the flag pops out:
Flag: S0_m@ny_cl@sse$_in_th3_Reg1stry@flare-on.com