The AI Vulnerability Storm is here. Are your defenses ready? Read the White Paper
  • Malware Analysis
  • Threat Intelligence
  • Reverse Engineering
  • Crypto Security

Needle: Inside a Modular Crypto-Stealing C2 That Left Its Keys in the Malware

A single MalwareBazaar sample, fed to our Caronte CTI platform, unfolded into 1,932 victims, six withdrawal wallets, and ~$148 ETH already moved to cold storage. All from intelligence Caronte extracted autonomously in minutes.

Beelzebub Labs

Beelzebub Labs

From researchers at beelzebub labs

<h3>Needle: Inside a Modular Crypto-Stealing C2 That Left Its Keys in the Malware</h3>

Research note: The API key used to enumerate this infrastructure was extracted from malware distributed publicly on MalwareBazaar. The same credential the threat actor embedded in their own agent to phone home from infected machines. No victim data was retained beyond the statistics reported here. No settings were modified.


TL;DR

  • Analysis performed autonomously by Caronte, our agentic CTI platform: from a single MalwareBazaar sample to full C2 attribution, victim enumeration, and on-chain fund tracking, in minutes, with no manual reverse engineering
  • Needle is an active MaaS crypto-stealing platform with two live modules: a browser extension spoofer targeting MetaMask, Phantom, and Trust Wallet; and a Rust desktop agent impersonating Exodus, Trezor, and Ledger
  • The Rust agent embeds its C2 API key without protection. Using it, we enumerated 1,932 victims and the attacker’s full withdrawal configuration across six blockchains
  • The panel’s React SPA performed authentication entirely client-side: writing a structurally valid token to localStorage was enough to render the full admin dashboard, with no server validation of the UI routing layer
  • The frontend bundle defines a write endpoint for the withdrawal configuration using the same agent key authentication scheme, meaning the same credential that phones home from infected machines could potentially redirect every future auto-withdrawal

Key Findings at a Glance

CategoryDetails
SampleRust PE (Windows), v1.3, SHA256: d6ca3760...a490
C2 StackReact 19 SPA · Express.js API · nginx 1.29.8
Active ModulesDesktop Wallet Spoofer · Browser Wallet Spoofer
Victims1,932 total (111 browser extension, 1,821 desktop sessions)
Targeted WalletsMetaMask · Trust · Phantom · OKX · Exodus · Trezor · Ledger · Atomic · Guarda · Zelcore
Campaign WindowActive from April 18, 2026; ongoing at time of writing
Auth FailuresUnprotected agent key · client-side-only auth · unauthenticated builder
C2 Infrastructure130.12.180.135 (ports 3000, 8080, 8181)
Confirmed Fund MovementEVM hot wallet: ~$148 ETH forwarded to cold storage

Discovery: From MalwareBazaar to Full C2 Visibility

A sample flagged as a Windows crypto-stealer surfaced on MalwareBazaar. We fed it to Caronte, our agentic CTI platform. From that single upload, Caronte ran the full analysis pipeline autonomously, with no manual reverse engineering required.

Caronte started with binary classification: a stripped Rust PE, 8.9MB, unsigned, entropy 6.71, tagged on MalwareBazaar as RustyStealer, distributed via the Phorpiex spam botnet. It identified the egui desktop GUI framework from characteristic string patterns, traced the Rust panic handler paths to recover wallet impersonation targets (zelcore, trezor, ledger), and reconstructed the embedded configuration schema from the binary’s data segments.

Static reverse-engineering also surfaced capabilities beyond the wallet spoofer: keylogging via GetAsyncKeyState (consistent with capturing seed phrases as typed, not only on submission), persistence via the Windows Run registry key, and anti-debugging techniques including SetUnhandledExceptionFilter and software breakpoint traps. The C2 IP resolved to ASN 202412 (Omegatech LTD, Amsterdam), a known bulletproof hosting provider with 27 OTX malicious pulses on record at time of analysis.

The full analysis produced a threat graph of 94 nodes and 135 edges, matching 40 YARA rules across local and MalwareBazaar rulesets, including high-severity hits for keylogging, anti-VM evasion, and Rust-based stealer patterns. Within minutes of submission, Caronte had produced a complete operator profile: platform identity, C2 address, API key, and a live panel managing nearly two thousand victims.

What Caronte produced autonomously

