Securonix Threat Research Security Advisory
By Securonix Threat Research: D. Iuzvyk, T. Peck, O. Kolesnikov
May 21st, 2024
tldr:
An interesting attack campaign has been uncovered which leverages Google Drive and Dropbox to stage malware and exfiltrate sensitive data.
The Securonix Threat Research team has discovered a new sophisticated infection chain, dubbed CLOUD#REVERSER, which leverages popular cloud storage services like Google Drive and Dropbox to orchestrate the threat actor’s malicious operations. The usage of legitimate cloud-based storage was also a primary method of malware delivery during the DEEP#GOSU campaign uncovered by the team earlier in the year.
This approach follows a common thread where threat actors manage to infect and persist onto compromised systems while maintaining to blend into regular background network noise. By embedding malicious scripts within seemingly innocuous cloud platforms, the malware not only ensures sustained access to targeted environments but also utilizes these platforms as conduits for data exfiltration and command execution.
As we’ll dive into further down in the article, peeling back the many layers of VBScript and PowerShell stages, the malware has the ability to dynamically update its operational scripts and fetch executable commands remotely. This is done as scripts are executed and then re-executed through Windows scheduled tasks.
Initial infection
The attack chain kicks off after the user receives a phishing email and downloads a zip archive sent as an attachment. Zip file names and their contents tend to vary, though we were able to identify a single related zip payload, we were unable to identify the attacker’s naming convention.
The zip file contains a single executable file that has been modified to look like a Microsoft Office Excel file icon. Additionally, the file performs some trickery using Left to Right override characters ( LTRO) to obfuscate the fact that it is an executable (.exe) extension versus an Excel file (.xlsx) file. The character is completely invisible and affects in-sequence characters directly after it. For example, the file name follows the following format:
RFQ-101432620247fl<LTRO_CHARACTER>xslx.exe
When viewed by the user, it would appear as:
RFQ-101432620247flexe.xlsx
This technique works by reversing everything after the LTRO character thus making it appear to have a valid .xlsx extension. The technique is not new, however even after 20 plus years, it still a popular technique used by attackers today.
The user then would double click an executable file thinking that they’re opening an Excel spreadsheet which initiates the malware infection.
Executable analysis
The executable performs a few interesting operations. It’s overall quite small standing at around 560KB and was compiled using Visual Studio 2015.
Figure 1: Binary executable analysis: Payload overview
After analyzing the file most of the strings and embedded files which get written to disk are XOR encoded using a hexadecimal offset of E2. This makes static analysis difficult as almost no useful strings could be analyzed from the payload directly.
The purpose of the payload is to first, drop additional script-based payloads onto the disk, execute one of the .vbs script files, and then execute a newly dropped (legitimate) .xlsx file. The purpose of executing the Excel file is to ensure that the action that the user performed achieves the desired effect. If nothing happened when the user double clicked the .exe file, or if an error occurred, this might alarm the user and alert them to the fact that they might have done something wrong and take action accordingly.
Stage 1: Payload execution: File writes
Immediately after executing the payload, a handful of files were written to the system’s C:\ProgramData directory. This directory is commonly used by malware and threat actors to stage payloads. It’s typically hidden and has world writable permissions, making it a reliable staging directory.
Figure 2: Payload dynamic analysis: ProgramData directory
As you can see in the figure above ,the following files were dropped into the system’s ProgramData directory: 20240416.xlsx, 3156.vbs, 68904.tmp, 97468.tmp, Tmp703.tmp, Tmp912.tmp, i4703.vbs, i6050.vbs. We’ll discuss each of these as they’re utilized in subsequent stages.
Each file saved to the disk originates directly from the binary payload. This payload is embedded within the executable as variables encoded using XOR, effectively concealing its plain-text string values. This method shields them from basic static analysis techniques.
Script analysis
At this stage, we shift from binary file execution to script-based execution, which is a bit unorthodox. Typically initial compromise begins with a malicious script, or one-liner which often times through a few stages results in binary payloads being executed on the system.
Stage 2: Payload execution: VBScript execution (3156.vbs)
After writing all of the aforementioned files to ProgramData, the malware executes the first VBScript file (3156.vbs) using the following command:
“C:\Windows\System32\WScript.exe” “C:\ProgramData\3156.vbs”
The script is heavily obfuscated and relies on lots of variable substitutions and character manipulation using for loops. The contents of the file can be seen in the figure below.
Figure 3: Obfuscated VBScript from 3156.vbs
The script can be deobfuscated using the provided deobfuscation Python script in Appendix A. Executing the script with the contents of the “gjmqvae” variable, provides us with a much easier to read result:
Figure 4: 3156.vbs deobfuscated code
With the code in a much more readable form, the main purpose of this script is to execute some of the next-stage payloads, the .xlsx lure file and then perform a cleanup operation. Here’s a breakdown of each action:
- Declares “On Error Resume Next” which prevents the script from displaying any errors or stopping unexpectedly, allowing it to continue executing even if an error occurs.
- It sets the current working directory to C:\ProgramData\.
- Creates several objects (objFSO, objFolder, objShell) for file system and shell interactions.
- Two .vbs files (i4703.vbs and i6050.vbs) and an .xlsx file (20240416.xlsx) are executed using ShellExecute.
- After execution, the script sleeps for 3000 seconds and then deletes all .vbs and .jse files in the C:\ProgramData\ directory, giving the files which were just executed time to complete their operations.
Stage 3: Payload execution: VBScript execution (i4703.vbs)
The Visual Basic file i4703.vbs is obfuscated exactly the same as 3156.vbs. After taking the time to deobfuscate the script using the same deobfuscation script (Appendix A), makes it a little bit easier to read, though there is still some obfuscation present around structuring a date/time format.
Figure 5: i4703.vbs deobfuscated code
In a nutshell, the purpose of the stage 3 VBScript is to create a scheduled task for persistence. It repeatedly executes a VBScript from a specified path and ensures that the task runs hidden and starts automatically with system startup as soon as available.
Manually executing the .vbs file with wscript.exe, we observe the task get created, providing us with even more details. Below is a screenshot of the XML file created in C:\Windows\System32\Tasks.
Figure 6: XML file for newly created scheduled task from i4703.vbs
It registers the task under the name “GoogleUpdateTaskMachineUHX[69495-0742-9024]” in the root folder of the task scheduler and executes using the highest available privileges. The name mimics a typical Google Chrome browser update task to avoid suspicion. The created trigger for the task instructs the task scheduling service to start 10 seconds from the current time and repeats every minute.
The action for the task is set to execute a VBScript file using wscript.exe with parameters that suppress errors. The completed command which gets executed every minute is:
wscript.exe /b /e:vbscript “C:\Programdata\97468.tmp”
We’ll dive into the purpose of this script further down into “Stage 5”.
Stage 4: Payload execution: VBScript execution (i6050.vbs)
The file i6050.vbs if you recall during stage 3 was executed just after the stage 4 payload i4703.vbs file. The purpose of this file, i6050.vbs, is almost identical to that of the prior. Like all of the previous .vbs file, it is also obfuscated using the same technique, and when we run it through our deobfuscation script, the revealed VBScript looks identical to that of the script from the previous stage.
Figure 7: i6050.vbs deobfuscated code
This script also creates a scheduled task which also executes a .tmp file from the ProgramData directory every minute. The only difference is the slightly different scheduled task name (“GoogleUpdateTaskMachineUF[51853-4679-1246]“) and the .vbs file which gets executed:
wscript.exe //b //e:vbscript “C:\\Programdata\\68904.tmp”
So at this point, we’ve got two scheduled tasks which get created which execute two unique .tmp (VBS) payloads using wscript.exe and which run every minute on the victim machine.
Stage 5: VBScript execution through Schtasks
Let’s examine each of the VBScript files in detail to see what exactly is happening on the system when these scripts are executed every minute.
97468.tmp (from stage 3)
Once again, the VBScript obfuscation is similar to that from the last several stages featuring lots of variable substitutions. Once decoded, we’re presented with the code in the figure below.
Figure 8: Deobfuscated contents of 97468.tmp
The purpose of this script is to use the WScript.Shell object to execute two unique PowerShell scripts using two unique methods of PowerShell file execution. The first PowerShell command executes the file Tmp912.tmp using the following command:
powershell -ep bypass -command $fn=’C:\ProgramData\Tmp912.tmp\’;$d = Get-Content $fn; Invoke-Expression $d;
By reading in the file by using the Get-Content module, storing it into a variable and then executing its contents using IEX is an interesting way to execute a PowerShell script file, which does not contain a common PowerShell extension (ie .ps1, psd1, psm1).
The second PowerShell command runs and executes another script file tmpdbx.ps1 using the following command:
powershell -ep bypass -f C:\ProgramData\tmpdbx.ps1
68904.tmp (from stage 4)
Also executed by schtasks.exe is 68904.tmp, which is another VBScript file. Just like the previous file (97468.tmp), this file also executes PowerShell code.
Figure 9: Deobfuscated contents of 68904.tmp
The commands executed by PowerShell, are pretty much identical to that of the previous .tmp (VBS) file, with the only difference being the name of the PowerShell scripts being executed. Here we see both Tmp703.tmp and zz.ps1 being executed.
powershell -ep bypass -command $fn=’C:\ProgramData\Tmp703.tmp’;$d = Get-Content $fn; Invoke-Expression $d;
powershell -ep bypass -f C:\ProgramData\zz.ps1
Once the .ps1 file is executed, it is deleted using the objFSO.DeleteFile method.
Stage 6: PowerShell Execution
At this point we have four PowerShell scripts which were executed by 97468.tmp and 68904.tmp, which were both launched by two different scheduled tasks which run every minute. The VBScript file 97468.tmp executes both Tmp912.tmp and tmpdbx.ps1, while the VBScript 68904.tmp executes Tmp703.tmp and zz.ps1.
Tmp912.tmp
Let’s take a look at the first PowerShell script which gets executed, Tmp912.tmp. The script contains two large base64 encoded strings using the two variables “$a” and “$k”. These two variables are concatenated, converted from Base64 and then invoked using an Invoke-Expression.
Figure 10: example of Tmp912.tmp contents
The purpose of the script is to perform several functions which allow for interfacing with the Dropbox API. After defining the client_secret, refresh_token and client_id information, the script performs a series of actions:
- Sends an HTTP POST request to the Dropbox API to refresh the access token and parses the response to extract the access_token.
- Executes a ping command to the local machine to get its IPv4 address and then builds a directory path using the machine’s IP address.
- Dropbox upload functionality – The script contains a function which takes the access token and uploads a “log file” to Dropbox. The name for the file is constructed using the current date and time. A request stream is then opened to Dropbox and the file is uploaded to the remote Dropbox server.
- Dropbox download functionality – Using the Dropbox access token, this PowerShell function is able to open another request stream and download, or delete Dropbox files to a local directory. This function is used to download another PowerShell file (“C:\ProgramData\tmpdbx.ps1”)
tmpdbx.ps1
If you recall, this file was referenced earlier in Stage 5 where it was the second PowerShell script to be invoked from both 97468.tmp and 68904.tmp. The file is downloaded during stage 6 from an attacker-controlled Dropbox account.
In addition to some of the other scripts, this script will also be executed every minute from the scheduled task at stage 5.
Figure 11: example of tmpdbx.ps1 contents
The PowerShell file tmpdbx.ps1 features no obfuscation of any kind. It’s used to download files within Dropbox using REST API calls. It uses authentication tokens from the parent script Tmp921.tmp and uses them to list all files in Dropbox, identifies files matching specific patterns (*.txt), downloads any matching files to the local system and then optionally deletes it from Dropbox after download.
Tmp703.tmp
This PowerShell file is obfuscated identical to the last, featuring two blocks of a base64 encoded payload concatenated together and then executed.
Its purpose is also similar to that of Tmp921.tmp, however rather than connecting and managing Dropbox uploads and downloads, it uses Google Drive. It uses advanced features like MIME type handling, base64 encoding, and OAuth 2.0 for secure authentication.
Lastly, at the end of the script, it downloads the file (“C:\ProgramData\zz.ps1”). This file is executed every minute by the second scheduled task which executed the 68904.tmp file from stage 5.
zz.ps1
Similar to that of tmpdbx.ps1, zz.ps1 performs roughly the same operations, though using Google Drive as a download and upload medium. The script provides functions for uploading and downloading files from Google Drive, once again using OAuth 2.0 for authentication. It operates through a series of hooks that interact with the Drive API to handle files based on their metadata and content.
Files matching the specific MIME type are downloaded by iterating through the stored files. If the MIME type matches “text/plain,” it constructs a download URL and downloads the file using PowerShell’s System.Net.WebClient module.
Post Exploitation: Hands on keyboard
To establish proper command and control capabilities on the host, the attackers downloaded and executed another PowerShell script. The script was observed executing from the Stage 5 VBScript 68904.tmp and is designed to download a compressed (gzip) binary and use reflection techniques to execute it directly into memory. It has a specific focus on maintaining network communication capabilities.
Figure 12: Post exploitation PowerShell script analysis
Since the downloaded payload is downloaded and executed directly into memory, it increases the chance that this could be missed by antivirus or EDR software, especially when file scanning is involved. The attacker’s IP address (159.100.13[.]216 and port (6606) are hardcoded into the script.
To execute the payload, the script skips the first 10 bytes of the downloaded content (possibly a header or offset used for specific reasons such as alignment or metadata) and sends the rest to the GzExtract function for decompression.
After decompression, it loads the resulting byte array as a .NET assembly directly into preallocated memory space in the current running PowerShell process.
Next, it searches for a method named “start” within any of the types defined in the assembly and invokes this method with the provided IP and port as arguments. This establishes a network connection to the attacker’s C2 server which allows the attacker to issue further shell commands.
Wrapping up
The VBScript and PowerShell scripts in the CLOUD#REVERSER inherently involves command and control-like activities by using Google Drive and Dropbox as staging platforms to manage file uploads and downloads.
The scripts are designed to fetch files that match specific patterns, suggesting they are waiting for commands or scripts placed in Google Drive or Dropbox. The late-stage PowerShell script zz.ps1 has functionality to download files from Google Drive based on specific criteria and save them to a specified path on the local system inside the ProgramData directory. This indicates that if the downloaded file is executable and the system’s policies allow it, these files can potentially be executed.
Interestingly, the two PowerShell scripts (tmpdbx.ps1 and zz.ps1) have the ability to dynamically update themselves by deleting and redownloading itself the next time the scheduled task executes. This could be beneficial for the attacker to maintain persistence. New authentication tokens could be issued, or a new set of matching files could be downloaded and executed by the attacker.
Securonix recommendations
Phishing emails and crafty lures continue to be a popular method of malware delivery for threat actors. It’s critical for users to be mindful of tactics that attackers are using to fool their victims into executing the malware. With the case of this campaign, CLOUD#REVERSER, double extensions were used to trick the user into running a single executable file from a zip file. The executable file’s icon was also modified to look like a typical Microsoft Excel file to also make it appear legitimate.
Additionally, always exercise caution around unsolicited emails, especially when the email is unexpected or employs a sense of urgency. When it comes to prevention and detection, the Securonix Threat Research team recommends:
- Avoid downloading files or attachments from external sources, especially if the source was unsolicited. Common file types include zip, rar, iso, and pdf. Zip files were used during this campaign.
- Monitor common malware staging directories, especially script-related activity in world-writable directories. In the case of this campaign the threat actors staged the in C:\ProgramData directory.
- Through various phases of the CLOUD#REVERSER campaign, the threat actors leveraged encrypted channels through Dropbox and Google servers using encrypted API connections to stage and exfiltrate data. Because of this, we strongly recommend deploying robust endpoint logging capabilities. This includes leveraging additional process-level logging such as Sysmon and PowerShell logging for additional log detection coverage.
- Securonix customers can scan endpoints using the Securonix hunting queries below.
MITRE ATT&CK Matrix
Tactics |
Techniques |
Collection |
T1560: Archive Collected Data |
Credential Access |
T1539: Steal Web Session Cookie
T1555.003: Credentials from Password Stores: Credentials from Web Browsers |
Defense Evasion |
T1027.010: Obfuscated Files or Information: Command Obfuscation
T1070.004: Indicator Removal: File Deletion |
Discovery |
T1082: System Information Discovery |
Execution |
T1059.001: Command and Scripting Interpreter: PowerShell
T1059.003: Command and Scripting Interpreter: Windows Command Shell
T1059.006: Command and Scripting Interpreter: Python |
Exfiltration |
T1041: Exfiltration Over C2 Channel |
Persistence |
T1547.001: Boot or Logon Autostart Execution: Registry Run Keys / Startup Folder |
Relevant provisional Securonix detections
- EDR-ALL-336-RU
- EDR-ALL-1275-ERR
- EDR-ALL-1294-RU
- PSH-ALL-307-RU
Relevant hunting queries
(remove square brackets “[ ]” for IP addresses or URLs)
- index = activity AND rg_functionality = “Web Proxy” AND destinationaddress = “159.100.13.216”
- index = activity AND rg_functionality = “Microsoft Windows Powershell” AND (message CONTAINS “content.dropboxapi[.]com/oauth2” or message CONTAINS “https://www.googleapis.com/upload/drive/”)
- index = activity AND rg_functionality = “Endpoint Management Systems” AND (deviceaction = “Process Create” OR deviceaction = “Process Create (rule: ProcessCreate)” OR deviceaction = “ProcessRollup2” OR deviceaction = “Procstart” OR deviceaction = “Process” OR deviceaction = “Trace Executed Process”) AND sourceprocessname ENDS WITH “svchost.exe” AND resourcecustomfield2 ENDS WITH “-k netsvcs -p -s Schedule” AND resourcecustomfield1 CONTAINS “\ProgramData”
C2 and infrastructure
C2 Address |
159.100.13.216 |
Analyzed files/hashes
File Name / Description |
SHA256 |
Zip Archive |
91bd0f7e5af15248c1e3f2908891bbd9262753910fe4bbd61729f0c184287153 |
KZAH.exe
RFQ-101432620247flxslx.exe |
b89d6be0bcfb915492beb7ae726f815dcf289a284e650c200bda4faf5db60fa1 |
4.exe (renamed) |
4C37F3DB024AFD425301666E318C03E34F8813D21D90D95EFB4018B3196D07B8 |
20240416.xlsx |
5F0642383CA70A3FD2C4491B2826002763E90CA25A7413869FD824E7745D0465 |
3156.vbs |
59C49F31B5F389C1C0109B0E603E2679C4F63C3F5C64432E820A50F50B80124F |
i4703.vbs |
51D758FC04D05B997C651F658CDD30819EF5CF795D4498FAD919E75A320E72EA |
i6050.vbs |
4CB1E5CA257C709154B38704C34F4F0ADE5305263FB21E6142C90C10A5764D52 |
68904.tmp |
09FEE43F923FAAA30857A09C74D96FCA9354653835165A01B274CAD4C24460C7 |
97468.tmp |
590353941BAB80F38D77B2139BC7DA6888B3DFF9C8817C4B7E058F50173288BF |
Tmp703.tmp |
9B9A3DA9C602BF70A60CDB9B2BCA6F4472222E8431B6B5ECF82B010FE274BBA3 |
Tmp912.tmp |
F96631CDFFA6AE69E5432C38778F3B93E5335A935F62939CD0094E5CCB886460 |
tmpdbx.ps1 |
8955585100F75C59472E4C2C77FCDDD7422400F745AE75132C81C6144AA86824 |
zz.ps1 |
7BB7CA87149B6407E1E7C11C1A528A2E2147D3096337E3DA6F6BE130F76FF6AC |
Post-ex PowerShell script |
BEAA71057AD064E96FC9F8227A7C2A3B8D70D13E45D5908F25C066D937D5BD9D |
Gzip payload |
f4275b0d3c4b6f3a165984b862f4890df14cc346013a22412f7288c9fdc65690 |
References:
- ANALYSIS OF NEW DEEP#GOSU ATTACK CAMPAIGN LIKELY ASSOCIATED WITH NORTH KOREAN KIMSUKY TARGETING VICTIMS WITH STEALTHY MALWARE
https://www.securonix.com/blog/securonix-threat-research-security-advisory-new-deepgosu-attack-campaign/
- Left-to-right override makes a return in spam
https://www.virusbulletin.com/blog/2014/09/left-right-override-makes-return-spam/
Appendix A: VBScript Deobfuscator (Python):
obfuscatedVBS = (“Rq#Huuru#Uhvxph#Qh{w=vmf@%7uiyjkmxl;:9w8uhgfyeqmpnrl<;:987h6zv{gfiyjkmnlronmqkejyiguw|xmkqejyighuw|xlnmkjw|xlnmkjifyejkmlnrjk|xkjiyyjkmlnmkjyifiykmlxkjigf{iwuhvzghu7hzv{ijkx|kjmnlrx|kjeqmnl;x:|jekqmnlrx%=Glp#ivr=#vhw#ivr#@#FuhdwhRemhfw+%Vfulswlqj1IlohV|vwhpRemhfw%,=FxuuhqwGluhfwru|#@#%f=__surjudpgdwd__%=Vhw#remIVR#@#FuhdwhRemhfw+%Vfulswlqj1IlohV|vwhpRemhfw%,=Vhw#remIroghu#@#remIVR1JhwIroghu+FxuuhqwGluhfwru|,=Vhw#remVkhoo#@#FuhdwhRemhfw+%Vkhoo1Dssolfdwlrq%,=lqvMv#@#%l7:361yev%=zhu#@#FxuuhqwGluhfwru|#)#lqvMv=#remVkhoo1VkhooH{hfxwh#zhu=lqvMv#@#%l93831yev%=zhu#@#FxuuhqwGluhfwru|#)#lqvMv=#remVkhoo1VkhooH{hfxwh#zhu=zhu#@#FxuuhqwGluhfwru|#)#%535737491{ov{%=#remVkhoo1VkhooH{hfxwh#zhu=ZVfulsw1Vohhs+6333,=remIVR1GhohwhIloh+FxuuhqwGluhfwru|#)#%-1yev%,=remIVR1GhohwhIloh+FxuuhqwGluhfwru|#)#%-1mvh%,=”)
decodedVBS = ”.join(chr(ord(c) – 3) for c in obfuscatedVBS)
print(decodedVBS)