Tsundere Bot: Hunting the Initial Access Broker Pipeline to Ransomware
The ransomware ecosystem keeps evolving. Initial access brokers (IABs) are leading the charge. Proofpoint recently documented TA584's adoption of Tsundere Bot, a Node.js-based malware-as-a-service platform that's becoming the new favorite for establishing persistent access before ransomware hits.
I run MDR operations at Crayon. IAB activity is often the first warning sign that a customer might be weeks away from a ransomware incident. Today I'm sharing detection strategies for catching TA584's attack chain before it progresses to data exfiltration or encryption.
Understanding the TA584 Attack Chain
TA584 has tripled their activity since early 2025. They've expanded targeting beyond North America to include Europe and Australia. Their current attack chain is clever:
- Initial Contact: Emails sent from compromised, aged accounts via SendGrid/Amazon SES
- Filtering: Geofencing, IP filtering, and redirect chains through traffic direction systems (Keitaro TDS)
- Social Engineering: CAPTCHA followed by ClickFix page with PowerShell instructions
- Payload Delivery: Obfuscated script loads XWorm or Tsundere Bot into memory
- Persistence: Tsundere Bot establishes C2 via Ethereum blockchain (EtherHiding technique)
- Monetization: Access sold on built-in marketplace, often to ransomware affiliates
What makes Tsundere Bot dangerous? It uses blockchain for C2 resolution. Traditional network-based blocking doesn't work against the initial beacon. That's a problem.
Detection Strategies: Advanced Hunting in Defender XDR
Here are the hunting queries I've developed to catch this attack chain at multiple stages:
Detecting ClickFix PowerShell Execution
The ClickFix technique relies on users manually running PowerShell. This creates a distinctive pattern:
// Detect PowerShell launched from browser context with encoded commands
DeviceProcessEvents
| where Timestamp > ago(24h)
| where FileName =~ "powershell.exe" or FileName =~ "pwsh.exe"
| where ProcessCommandLine has_any ("-enc", "-encodedcommand", "FromBase64", "IEX", "Invoke-Expression")
| where InitiatingProcessFileName in~ ("chrome.exe", "msedge.exe", "firefox.exe", "brave.exe")
| extend DecodedCommand = base64_decode_tostring(
extract(@"-[eE](?:nc|ncodedcommand)\s+([A-Za-z0-9+/=]+)", 1, ProcessCommandLine))
| project Timestamp, DeviceName, AccountName, ProcessCommandLine, DecodedCommand, InitiatingProcessFileName
| where isnotempty(DecodedCommand) or ProcessCommandLine has "http"
Hunting for Node.js-Based Malware (Tsundere Bot Indicator)
Tsundere Bot requires Node.js. It installs Node if it's not already there:
// Suspicious Node.js installations and executions
let nodeInstalls = DeviceFileEvents
| where Timestamp > ago(7d)
| where FileName endswith "node.exe" or FolderPath contains "nodejs"
| where ActionType == "FileCreated"
| summarize InstallTime = min(Timestamp) by DeviceId, DeviceName;
DeviceProcessEvents
| where Timestamp > ago(7d)
| where FileName =~ "node.exe"
| where ProcessCommandLine has_any (".js", "eval", "require", "child_process")
| join kind=inner nodeInstalls on DeviceId
| where Timestamp > InstallTime
| where datetime_diff('hour', Timestamp, InstallTime) < 24
| project Timestamp, DeviceName, AccountName, ProcessCommandLine, InstallTime
| extend SuspicionReason = "Node.js execution shortly after fresh install"
Detecting Ethereum Blockchain C2 Resolution
The EtherHiding technique queries blockchain APIs:
// Network connections to Ethereum RPC endpoints
DeviceNetworkEvents
| where Timestamp > ago(24h)
| where RemoteUrl has_any (
"infura.io",
"alchemy.com",
"etherscan.io",
"cloudflare-eth.com",
"eth.llamarpc.com"
)
| where InitiatingProcessFileName !in~ ("chrome.exe", "msedge.exe", "firefox.exe", "brave.exe")
| summarize
ConnectionCount = count(),
UniqueEndpoints = dcount(RemoteUrl),
Processes = make_set(InitiatingProcessFileName)
by DeviceName, DeviceId, bin(Timestamp, 1h)
| where ConnectionCount > 5 or "node.exe" in (Processes)
WebSocket C2 Communication Pattern
Tsundere Bot uses WebSockets for C2:
// Unusual WebSocket connections from non-browser processes
DeviceNetworkEvents
| where Timestamp > ago(24h)
| where RemotePort in (80, 443, 8080, 8443)
| where InitiatingProcessFileName !in~ ("chrome.exe", "msedge.exe", "firefox.exe", "teams.exe", "slack.exe")
| where InitiatingProcessCommandLine has_any ("ws://", "wss://", "socket", "websocket")
| project Timestamp, DeviceName, InitiatingProcessFileName, RemoteIP, RemotePort, RemoteUrl
| summarize Connections = count(), IPs = make_set(RemoteIP) by DeviceName, InitiatingProcessFileName
| where Connections > 10
Full Attack Chain Correlation
// Correlate ClickFix → Node.js install → Blockchain C2 → WebSocket activity
let clickfixEvents = DeviceProcessEvents
| where Timestamp > ago(24h)
| where FileName =~ "powershell.exe"
| where InitiatingProcessFileName in~ ("chrome.exe", "msedge.exe")
| where ProcessCommandLine has_any ("-enc", "IEX", "http")
| project ClickFixTime = Timestamp, DeviceId, DeviceName;
let nodeEvents = DeviceProcessEvents
| where Timestamp > ago(24h)
| where FileName =~ "node.exe"
| project NodeTime = Timestamp, DeviceId, NodeCommand = ProcessCommandLine;
let blockchainEvents = DeviceNetworkEvents
| where Timestamp > ago(24h)
| where RemoteUrl has_any ("infura.io", "alchemy.com", "etherscan.io")
| project BlockchainTime = Timestamp, DeviceId, BlockchainUrl = RemoteUrl;
clickfixEvents
| join kind=inner nodeEvents on DeviceId
| where NodeTime between (ClickFixTime .. (ClickFixTime + 1h))
| join kind=leftouter blockchainEvents on DeviceId
| where BlockchainTime between (NodeTime .. (NodeTime + 30m))
| project DeviceName, ClickFixTime, NodeTime, BlockchainTime, NodeCommand, BlockchainUrl
| extend AttackChainConfidence = iff(isnotempty(BlockchainUrl), "High", "Medium")
Immediate Response Playbook
When these detections fire, time matters. IABs typically maintain access for days to weeks before selling to ransomware operators. You have a window. Use it.
Phase 1: Rapid Triage (0-30 minutes)
- Isolate the device via Defender for Endpoint
- Check for lateral movement: Query the account's recent authentications across your tenant
- Identify the email: Trace back to the initial phishing message for IOCs
Phase 2: Scope Assessment (30 min - 2 hours)
- Hunt for other victims: Search for the same sender, subject patterns, or URLs
- Check for Node.js installations across the fleet
- Review blockchain API connections tenant-wide
Phase 3: Eradication
- Kill malicious processes and remove Node.js if it was illegitimately installed
- Reset credentials for affected accounts
- Block IOCs: Sender addresses, domains, file hashes
- Report to email providers: SendGrid/Amazon SES abuse channels
Proactive Defenses
Beyond detection, consider these preventive measures:
Application Control: If your organization doesn't need Node.js, block it via AppLocker or WDAC. This single control would break Tsundere Bot completely.
PowerShell Constraints: Enable Constrained Language Mode and script block logging. ClickFix techniques become much more visible with proper logging.
Email Authentication: Ensure SPF, DKIM, and DMARC are enforced. While TA584 uses compromised accounts, many of their messages fail authentication checks.
User Awareness: Train users to recognize ClickFix pages. The "run this PowerShell command" instruction is a major red flag. Technical users can learn to spot it.
The Bigger Picture
TA584's adoption of Tsundere Bot shows how the initial access broker market keeps professionalizing. The malware's built-in marketplace for selling compromised hosts creates a direct pipeline to ransomware groups.
In our MDR operations at Crayon, we see IAB activity as an increasingly reliable leading indicator of future ransomware incidents. The window between initial compromise and ransomware deployment has shrunk. Sometimes it's just days.
The good news: this attack chain has multiple detection opportunities. From ClickFix social engineering to the distinctive Node.js + blockchain C2 pattern, defenders have several chances to catch and contain this before it escalates.