DeliverableOutput
Binary classificationStripped Rust PE, 8.9MB, RustyStealer family
Framework identificationegui GUI, Phorpiex distribution
Capability extractionKeylogging, persistence, anti-debug
Embedded config recoveryC2 URL and API key from binary data segments
Infrastructure attributionASN 202412 Omegatech, 27 OTX pulses
Threat graph94 nodes, 135 edges
Detection coverage40 YARA rule matches
Time to intelligenceMinutes vs. days of manual RE

Everything below this section is verification and exploration built on top of Caronte’s autonomous output: the human-in-the-loop step.


What is Needle?

Needle is a modular MaaS (Malware-as-a-Service) platform. The panel is built around purchasable modules: operators activate what they need, the infrastructure stays shared. During our analysis two modules were active:

Needle Modules Page showing all available modules with ACTIVE/INACTIVE status

ModuleStatusDescription
Needle CoreInactiveForm grabber, Clipper, system core
Extension BaseInactiveSite substitution, backup domain management
Desktop Wallet SpooferActiveRust agent, fake wallet UI, seed phrase capture
Browser Wallet SpooferActiveExtension replacement, password and seed interception
FarmInactiveDeferred withdrawal triggered by balance threshold
Launch PanelInactiveTraffic management and launcher creation
Captcha (Win+R)InactiveSocial engineering delivery mechanism

The module structure is consistent with a platform sold or rented to multiple operators, inactive modules represent capabilities the current operator hasn’t subscribed to. This is corroborated by independent research: in the same month, Malwarebytes documented a separate Needle campaign using entirely different infrastructure (different hashes, different C2 IPs), focused on delivery via a fake trading website and DLL hijacking. Their samples share no overlap with this C2. Where that analysis documented how victims get infected, this report goes inside the infrastructure that processes them.


The Rust Agent: A Key Hidden in Plain Sight

The binary is a stripped Rust PE with no debug symbols. Rust’s panic handler mechanism retains source file paths even in release builds, these strings, present in the binary’s data section, identify the wallet impersonation targets:

src/views/zelcore/app.rs
src/views/trezor/seed_panel.rs
src/views/ledger/screens/seed_recovery.rs

The binary also carries a full egui desktop GUI framework, identifiable from characteristic string patterns in the binary, used to render the fake wallet dialogs victims interact with.

Through analysis of the binary’s data segments and configuration structures, Caronte reconstructed the agent’s embedded configuration block:

{
  "version": "1.3",
  "api_url": "http://130.12.180.135:3000/api/v2",
  "api_key": "alk_776...fc1",
  "open_original_wallet_on_valid_seed": true
}

The open_original_wallet_on_valid_seed field is worth noting: when set to true, the agent opens the legitimate wallet application after successfully capturing the seed phrase, so the victim sees their real wallet load normally and has no immediate reason to suspect anything went wrong. It is a deliberate anti-detection measure baked into the configuration.

The configuration was stored without any obfuscation or encryption. More critically, the api_key field is the same credential infected machines use to authenticate back to the C2. There is no separation between agent authentication and API read access: the key that registers a new victim also reads the entire victim list.


Mapping the API Surface: Frontend Bundle Analysis

Before sending a request to the server, Caronte analyzed the React SPA’s webpack bundle served at port 3000. All API route strings were present in the bundled JavaScript:

/api/v2/wallets
/api/v2/antiledger/settings
/api/v2/antiledger-v2/seed-phrases
/api/v2/panel-access/evaluate
/api/v2/backup-domains/active
/api/v2/browser-spoofer/build/{buildId}/status
/api/v2/builds/{buildId}/{filename}

This gave us a complete endpoint map derived from a single bundle fetch, before any active enumeration of the server.


Getting Inside the Panel: Two Independent Access Layers

Analysis of the C2 required two separate techniques that provided different types of visibility. They are worth distinguishing clearly.

Frontend UI: Client-Side-Only Authentication

The React SPA’s authentication logic reads from localStorage to decide whether to render the dashboard or redirect to login. The server plays no role in this routing decision.

Writing two values directly to localStorage in the browser was sufficient:

localStorage.setItem("auth_token", "<structurally valid JWT, exp:9999999999>");
localStorage.setItem("auth_user", JSON.stringify({ username: "admin", role: "admin" }));

