Ivy v1.12 releases: payload creation framework for the execution of arbitrary VBA source code in memory
Ivy
Ivy is a payload creation framework for the execution of arbitrary VBA (macro) source code in memory. Ivy’s loader does this by abusing programmatical access in the VBA object environment to load, decrypt, and execute shellcode. This technique is as close as possible to be truly fileless, as most fileless attacks these days require some sort of files being dropped on disk, as a result bypassing standard signature-based rules for detecting VBA code. Typical VBA payloads have the following characteristics:
- Exist in Macro enabled Office Documents
- These Macro Documents exist on disk
By running purely in memory, these behavior characteristics makes it harder to be detected by EDRs.
Ivy’s loaders are encrypted using RC4 encryption (AES encryption causes a lot of bloat and takes forever for VBA to decrypt) and then broken into separate strings, preventing any sandboxing from recognizing these strings as encrypted strings that should be investigated. This also prevents any decoding mechanism from recognizing these payloads as anything but garbage characters.
Ivy’s loader first performs a registry query to enable “Trust access to the VBA project object mode”. This registry key value is stored in user-mode which allows the user to modify the value without requiring any elevated permissions. The registry value is set from a zero to 1; if the registry key does not exist Ivy will create it with a value of “1”. With this value enabled, programmatical access is allowed to the VBA object environment from a different process.
Once this is done the loader will then spawn a hidden Excel process and load the encrypted strings into a VBA function. This is done by using ActiveX to simulate the GUI actions of doing the same task. This helps bypass a lot of traditional controls in place to monitor for execution. As a result, the decrypt function and shellcode are moved from one memory buffer to another, never touching the disk. Finally, the loader uses command-GUI calls and executes the run function, which simulates the act of clicking on the run macro button in the GUI panel of VBA, beginning the decryption function, followed by the actual execution of the shellcode.
IMPORTANT
The target endpoint must have Microsoft Office installed and activated in order to run because Ivy relies on abusing the programmatical access to the VBA environment of Microsoft office.
EDR Unhook Mode
This allows Ivy to use low-level system calls to build its own version of the Windows function WriteProcessMemory by referencing the direct memory address and register values indirectly. Ivy can overwrite sections of memory that are not writable without calling any of the memory change API functions. This is done because of a feature of WriteProcessMemory which temporarily changes the permissions of the region of memory to writeable (if you have sufficient privileges, which we do since we own the process). It writes the value and restores the original permissions without calling the VirtualProtect function, instead it automatically calls the associated syscall (NtProtectVirtualMemory).
Ivy does not utilize its own version of NtWriteVirtualMemory because this process of temporarily changing the memory permissions would not occur, meaning the protection of the specific memory address would not be modified and the execution would fail. This is a “feature” Microsoft has released to make debuggers more stable. As debuggers want to modify memory on the fly, they can simply modify a section without having to perform multiple tasks. (See devblogs.microsoft.com for information)
Let’s take a look at the series of events that an EDR would see:
- Ivy creates a WriteProcessMemory function that sets up the proper registry values manually.
- Our function calls the exact memory address where WriteProcessMemory is stored. (This would look like a call to the register RAX rather than calling kernel32.WriteProcessMemory)
- This means we’re not directly calling WriteProcessMemory while still utilizing all the features.
- EDR would only see a string of assembly that does not match any malicious indicators to a memory address.
- This memory address would be the start of a function, but the function address is unique because of ASLR; a lookup of every function would need to be performed.
- Prior to the Write action being performed, the syscall ZWQueryVirtualMemory is executed to view the protections on the region of memory.
- If this memory is not set to writeable, NtProtectVirtualMemory is called to change the permissions.
- Then 8 bytes of assembly are written to the specific memory address.
- NtProtectVirtualMemory is called once more to restore the original protection value.
Once all the EDR hooks have been flushed out it, the loader then performs its normal action to establish a remote session.
Ivy address this by unhooking common system DLLs EDR’s hook, this includes:
- Ntdll.dll
- Kernel32.dll
- Kernelbase.dll
- Advapi32.dll
- Sechost.dll
- Ws2_32.dll
- Winmmbase.dll
When using unhook
with a payload type Inject
Ivy’s loader will first unhook the office process removing the edr from it and then remove the hooks in the injected processs. These ensures that both processes are hook free, preventing any telemetry from the parent and child process from being sent to the EDR.
ETW Patching
Using the same technique to unhook, Ivy can patch ETW functions, preventing any event from being generated by the process. ETW utilizes built-in Syscalls to generate this telemetry. Since ETW is a native feature built into Windows, security products do not need to “hook” the ETW syscalls to gain the information. As a result, to prevent ETW, Ivy patches numerous ETW syscalls, flushing out the registers and returning the execution flow to the next instruction. Patching ETW is now default in all loaders, if you wish to not patch ETW use the -noetw
command-line option to disable it in your loader.
Install & Use
Copyright (c) 2021 Optiv Security