Authored by Mohansundaram M and Neil Tyagi
A new packed variant of the Redline Stealer trojan was observed in the wild, leveraging Lua bytecode to perform malicious behavior.
McAfee telemetry data shows this malware strain is very prevalent, covering North America, South America, Europe, and Asia and reaching Australia.
Infection Chain
- GitHub was being abused to host the malware file at Microsoft’s official account in the vcpkg repository https[:]//github[.]com/microsoft/vcpkg/files/14125503/Cheat.Lab.2.7.2.zip
- McAfee Web Advisor blocks access to this malicious download
- Cheat.Lab.2.7.2.zip is a zip file with hash 5e37b3289054d5e774c02a6ec4915a60156d715f3a02aaceb7256cc3ebdc6610
- The zip file contains an MSI installer.
- The MSI installer contains 2 PE files and a purported text file.
- Compiler.exe and lua51.dll are binaries from the Lua project. However, they are modified slightly by a threat actor to serve their purpose; they are used here with readme.txt (Which contains the Lua bytecode) to compile and execute at Runtime.
- Lua JIT is a Just-In-Time Compiler (JIT) for the Lua programming language.
- The magic number 1B 4C 4A 02 typically corresponds to Lua 5.1 bytecode.
- The above image is readme.txt, which contains the Lua bytecode. This approach provides the advantage of obfuscating malicious stings and avoiding the use of easily recognizable scripts like wscript, JScript, or PowerShell script, thereby enhancing stealth and evasion capabilities for the threat actor.
- Upon execution, the MSI installer displays a user interface.
- During installation, a text message is displayed urging the user to spread the malware by installing it onto a friend’s computer to get the full application version.
- During installation, we can observe that three files are being written to Disk to C:\program Files\Cheat Lab Inc\ Cheat Lab\ path.
- Below, the three files are placed inside the new path.
-
- Here, we see that compiler.exe is executed by msiexec.exe and takes readme.txt as an argument. Also, the Blue Highlighted part shows lua51.dll being loaded into compiler.exe. Lua51.dll is a supporting DLL for compiler.exe to function, so the threat actor has shipped the DLL along with the two files.
- Here, we see that compiler.exe is executed by msiexec.exe and takes readme.txt as an argument. Also, the Blue Highlighted part shows lua51.dll being loaded into compiler.exe. Lua51.dll is a supporting DLL for compiler.exe to function, so the threat actor has shipped the DLL along with the two files.
-
- During installation, msiexec.exe creates a scheduled task to execute compiler.exe with readme.txt as an argument.
- Apart from the above technique for persistence, this malware uses a 2nd fallback technique to ensure execution.
- It copies the three files to another folder in program data with a very long and random path.
- Note that the name compiler.exe has been changed to NzUW.exe.
- Then it drops a file ErrorHandler.cmd at C:\Windows\Setup\Scripts\
- The contents of cmd can be seen here. It executes compiler.exe under the new name of NzUw.exe with the Lua byte code as a parameter.
- Executing ErrorHandler.cmd uses a LolBin in the system32 folder. For that, it creates another scheduled task.
-
- The above image shows a new task created with Windows Setup, which will launch C:\Windows\system32\oobe\Setup.exe without any argument.
- Turns out, if you place your payload in c:\WINDOWS\Setup\Scripts\ErrorHandler.cmd, c:\WINDOWS\system32\oobe\Setup.exe will load it whenever an error occurs.
Source: Add a Custom Script to Windows Setup | Microsoft Learn
-
- c:\WINDOWS\system32\oobe\Setup.exe is expecting an argument. When it is not provided, it causes an error, which leads to the execution of ErrorHandler.cmd, which executes compiler.exe, which loads the malicious Lua code.
- We can confirm this in the below process tree.
We can confirm that c:\WINDOWS\system32\oobe\Setup.exe launches cmd.exe with ErrorHandler.cmd script as argument, which runs NzUw.exe(compiler.exe)
-
- It then checks the IP from where it is being executed and uses ip-API to achieve that.
-
- We can see the network packet from api-api.com; this is written as a JSON object to Disk in the inetCache folder.
- We can see the network packet from api-api.com; this is written as a JSON object to Disk in the inetCache folder.
-
- We can see procmon logs for the same.
- We can see procmon logs for the same.
- We can see JSON was written to Disk.
C2 Communication and stealer activity
-
- Communication with c2 occurs over HTTP.
-
- We can see that the server sent the task ID of OTMsOTYs for the infected machine to perform. (in this case, taking screenshots)
- A base64 encoded string is returned.
- We can see that the server sent the task ID of OTMsOTYs for the infected machine to perform. (in this case, taking screenshots)
-
- An HTTP PUT request was sent to the threat actors server with the URL /loader/screen.
- IP is attributed to the redline family, with many engines marking it as malicious.
- Further inspection of the packet shows it is a bitmap image file.
- The name of the file is Screen.bmp
- Also, note the unique user agent used in this put request, i.e., Winter
- After Dumping the bitmap image resource from Wireshark to disc and opening it as a .bmp(bitmap image) extension, we see.
- The screenshot was sent to the threat actors’ server.
Analysis of bytecode File
- It is challenging to get the true decomplication of the bytecode file.
- Many open source decompilers were used, giving a slightly different Lua script.
- The script file was not compiling and throwing some errors.
- The script file was sensitized based on errors so that it could be compiled.
- Debugging process
- One table (var_0_19) is populated by passing data values to 2 functions.
- In the console output, we can see base64 encoded values being stored in var_0_19.
- These base64 strings decode to more encoded data and not to plain strings.
- All data in var_0_19 is assigned to var_0_26
-
- The same technique is populating 2nd table (var_0_20)
- It contains the substitution key for encoded data.
-
- The above pic is a decryption loop. It iterates over var_0_26 element by element and decrypts it.
- This loop is also very long and contains many junk lines.
- The loop ends with assigning the decrypted values back to var_0_26.
-
- We place the breakpoint on line 1174 and watch the values of var_0_26.
- We place the breakpoint on line 1174 and watch the values of var_0_26.
-
- As we hit the breakpoint multiple times, we see more encoded data decrypted in the watch window.
- As we hit the breakpoint multiple times, we see more encoded data decrypted in the watch window.
- We can see decrypted strings like Tamper Detected! In var_0_26
Loading luajit bytcode:
Before loading the luajit bytecode, a new state is created. Each Lua state maintains its global environment, stack, and set of loaded libraries, providing isolation between different instances of Lua code.
It loads the library using the Lua_openlib function and loads the debug, io, math,ffi, and other supported libraries,
Lua jit bytecode loaded using the luaL_loadfile export function from lua51. It uses the fread function to read the jit bytecode, and then it moves to the allocated memory using the memmove function.
The bytecode from the readme. Text is moved randomly, changing the bytecode from one offset to another using the memmove API function. The exact length of 200 bytes from the Jit bytecode is copied using the memmove API function.
It took table values and processed them using the below floating-point arithmetic and xor instruction.
It uses memmove API functions to move the bytes from the source to the destination buffer.
After further analysis, we found that c definition for variable and arguments which will be used in this script.
We have seen some API definitions, and it uses ffi for directly accessing Windows API functions from Lua code, examples of defining API functions,
It creates the mutex with the name winter750 using CreateMutexExW.
It Loads the dll at Runtime using the LdrLoaddll function from ntdll.dll. This function is called using luajit ffi.
It retrieves the MachineGuid from the Windows registry using the RegQueryValueEx function by using ffi. Opens the registry key “SOFTWARE\\Microsoft\\Cryptography” using RegOpenKeyExA—queries the value of “MachineGuid” from the opened registry key.
It retrieves the ComputerName from the Windows registry using the GetComputerNameA function using ffi.
It gathers the following information and sends it to the C2 server.
It also sends the following information to the c2 server,
- In this blog, we saw the various techniques threat actors use to infiltrate user systems and exfiltrate their data.
- Microsoft has since removed these files from the repositories.
Indicators of Compromise
Cheat.Lab.2.7.2.zip | 5e37b3289054d5e774c02a6ec4915a60156d715f3a02aaceb7256cc3ebdc6610 |
Cheat.Lab.2.7.2.zip | https[:]//github[.]com/microsoft/vcpkg/files/14125503/Cheat.Lab.2.7.2.zip
|
lua51.dll | 873aa2e88dbc2efa089e6efd1c8a5370e04c9f5749d7631f2912bcb640439997 |
readme.txt | 751f97824cd211ae710655e60a26885cd79974f0f0a5e4e582e3b635492b4cad |
compiler.exe | dfbf23697cfd9d35f263af7a455351480920a95bfc642f3254ee8452ce20655a |
Redline C2 | 213[.]248[.]43[.]58 |
Trojanised Git Repo | hxxps://github.com/microsoft/STL/files/14432565/Cheater.Pro.1.6.0.zip |