With requests to /login intercepted to prevent the app from refreshing auth state, the full admin dashboard rendered. This is not a JWT library bypass; it is the absence of any server-side authentication gate on the UI routing layer, the SPA trusts localStorage unconditionally for rendering decisions.

What this gave us: The panel’s structure, module layout, configuration pages, the overall UI. The C2 stack was confirmed from HTTP response headers (Server: nginx/1.29.8) and bundle metadata (React 19 version strings in the webpack output). The screenshots in this report show the rendered frontend.

What it did not give us: Actual data. Backend API endpoints require a valid signed JWT (HS256) for privileged operations. With only a fake token, API calls from the SPA returned 401s.

Needle C2 Dashboard, overview page showing current domain

Data Access: The Embedded Agent Key

All victim records, withdrawal configuration, and session statistics came from direct API calls using the agent key extracted by Caronte from the binary. This key authenticates the agent-facing endpoints independently of the admin JWT scheme, the same credential infected machines use to register themselves was sufficient to read the entire victim list and operator configuration.

The two techniques are complementary but entirely independent. The frontend bypass revealed the panel’s structure and confirmed it was a live operator platform. The agent key provided all the data.


Two-Pronged Attack Strategy

Browser Wallet Spoofer

The browser module replaces or intercepts legitimate crypto wallet extensions. Victims interact with what appears to be their normal MetaMask or Phantom extension; the fake version intercepts the password or seed phrase on entry and exfiltrates it to the C2.

The builder, running on port 8080 with no meaningful authentication, lets operators configure which wallets to target, installer self-destruction behavior, wait mode, and smart-pin options.

Needle Builder, Browser Wallet Spoofer configuration and wallet selection

Targets include MetaMask, Trust Wallet, Phantom, OKX, TonKeeper, Coinbase, Atomic, Bybit, and Binance Wallet. 111 browser victims were recorded from the API:

WalletVictims
MetaMask48
Trust Wallet30
Phantom20
OKX6
TON3
Binance2
Bybit2
Total111

Polling the /api/v2/wallets endpoint repeatedly during our monitoring window, we observed the count growing by 3 to 5 new entries every few hours. The campaign was actively acquiring victims throughout our observation period.

Desktop Wallet Spoofer

The Rust agent impersonates desktop wallet applications. When a victim opens what they believe is their Exodus, Trezor, or Ledger application, a fake “Restore Wallet” dialog appears and requests their seed phrase. Entered seeds are posted to the C2; if valid and the auto-transfer module is enabled, funds move to the operator’s withdrawal addresses.

Needle Withdrawal Settings, auto-transfer configuration

1,821 desktop sessions were on record at time of data collection, all with awaitingSeed: true, indicating the C2 had registered the infected machines but no seed phrases had been submitted yet. The server-reported total reached 1,825 during continued monitoring, confirming new sessions were accumulating. Whether the absence of submitted seeds reflects early-stage distribution or victims abandoning the fake dialog cannot be determined from the data alone.

Needle Withdrawal Settings, auto-transfer configuration

The withdrawal module supports three automation modes: auto balance check on connect, automatic withdrawal after password entry, and withdrawal triggered by seed phrase submission, all independently toggleable per operator.


Inside the C2: What the Agent Key Unlocked

Attacker Configuration and Fund Movement

GET /api/v2/antiledger/settings returned the full operational configuration: withdrawal addresses for BTC (1PVq...qfZ), LTC (LKmc...DBL), DOGE (D5xE...FFq), SOL (BpxG...YU), TRON (TDij...UNp), and EVM (0xD5...F1b), alongside a TronGrid API key.

TronGrid is the TRON equivalent of Infura, a professional-grade blockchain RPC service. Its presence here indicates the operator has set up automated TRON/USDT balance checking before triggering withdrawal, rather than relying on manual monitoring.

On-chain analysis confirms the operation is actively moving funds. The EVM withdrawal address had approximately $148 in ETH emptied and forwarded to three separate cold wallets at time of analysis. The TRON address held approximately $60 in USDT and TRX. The BTC, LTC, DOGE, and SOL addresses showed no recorded transaction history, consistent with a campaign still in early collection phase for those chains.

Write Access to Withdrawal Configuration

The frontend bundle defines PUT /api/v2/antiledger/settings using the same agent key authentication scheme as the GET endpoint. If the key is accepted on the write path, which the identical auth implementation suggests, the six withdrawal addresses could be replaced with arbitrary addresses, redirecting every future auto-transfer away from the operator.

We did not send any write requests. The implication is reported here because it represents the full consequence of distributing an agent key with no scope restriction: a researcher, a competitor, or a hostile party with access to the sample binary can enumerate this C2’s victims and potentially redirect its earnings.

Needle Profile Page showing API key and session management, fully rendered as admin


Two Instances, One Database

During enumeration we identified a second panel instance at port 8181 on the same host, accepting the same agent key. Cross-referencing seed phrase session IDs confirmed 1,814 records in common out of 1,817 queried from port 3000, near-perfect overlap confirming a shared database backend. The delta reflects the time gap between queries, not a separate deployment.

The shared-database setup is consistent with a MaaS platform providing independent panel access to multiple operators or affiliates without separate infrastructure. Port 8181 returned an empty result set for the browser wallet endpoint; whether this reflects a different module subscription or simply a different API surface for that instance is not possible to determine definitively from the available data.


Indicators of Compromise

Sample:
  SHA256: d6ca3760...a490
  MD5:    8b3433...36ca534b
  Name:   needle_agent_v1.3 (internal)

Network:
  C2 Panel:  130.12.180.135:3000
  Builder:   130.12.180.135:8080
  Secondary: 130.12.180.135:8181
  Stack:     nginx/1.29.8 (Server header), React 19, Express.js
  Hosting:   ASN 202412 Omegatech LTD, Amsterdam (bulletproof hoster)

Persistence:
  Registry:  HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
rule Needle_Crypto_Stealer_v1 {
    meta:
        description  = "Needle MaaS crypto-stealer, Rust desktop agent v1.x, distributed as agent.exe"
        author       = "Beelzebub Research"
        date         = "2026-04-28"
        reference    = "https://beelzebub.ai/blog/needle-c2-crypto-stealer-analysis"

    strings:
        // Needle-specific C2 API path and config field
        $api1 = "antiledger-v2/seed-phrases" ascii
        $api2 = "open_original_wallet_on_valid_seed" ascii

        // Rust panic handler source paths, present in release builds
        $src1 = "src/views/zelcore/app.rs" ascii
        $src2 = "src/views/trezor/seed_panel.rs" ascii
        $src3 = "src/views/ledger/screens/seed_recovery.rs" ascii

        // UI string keys from Needle's fake-wallet dialog logic
        // needle_desktop_wallet_debug.txt is a debug log path embedded in the agent
        // needle.wallet. is a namespace prefix for wallet-specific UI keys
        $ui1  = "checkseed.invalid_message" ascii
        $ui2  = "needle_desktop_wallet_debug.txt" ascii
        $ui3  = "needle.wallet." ascii

    condition:
        // Valid Windows PE (MZ header + PE signature)
        uint16(0) == 0x5A4D and
        uint32(uint32(0x3c)) == 0x4550 and
        // Rust + egui binary size range
        filesize > 5MB and filesize < 50MB and
        // Both Needle-specific API strings must be present
        all of ($api*) and
        // At least one compiled-in Rust source path
        1 of ($src*) and
        // At least two Needle UI strings
        2 of ($ui*)
}

Conclusion

In under two weeks, this Needle deployment registered 1,932 targets across two attack surfaces. The EVM hot wallet had already moved funds to cold storage before we completed our analysis, the operation was not hypothetical.

The complete picture only became available because of how the operator built the agent. Using credentials they distributed inside their own malware, we read their victim list, extracted their withdrawal configuration, and traced their on-chain activity. The Malwarebytes report on a separate Needle campaign confirms this is not an isolated deployment: multiple operators are running simultaneous campaigns on the same platform.


How Caronte Made This Possible

This entire investigation started from a single sample upload. Caronte autonomously recovered the embedded configuration, attributed the infrastructure, generated the YARA rule, and built the threat graph. Work that would have taken a senior reverse engineer days. The human analyst’s role was verification and on-chain correlation, not extraction.

If your SOC is still reverse-engineering samples by hand, you are operating at the speed of the attacker’s first wave, not their last.

Learn how Caronte works

Try Our Managed Platform

Security deception runtime framework with zero false positives
Continuous validation via automated AI Red Teaming
Real-time malware analysis via our CTI Hub
Instant threat containment driven by the AI SOC