FTP Banners: The New Dead Drop Resolver Delivering Novel RATs
STRU found threat actors using FTP banners as Dead Drop Resolvers – legitimate services or protocols abused to host C2 addresses and commands, so the stager never carries them itself. Live since early July 2026 and still active. The infrastructure led to two previously undocumented RATs: E4del, an Electron implant hiding under a signed Discord binary, and PINHOLE, a multi-stage RAT pulling its C2 from Pinterest and SurveyMonkey behind Cloudflare Workers.
Security products have become increasingly effective at detecting suspicious commands used for malware delivery. Consequently, threat actors are adopting more creative methods to bypass these defenses, such as utilizing Dead Drop Resolvers (DDRs): alternative locations, including legitimate web services or protocols, used to acquire malicious strings, Command and Control (C2) configurations, or commands.
During an investigation, the SOCRadar Threat Research Unit (STRU) identified the active abuse of FTP banners as DDRs to distribute malicious commands, a technique observed in the wild since early July 2026. Further infrastructure analysis led to the discovery of two previously undocumented Remote Access Trojans (RATs), which we have named E4del and PINHOLE.
Key Points
- STRU discovered active abuse of FTP banners as DDRs, allowing malware stagers to fetch commands directly from the protocol’s initial response.
- While currently observed in malicious LNK files, this technique is highly versatile and easily adaptable for “ClickFix” social engineering campaigns.
- FTP-based DDRs were found delivering two previously undocumented RATs: E4del and PINHOLE, tracked as separate clusters.
- E4del is a modular, Electron-based RAT offering eight specialized commands, such as live desktop streaming, screenshot capture, and privilege escalation.
- E4del’s beaconing mechanism implements a tiered jitter system, dynamically transitioning between three distinct states (Active, Semi-Active, Inactive) based on the elapsed time since its last received task.
- PINHOLE is a sophisticated multi-stage RAT with fourteen distinct command types, including browser credential theft, file upload/download, and screenshot capture.
- To evade detection, PINHOLE employs Halo’s Gate and Early Bird APC Injection. Additionally, it leverages legitimate platforms like Pinterest and SurveyMonkey to resolve its C2 while proxying its traffic through Cloudflare Workers.
- PINHOLE operators also maintain an “FTP Stats Panel” to track script execution and IP addresses connected to their infrastructure.
FTP Banners as a DDR
Based on a hunt, a post from MalwareHunterTeam was identified. The post was the first to document the capability of LNK files (likely spread through phishing) to use FTP banners as a DDR for fetching commands. While threat actors typically utilize legitimate web services, such as X, GitHub, or YouTube, to provide cover through high-volume, expected network traffic, FTP banners represent a novel alternative. However, this method is less stealthy than traditional web-based DDRs, as security teams are more likely to flag FTP connections to unknown servers as anomalous.
The following figure illustrates the delivery chain of the identified sample. The actors utilized Spanish-language lures, such as a “Voucher” claim, to entice users into executing a shortcut file that retrieves commands from an FTP banner. These commands subsequently connect to a WebDAV server to download and execute a DLL export function via rundll32.exe.

LNK file requesting and executing commands via an FTP banner
Since the infrastructure described in the original post was no longer active at the time of our analysis, we expanded our search for similar commands stored as FTP banners. By utilizing FOFA searches, we determined that this technique has been weaponized since early July 2026 and remains operational, with new infrastructure observed as recently as August 2026.

FOFA search results for commands in FTP banners
Investigation into this live infrastructure revealed two previously undocumented RATs, designated E4del and PINHOLE. We assess these as separate clusters using the same delivery technique. Due to their novelty, evidence is currently insufficient for actor attribution.
| REDUCE YOUR ATTACK SURFACE This infrastructure was located through internet-wide scanning of port 21, the same visibility attackers rely on when selecting targets. SOCRadar’s Attack Surface Management continuously maps external-facing services, including open port 21, and alerts on banner modifications that indicate compromise or staging activity. |
|---|
E4del: An Electron-based RAT Impersonating Discord
Analysis of the FTP banner at 157.254.194[.]31:21 revealed a multi-stage delivery chain. The initial commands fetch a second FTP banner from 167.148.41[.]164:21, which triggers a PowerShell script to download, extract, and execute a binary from a ZIP archive. The chain launches a legitimate Discord binary with the –init argument and the victim’s username.
As an Electron-based application, Discord requires a bundled Chromium and Node.js runtime environment to function. The threat actors exploit this architecture by including the necessary Electron environment files (i.e., d3dcompiler_47.dll and libEGL.dll) and replacing the application’s core logic within the resources/app.asar archive (responsible for bundling the source code and assets of the application).
Upon execution, the operating system identifies a digitally signed Discord.exe loading trusted dependencies, effectively masking the malicious code residing in app_bootstrap/index.js. The final payload is E4del, a Node.js-based RAT that provides extensive capabilities including evasion, persistence, system fingerprinting, and encrypted C2 communication.

E4del RAT delivery chain
Execution & Evasion
Upon execution, E4del immediately evaluates its command-line arguments to dictate its behavior and verify its environment. It looks for the –init flag followed by a username, checking that the current Windows user matches the provided argument. If the username does not match, the RAT terminates immediately. This serves as an anti-sandbox technique, ensuring the payload only detonates on the intended victim’s machine rather than in an automated analysis environment without the required arguments.

–init arguments check
To maintain a zero-visibility profile, E4del dynamically appends several Chromium command-line switches to the underlying Electron application. By invoking switches such as headless, disable-gpu, and mute-audio, the RAT ensures no graphical user interface is ever rendered to the victim, reducing the application to a silent background process.

Command-line switches
Persistence
Furthermore, it establishes persistence by utilizing Electron’s native login item settings (setLoginItemSettings), configuring the host executable (Discord.exe) to launch automatically upon user login with the necessary –init parameters.

Persistence via setLoginItemSettings
System Profiling and Fingerprinting
Before reaching out to the attacker’s infrastructure, E4del conducts a localized fingerprinting phase to profile the infected machine. It generates a unique hardware identifier (HWID) by SHA256-hashing the MAC addresses of the system’s network interfaces alongside the CPU model. This ensures the attacker can uniquely track the infected host across varying network environments.
Following this hardware profiling, the RAT queries Windows Management Instrumentation (WMI) or the system registry to enumerate installed antivirus products, specifically hunting for security solutions like Windows Defender, Symantec, ESET, Avast, McAfee, Sophos, CrowdStrike, and Kaspersky.

HWID generation and AV information
Command and Control (C2)
E4del’s communication protocol is built on encrypted HTTP POST requests directed at a hardcoded C2 server (http[://]157.254.194[.]31). All traffic is secured using AES-256-CBC encryption, relying on a static, hardcoded passphrase (protected!) and a randomly generated Initialization Vector (IV) for each request. To evade basic network detection, the HTTP requests spoof a legitimate Google Chrome User-Agent (Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36) and utilize standard browser headers.
The beaconing mechanism is highly dynamic, implementing a tiered jitter system to blend in with normal network traffic. The RAT dynamically transitions between three distinct states based on the elapsed time since its last received task. Within the first 20 seconds of receiving a command, E4del operates in “Active“ mode, rapidly checking in with random sleep delays between 200 milliseconds and 2 seconds. If no new tasks arrive within 20 to 40 seconds, it enters a ”Semi-Active“ state, lengthening its sleep interval to between 2 and 5 seconds. Beyond 40 seconds of inactivity, the RAT drops into a full ”Inactive“ mode, scaling back check-ins to random delays between 5 and 9 seconds.
![]()
E4del’s tiered jitter system
When transmitting data back to the server, the RAT employs a unique string replacement technique, swapping standard pipe characters with the custom %e4del% delimiter. This prevents shell command outputs from accidentally breaking the attacker’s server-side output parser. Encrypted beaconing requests are sent via HTTP POST in the /beacon endpoint and contain the following structure: “H|${hostId}|${hwid}|${avInfo.name}|${Date.now()}”.
![]()
E4del’s beaconing mechanism
Once the encrypted heartbeat is dispatched, the C2 server responds with encrypted tasks that dictate the RAT’s next actions. E4del supports a robust suite of post-exploitation commands:
| E4del Commands | Function |
|---|---|
| startcmd / runcmd%e4del%[command] | Interactive Reverse Shell startcmd initializes a persistent, hidden cmd.exe child process using Node’s spawn with piped standard I/O streams. It attaches event listeners to capture all stdout and stderr output and funnel it into an internal outputBuffer. Once initialized, the operator uses runcmd%e4del%[command] to inject arbitrary shell commands directly into the stdin of this active shell. The buffered output is subsequently sanitized (replacing pipes with %e4del%) and exfiltrated during the next scheduled C2 beacon. |
| screenshot | Screenshot Capture screenshot invokes Electron’s native desktopCapturer API to query the system’s primary screen. It captures a 1920×1080 frame, compresses it into a JPEG format (at 30% quality to reduce payload size), and converts the binary buffer into a Base64-encoded string. This string is stored in a temporary variable and seamlessly appended to the next encrypted HTTP heartbeat payload using the |SCREENSHOT| delimiter. |
| streamstart[ip:port] / streamstop | Live Desktop Streaming streamstart extracts the provided attacker-controlled IP address and initiates a custom WebSocket client. It establishes a direct TCP socket connection (ws://[IP:PORT]/ws/agent?hostId=[hostId]), performs the HTTP/1.1 WebSocket upgrade handshake, and begins a loop that captures the desktop every 2 seconds. These JPEG buffers are transmitted continuously as raw binary WebSocket frames, creating a hidden Remote Desktop feed. streamstop clears the timeout interval and tears down the socket connection. |
| runpackage%e4del%[token] | Payload Dropper runpackage%e4del%[token] extracts an authentication token and reaches out to the C2’s /api/download?token=[token]&clientId=[hwid] endpoint. It downloads a dynamically generated .zip archive into %LOCALAPPDATA%Packages[token]. E4del then spawns a hidden PowerShell process utilizing Expand-Archive to extract the contents. It recursively searches the extracted files for a config.json, parses it to identify the designated entrypoint executable, and launches it as a fully detached, hidden child process. To cover its tracks, the ZIP archive and JSON configuration are immediately deleted. |
| filedownload%e4del%[token] | Targeted File Deployment Similar to the package runner, filedownload%e4del%[token] uses an authentication token to fetch a specific file from the C2 server (/api/download?token=[token]&clientId=[hwid]). It parses the HTTP Content-Disposition header to determine the correct filename (downloaded_file) and writes the binary data directly into the Electron application’s process.resourcesPath directory. This is typically used to drop secondary modules (like the crypto32.node file that is mentioned next) directly alongside the malicious app.asar. |
| elevate | Privilege Escalation Attempt Executes a secondary instance of the RAT’s own host binary (discord.exe) while passing specific internal arguments (–e and –a). This attempts to load a custom Node.js add-on named crypto32.node from the resources directory (process.resourcesPath) , highly likely downloaded previously with the filedownload%e4del%[token] command. By invoking the .start() function of this module and passing the binary and specific arguments, the RAT attempts a local privilege escalation or UAC bypass to gain administrative rights. We couldn’t recover the crypto32.node file at the time of the analysis. |
| (default) | Standard Shell Execution If the decrypted task string does not match any of the predefined command keywords, the RAT defaults to passing the entire raw string to Node’s child_process.exec() function. The command is executed in a standard, non-persistent system shell with a hardcoded timeout of 15 seconds. Any resulting output, or error messages, are appended to the outputBuffer for exfiltration in the next C2 heartbeat. |
PINHOLE: A Stealthy RAT Leveraging Pinterest & SurveyMonkey as DDRs
In a separate instance of FTP banner abuse, the STRU uncovered a more sophisticated multi-stage delivery chain culminating in the deployment of another novel RAT, which we have designated PINHOLE. This RAT exhibits stealthy capabilities, including the storage of configuration data in Alternate Data Streams, the implementation of the Halo’s Gate and Early Bird APC Injection to bypass Endpoint Detection and Response (EDR) solutions, and the utilization of Pinterest pins and SurveyMonkey questions as DDRs to acquire its C2 and proxy it behind Cloudflare Workers.
Delivery Chain
The FTP banner at 209.99.185[.]38:21 was found to contain commands that utilize the MSXML2.XMLHTTP COM object within PowerShell to retrieve a secondary command script from hxxps[://]cloudflare.milicare[.]in/app/c. This script is saved as %TEMP%u.cmd, executed, and subsequently deleted to minimize the forensic footprint.
The downloaded script functions as a dropper for the final payload. It employs echo commands to write a large block of Base64-encoded data into a file named %TEMP%calc. To evade detection, the data is wrapped in —–BEGIN CERTIFICATE—– and —–END CERTIFICATE—– headers, masquerading as a legitimate certificate file.
The dropper then creates a temporary batch script, %TEMP%calc_runner.cmd, which contains the logic to unpack and execute the smuggled binary. This temporary script leverages certutil -decode to transform the Base64 “certificate” file into a Cabinet archive (%TEMP%calc.cab) and then uses the expand utility to extract and run the final executable, %TEMP%calc.exe. Interestingly, error messages were identified in Spanish. Following execution, the script waits three seconds before deleting all temporary files to maintain operational stealth.

PINHOLE’s delivery chain
The actors behind PINHOLE also maintain a dedicated “FTP Stats Panel” at hxxp[://]69.48.228[.]126:5000/. This interface allows them to monitor the efficacy of their campaigns by tracking script executions, total connections, and unique active or blocked IP addresses interacting with their FTP infrastructure. Interestingly, the script had only run 11 times at the time of analysis, suggesting the campaign was in its early stages.

PINHOLE’s FTP Stats Panel
First Stage: An Evasive Wrapper

PINHOLE’s execution chain
The executed 64-bit binary masquerades as an update utility from a fictitious entity, Weston Computing Systems Ltd. It maintains its stealth by importing only three functions directly and obfuscating the remainder. All strings reside encoded in the .rdata section and are decoded on demand into .bss at runtime using individual 32-bit keys. The binary avoids storing Win32 API string names entirely. Instead, it dynamically resolves APIs at runtime by walking the PEB loader data and matching 32-bit function hashes against module export tables.

File information of the dropped binary
The very first action of the PINHOLE binary is to call a guard that resolves the names of core Windows components like KERNEL32.DLL, kernelbase.dll and ntdll.dll and inspects their Export Address Tables for wildcard templates (xxxx/xxxxx). It specifically looks for synthetic, hollowed-out “stub” DLLs that emulators and analysis environments use to fake a real operating system. If the guard detects these artificial structures, it forces the executable to immediately exit.
Next, it implements the Halo’s Gate evasion technique to dynamically retrieve System Service Numbers (SSNs) for direct system calls, bypassing user-mode EDR hooks. Security tools often monitor software by placing ‘hooks’ inside key system libraries like ntdll.dll.
While earlier techniques like Hell’s Gate fail when an EDR hooks the target function and overwrites its SSN bytes, Halo’s Gate overcomes this by exploiting the fact that Windows assigns SSNs sequentially in memory: if the target function is hooked, it scans neighboring unhooked functions immediately above or below it in memory, extracts their SSNs, and uses simple arithmetic offsets to calculate the target’s actual SSN. SSNs serve as the unique index numbers Windows uses to route low-level kernel requests. Once retrieved, PINHOLE executes system calls directly from its own code to run malicious operations undetected.

Halo’s Gate functionality
Persistence
For persistence, PINHOLE creates a copy of itself in C:\Users\{user}\AppData\Local\Packages\{random_name}\{random_name}.exe and registers it via the registry. It creates a “Load” value located at HKCUSoftwareMicrosoftWindows NTCurrentVersionWindows, which is a legacy Windows feature designed to automatically load programs upon user login.
Alternate Data Streams & C2 Retrieval
Another notable feature of the RAT is its use of host files with NTFS Alternate Data Streams (ADS) as its configuration datastore. PINHOLE stores its build token and C2 DDR encryption key in the ADS of two local desktop.ini files. To conceal its C2 DDRs, the RAT encodes them using a custom base-41 alphabet (0123456789abcdefghijklmnopqrstuvwxyz.-_:/) before encrypting them with a SplitMix64-based PRNG algorithm.
The algorithm seeds its internal state using three rounds of SplitMix64, producing an 8-byte keystream per round. Once decrypted, streams 1, 2, and 3 reveal specific URLs used to fetch C2 infrastructure hosted on legitimate platforms like Pinterest pins and SurveyMonkey survey questions:
| Host file | Stream | Contents |
|---|---|---|
| %USERPROFILE%Downloadsdesktop.ini | bt | 64-hex build token – cc615d23122e1d221d9a1e43d64f121d814f0947d1cd7914a772ede5be5ba280 |
| ek | Encrypted encryption key to decrypt dead drop URLs – 0x6a8b8f4d7a63624b | |
| 1, 2 , 3 | C2 DDR URLs
1 → https://mx.pinterest.com/pin/1128292512937332995 2 → https://mx.pinterest.com/pin/1128292512937332894/ 3 → https://www.surveymonkey.com/r/WW5NVT6 |
|
| %USERPROFILE%Documentsdesktop.ini | ili | Written by the persistence routine – C:\Users\admin\AppData\Local\Packages\{random_name} |
To obtain its C2, PINHOLE uses curl to fetch content from Pinterest pins or SurveyMonkey survey questions.
The HTML response contains hidden C2 settings bounded by the delimiters ====D5===D6==== and ====D7===D8====, which store two colon-separated domains. The first field (D5/D6) represents the actual C2 server (nokierojotiarmx[.]com), while the second (D7/D8) specifies a Cloudflare Worker domain (worker-1785198984-xsekhi[.]api-62c3cac6[.]workers[.]dev) used for proxying.
By leveraging trusted Cloudflare services, the operators conceal traffic from network security controls. PINHOLE constructs its primary request using the format https://<D7/D8 field>/https://<D5/D6 field>, falling back to direct communication (https://<D5/D6 field>) if proxying fails.

PINHOLE’s C2 DDRs
Second Stage Retrieval & Unpacking
Once C2 resolution is complete, PINHOLE verifies server availability by issuing a GET request to {C2}/api/health, validating that it receives an HTTP 200 response containing the string yes. Upon successful validation, the RAT makes a second GET request to {C2}/api/bc to retrieve its next-stage payload, which it then hands off to an Early Bird APC Injection routine into a legitimate process (detailed next). Notably, six layers of unpacking are executed across these steps before final stage execution occurs.

Next stage unpacking transformations
Layer 1 – Dressing as an Image
The C2 response disguises its payload as a JPEG by prefixing it with an SOI/APP0 header (FF D8 FF E0). PINHOLE strips this 4-byte header and decrements every subsequent byte by one to restore the original content. These fake magic bytes camouflage the traffic against content inspection defenses and set the loader’s expected length offset.
Layer 2 – Reading the Container
The recovered payload is actually shellcode which is padded with multi-byte NOPs and benign junk instructions that modify CPU flags without altering registers or the memory state. The actual payload execution begins at offset 0x38 with a call to 0xEB20. This transfers control to an XOR decryption stub and pushes the return address of 0x3D onto the stack, which is the start of the embedded configuration.
Container layout:
| Offset | Size | Contents |
|---|---|---|
| 0x00 | 56 B | Junk prologue + call to XOR stub |
| 0x3D | 60,131 B | Configuration (encrypted) |
| 0xEB20 | ~1.2 KB | XOR stub |
| 0xF000 | 4 KB | Loader (encrypted) |
| 0x10000 | 15,552 B | Next stage payload (encrypted) |
Layer 3 – The Throwaway Stub
The stub routine decrypts the 4 KB loader at 0xF000 using a repeating 4-byte XOR key (1F 3B 39 27) and immediately jumps to it.
Layer 4 – Shellcode Fluctuation
Control now passes to the 4 KB loader, whose purpose is to execute the next-stage payload at 0x10000 without ever exposing it entirely in plaintext.
First, the loader dynamically resolves VirtualProtect, RtlAddVectoredExceptionHandler, and RtlRemoveVectoredExceptionHandler from stack strings encrypted with XOR 0xA1. It then strips execution permissions from the stage payload region (marking it as PAGE_READWRITE via VirtualProtect) and intentionally executes code within that protected boundary.
Attempting to run code from a non-executable page triggers a Data Execution Prevention (DEP) EXCEPTION_ACCESS_VIOLATION (0xC0000005, ExceptionInformation[0] == 8). The loader anticipates this crash, having previously registered a Vectored Exception Handler (VEH) to trap the fault.
Upon intercepting the exception, the VEH validates that the faulting address resides within the payload region, and then:
- Re-encrypts the previously active 4 KB page using a static 64-bit XOR cipher derived from a hardcoded key (0x014D6302A361A315) and the page index.
- Decrypts the target page requested by the CPU.
- Upgrades the target page’s permissions to PAGE_EXECUTE_READ.
- Returns EXCEPTION_CONTINUE_EXECUTION to resume execution seamlessly.
This flow ensures that only a single 4 KB page of the payload remains decrypted and executable at any given time (a mechanism commonly referred to as shellcode fluctuation). A full process memory dump captured at an arbitrary moment yields only one readable page, leaving the remaining ~11 KB fully encrypted.
Statically decrypting all four pages uncovers the underlying payload: a 15.5 KB position-independent loader compiled with MinGW-w64 that resolves API imports via PEB traversal and hash matching. This marks the end of the RAT developer’s custom wrapper code. The remaining payload stages rely on Donut (an open-source shellcode generator) executing its standard initialization, driven by the configuration stored at offset 0x3D since Layer 2.
Layer 5 – Configuration Blob
The configuration blob matches Donut’s native Donut Instance structure: a self-contained header detailing execution targets, compression parameters, required API imports, and decryption keys. The instance is encrypted via Chaskey in Counter (CTR) mode, with its key and initial counter stored in cleartext at the head of the structure.
Donut’s configuration fields:
| Offset | Field |
|---|---|
| 0x00 | uint32 total length |
| 0x004 | 16-byte cipher key (KeyMk) |
| 0x014 | 16-byte CTR counter (KeyCtr) |
| 0x028 | 64-bit Maru hash IV |
| 0x030 | 64 × uint64 API hashes |
| 0x230 | ExitOpt – 1, exit thread |
| 0x234 | Entropy – 3, random names plus encryption |
| 0x23c | api_cnt – 61; Encryption begins here |
| 0x240 | dll_names – ole32;oleaut32;wininet;mscoree;shell32 |
Layer 6 – aPLib Decompression
Preceded by a header detailing its packed and unpacked sizes, the final payload is compressed using the aPLib algorithm. Decompressing the stream yields an exact size match, confirming that all preceding layers were correctly reversed. The extracted final payload is a 119 KB native x86-64 PE executable compiled with MinGW-w64.
Early Bird APC Injection
After retrieving the final stage, PINHOLE injects it into ApplicationFrameHost.exe via Early Bird APC Injection. This is an evasion technique that injects code into legitimate, suspended processes and executes it before the target process’s main entry point or security hooks are initialized. It works by creating a signed Windows process in a suspended state, writing the payload into the allocated memory space of that process, and queuing an Asynchronous Procedure Call (APC) to its main thread. When the process resumes, the APC runs the injected payload before executing the application’s actual code.

Early Bird APC Injection code excerpt
Final Stage: PINHOLE RAT
The final injected executable contains the core RAT functionality of PINHOLE, communicating with its C2 server over HTTP GET and POST requests. The RAT resolves its C2 using the same DDR infrastructure mentioned in the earlier dropping stages.
C2 Endpoints
PINHOLE utilizes five primary HTTP endpoints for beaconing, registration, tasking, and exfiltration:
| Pinhole Endpoint | Method | Purpose |
|---|---|---|
| /api/health | GET | Health Check First it verifies the C2 availability. It expects an HTTP 200 response containing the string yes in the body. |
| /api/client | POST | Client Registration Next it registers the infected host by transmitting system metadata: build_token (bt), key (session key for task polling), username, workstation, version, build, cpu, gpu, ram, disk, drives, private_ip, and privileges. The C2 responds with a client_id and user_id (likely used to differentiate between different operators). |
| /api/tsk | POST | Task Polling & Results Then, to poll for tasks, PINHOLE submits its session key via POST to /api/tsk: {“type”:1,”key”:”1a91dcd678be35849db0329effdaa823″} The C2 responds with HTTP 200 and a tasks array containing a numeric command type and an args object. For example, a list directory command (ls) returns: {“tasks”:[“type”:1, “args”:[]]} Task execution results are sent back to /api/tsk using the following schema: {“type”:2,”key”:”%s”,”task_id”:%d,”success”:%s,”result_type”:%d,”result”:”%s”} The RAT also implements an adaptive jittered sleep mechanism as part of task polling. If no tasks are provided from the C2 in less than 300 seconds, it sleeps from 1 to 4 seconds, otherwise it sleeps from 2 to 2.5 seconds. |
| /api/fls | POST | File Upload Exfiltrates files via multipart form data. |
| /api/fls?type=1&file_id=%lld&key=%s | GET | File Download Fetches remote files to the victim host. |
| /api/stlbrwsr | GET | Browser Stealer Endpoint for the browser-stealer sub-module. (Unavailable during analysis) |
C2 Commands
PINHOLE supports 14 command IDs covering system reconnaissance, file manipulation, execution, screenshot capture, and interactive shell access:
| ID | Command | Function |
|---|---|---|
| 0 | ls | Enumerates files and directories in the target path. |
| 1 | cd | Changes the working directory |
| 2 | pwd | Returns the current working directory path. |
| 3 | upload | Exfiltrates target files to /api/fls via multipart POST requests. |
| 4 | download | Downloads a remote file via /api/fls?type=1&file_id=%lld&key=%s (GET) and writes it to %sdl_%lld. |
| 5 | exec | Executes a payload or binary using ShellExecuteW (defaults to the open verb). |
| 6 | delete | Deletes a specified file via DeleteFileW. |
| 7 | find | Recursively searches the file system across all drives. |
| 8 | ps | Captures running processes via native API NtQuerySystemInformation. |
| 9 | kill | Terminates a process by PID using TerminateProcess. |
| 10 | screenshot | Captures the screen via Windows Imaging Component (WIC) COM interfaces (GetDC → CreateCompatibleDC → CreateDIBSection → BitBlt → WICImagingFactory → CreateStreamOnHGlobal → InitializeFromIStream → CreateEncoder → CreateNewFrame → WritePixels). It encodes the image to JPEG, uploads it as screenshot.jpg via /api/fls, and returns the resulting file_id. |
| 11 | stealer | Downloads the browser stealer module from /api/stlbrwsr and loads it using the same /api/bc second-stage unpacking transformations and injection technique. (Unavailable during analysis) |
| 12 | powershell init | Initializes a persistent PowerShell session using anonymous pipes (CreatePipe) for stdin and stdout. |
| 13 | powershell exec | Executes commands through the live PowerShell pipe. It enforces a 30-second timeout and a 1 MB output buffer cap. |

Excerpt of PINHOLE’s command dispatcher function
Conclusion
The identification of FTP banners as DDRs presents a creative, albeit less stealthy, evolution in malware delivery, allowing threat actors to embed malicious commands directly within the protocol’s banner. Although initial access methods point to shortcut-file phishing, attackers could easily adapt FTP banner abuse for ClickFix campaigns as well. Further exploration of this trend led to the discovery of E4del and PINHOLE, two previously undocumented RATs with distinct operational frameworks. E4del distinguishes itself as a modular, Electron-based RAT that masquerades as legitimate Discord processes while employing a dynamic tiered jitter system for its C2.
In contrast, PINHOLE demonstrates advanced evasion through multi-stage delivery chains that leverage high-reputation platforms like Pinterest and SurveyMonkey for C2 resolution and proxying through Cloudflare Workers, loading additional modules and injecting into legitimate processes via Early Bird APC. Together, these campaigns highlight the persistent trend of actors weaponizing legitimate services and protocols to maintain stealth and operational security.
To defend against these tactics, security teams should restrict unapproved software through application controls, and inspect network traffic for stealthy abuse of trusted platforms and standard services. SOCRadar tracks emerging delivery techniques like FTP banner abuse across its XTI platform, correlating novel infrastructure with the malware families it delivers. To see how your organization’s external exposure and stolen credentials appear to an attacker, request a demo or start with the Free Edition.
MITRE ATT&CK TTPs
| Tactic | Technique ID | Technique Name | Description |
|---|---|---|---|
| Resource Development | T1583.007 | Acquire Infrastructure: Serverless | PINHOLE operators use Cloudflare Workers for proxying their C2 traffic. |
| Initial Access | T1566.001 | Phishing: Spearphishing Attachment | FTP banners are abused in the wild via phishing emails delivering LNK files inside ZIP files. |
| Command and Control | T1071.002 | Application Layer Protocol: File Transfer Protocols | The delivery chains of E4del & PINHOLE fetch multi-stage commands from FTP banners to retrieve instructions. |
| Execution | T1059.001 | Command and Scripting Interpreter: PowerShell | E4del & PINHOLE chains utilize a PowerShell script triggered by the FTP banner to download, extract, and execute the RATs. |
| Execution | T1059.003 | Command and Scripting Interpreter: Windows Command Shell | E4del spawns a hidden cmd.exe child process for interactive reverse shell access. PINHOLE executes temporary batch scripts (u.cmd, calc_runner.cmd) to orchestrate payload decoding and execution. |
| Execution | T1059.007 | Command and Scripting Interpreter: JavaScript | If the decrypted task string from the E4del C2 does not match any of the predefined command keywords, the RAT defaults to passing the entire raw string to Node’s child_process.exec() function. |
| Execution | T1047 | Windows Management Instrumentation | E4del utilizes WMI to query for installed security products. |
| Execution | T1106 | Native API | PINHOLE implements Halo’s Gate to dynamically extract System Service Numbers (SSNs) from unhooked neighbor functions and execute direct syscalls, bypassing EDR hooks. |
| Defense Evasion | T1218.015 | System Binary Proxy Execution: Electron Applications | E4del leverages an Electron application to launch itself. |
| Defense Evasion | T1140 | Deobfuscate/Decode Files or Information | PINHOLE chain leverages certutil -decode to extract Cabinet archive files from Base64 wrappers and expand utility to decompress them. |
| Defense Evasion | T1036.005 | Masquerading: Match Legitimate Resource Name or Location | E4del executes malicious JavaScript (app_bootstrap/index.js) under a digitally signed Discord.exe process accompanied by bundled Electron/Chromium runtime files (d3dcompiler_47.dll, libEGL.dll). PINHOLE masquerades as an update utility from a fictitious company (“Weston Computing Systems Ltd“). |
| Defense Evasion | T1497.001 | Virtualization/Sandbox Evasion: System Checks | E4del checks for the –init flag and verifies if the logged-in Windows username matches the provided argument; if it does not match, execution terminates to prevent automated sandbox analysis. PINHOLE inspects DLL Export Address Tables for wildcard patterns (xxxx/xxxxx) to detect emulator/sandbox hollowed-out “stub” DLLs and cleanly exit. |
| Defense Evasion | T1564.003 | Hide Artifacts: Hidden Window | E4del launches Electron using command-line flags such as headless, disable-gpu, and mute-audio to run without rendering a graphical user interface. |
| Defense Evasion | T1070.004 | Indicator Removal: File Deletion | E4del automatically deletes the downloaded .zip archive and its config.json file after extracting and executing secondary packages via runpackage. PINHOLE deletes temporary files (u.cmd, calc, calc_runner.cmd, calc.cab) within seconds of execution to reduce forensic footprint. |
| Defense Evasion | T1564.004 | Hide Artifacts: NTFS File Attributes | PINHOLE stores build tokens, encryption keys, DDR URLs, and installation paths within NTFS Alternate Data Streams (ADS) inside desktop.ini files. |
| Defense Evasion | T1027 | Obfuscated Files or Information | PINHOLE contains base64-encoded binary data wrapped in fake —–BEGIN CERTIFICATE—– headers, encrypted stage payloads using XOR/aPLib/Chaskey, and string encoding with per-string 32-bit keys. |
| Defense Evasion | T1055.004 | Process Injection: Asynchronous Procedure Call | PINHOLE injects the final stage code via Early Bird APC Injection, spawning ApplicationFrameHost.exe in a suspended state and executing the payload before main initialization. |
| Persistence | T1547.001 | Boot or Logon Autostart Execution: Registry Run Keys / Startup Folder | E4del uses Electron’s native setLoginItemSettings API to configure Discord.exe to launch automatically upon user login with the –init parameter. PINHOLE creates a Load value under HKCUSoftwareMicrosoftWindows NTCurrentVersionWindows pointing to the persistent copy in %LOCALAPPDATA%Packages{random_name}{random_name.exe}. |
| Discovery | T1082 | System Information Discovery | E4del generates a unique Hardware Identifier (HWID) by SHA256-hashing system MAC addresses and the CPU model string. PINHOLE gathers baseline host metadata during host registration (/api/client), including username, workstation, CPU, GPU, RAM, disk specs, and private IP. |
| Discovery | T1057 | Process Discovery | PINHOLE leverages NtQuerySystemInformation via Command 8 (processes) to collect the active process list. |
| Discovery | T1083 | File and Directory Discovery | PINHOLE includes commands for recursive directory listings, path printing, and drive searches (ls, pwd, find). |
| Discovery | T1518.001 | Software Discovery: Security Software Discovery | E4del queries WMI or the system registry to check for installed security software (e.g., Windows Defender, CrowdStrike, Kaspersky). |
| Discovery | T1012 | Query Registry | E4del queries the registry to check for installed security software. |
| Discovery | T1033 | System Owner/User Discovery | E4del reads local system environment variables (os.userInfo().username, os.hostname()) to verify the username and form the host identifier string. |
| Privilege Escalation | T1548 | Abuse Elevation Control Mechanism | E4del executes the binary passing internal –e and –a arguments to attempt privilege escalation via crypto32.node. |
| Collection | T1113 | Screen Capture | E4del captures primary desktop displays as JPEG buffers using Electron’s desktopCapturer API via the screenshot command or continuous WebSocket streaming (streamstart). PINHOLE captures a screenshot through the WIC utility and exfiltrates it to the C2. |
| Collection | T1555.003 | Credentials from Password Stores: Credentials from Web Browsers | PINHOLE includes a dedicated module endpoint (/api/stlbrwsr / Command 11) designed to retrieve and run a browser credential stealer. |
| Exfiltration | T1041 | Exfiltration Over C2 Channel | PINHOLE uploads exfiltrated files and screen captures back to the C2 via HTTP multipart POST requests to /api/fls. |
| Command and Control | T1102.001 | Web Service: Dead Drop Resolver | PINHOLE utilizes Pinterest pins and SurveyMonkey questions to store encoded C2 addresses (D5/D6 and D7/D8 markers). |
| Command and Control | T1071.001 | Application Layer Protocol: Web Protocols | E4del communicates with the C2 server over HTTP POST requests (/beacon) and uses raw TCP sockets via WebSockets (ws://[IP:PORT]/ws/agent) to continuously stream JPEG frames. PINHOLE communicates with the C2 over standard HTTP GET and HTTP POST requests for polling, system registration, and task execution. |
| Command and Control | T1090 | Proxy | PINHOLE uses Cloudflare Workers as outer fronting hosts (worker-1785198984-xsekhi[.]api-62c3cac6[.]workers[.]dev) to proxy traffic and mask the primary C2 server. |
| Command and Control | T1573.001 | Encrypted Channel: Symmetric Cryptography | E4del encrypts HTTP POST C2 beacon payloads using AES-256-CBC with a static passphrase (protected!) and random Initialization Vectors (IVs). |
| Command and Control | T1205 | Traffic Signaling | E4del implements a tiered jitter sleeping system (“Active”, “Semi-Active”, “Inactive”) based on task activity to dynamically shift check-in intervals. |
| Command and Control | T1105 | Ingress Tool Transfer | E4del downloads secondary ZIP packages (runpackage) or standalone files like crypto32.node (filedownload) into AppData or Electron resource directories. |
IoCs
The indicators below can be checked against your environment using IOC Radar, SOCRadar’s free threat intelligence lookup for IPs, domains, hashes, and URLs.
Network Indicators
| Type | Indicator | Description |
|---|---|---|
| IP Address | 209[.]99[.]185[.]38 | FTP banner containing commands delivering PINHOLE, FTP Stats Panel |
| IP Address | 69[.]48[.]228[.]126 | FTP banner containing commands, FTP Stats Panel |
| IP Address | 72[.]5[.]43[.]81 | FTP banner containing commands |
| IP Address | 45[.]61[.]136[.]50 | FTP banner containing commands |
| IP Address | 45[.]87[.]41[.]133 | FTP banner containing commands |
| IP Address | 185[.]14[.]92[.]162 | FTP banner containing commands |
| IP Address | 64[.]95[.]13[.]65 | FTP banner containing commands |
| IP Address | 157[.]254[.]194[.]31 | FTP banner containing commands, E4del C2 |
| IP Address | 167[.]148[.]41[.]164 | FTP banner containing commands delivering E4del RAT |
| URL | ws://[IP:PORT]/ws/agent?hostId=[hostId] | E4del stream capture WebSocket URL |
| URL | hxxps[://]157[.]254[.]194[.]31:21/api/download?token=[token]&clientId=[hwid] | E4del File / ZIP Download URL |
| URL | hxxps[://]157.254.194[.]31/beacon | E4del RAT beacon URL |
| URL | hxxps[://]cloudflare.milicare[.]in/app/c | PINHOLE dropper URL |
| URL | hxxp[://]69.48.228[.]126:5000/ | PINHOLE’s FTP Stats Panel |
| URL | hxxp[://]209.99.185[.]38:5000/ | PINHOLE’s FTP Stats Panel |
| URL | hxxps[://]worker-1785198984-xsekhi.api-62c3cac6.workers[.]dev/hxxps[://]nokierojotiarmx[.]com | PINHOLE’s C2 |
| URL | hxxps[://]worker-1785198984-xsekhi.api-62c3cac6.workers[.]dev/hxxps[://]nokierojotiarmx[.]com/api/health | PINHOLE C2 health check |
| URL | hxxps[://]worker-1785198984-xsekhi.api-62c3cac6.workers[.]dev/hxxps[://]nokierojotiarmx[.]com/api/bc | PINHOLE C2 stage 2 retrieval |
| URL | hxxps[://]worker-1785198984-xsekhi.api-62c3cac6.workers[.]dev/hxxps[://]nokierojotiarmx[.]com/api/client | PINHOLE C2 host registration & system data exfiltration |
| URL | hxxps[://]worker-1785198984-xsekhi.api-62c3cac6.workers[.]dev/hxxps[://]nokierojotiarmx[.]com/api/tsk | PINHOLE C2 task polling and result submission |
| URL | hxxps[://]worker-1785198984-xsekhi.api-62c3cac6.workers[.]dev/hxxps[://]nokierojotiarmx[.]com/api/fls | PINHOLE C2 file upload |
| URL | hxxps[://]worker-1785198984-xsekhi.api-62c3cac6.workers[.]dev/hxxps[://]nokierojotiarmx[.]com/api/fls?type=1&file_id=%lld&key=%s | PINHOLE C2 file download |
| URL | hxxps[://]worker-1785198984-xsekhi.api-62c3cac6.workers[.]dev/hxxps[://]nokierojotiarmx[.]com/api/stlbrwsr | PINHOLE C2 browser stealer |
| URL | hxxps[://]mx.pinterest[.]com/pin/1128292512937332995 | PINHOLE’s C2 DDR |
| URL | hxxps[://]mx.pinterest[.]com/pin/1128292512937332894/ | PINHOLE’s C2 DDR |
| URL | hxxps[://]www.surveymonkey[.]com/r/WW5NVT6 | PINHOLE’s C2 DDR |
| Domain | nokierojotiarmx[.]com | PINHOLE primary C2 |
| Domain | worker-1785198984-xsekhi.api-62c3cac6.workers[.]dev | Cloudflare Worker domain used to proxy PINHOLE’s C2 traffic |
Host Indicators
| Type | Indicator | Description |
|---|---|---|
| SHA256 | 117b2b7e7c0deee1f7bf0f154babc09738eac18e810625fab4f54dc8088d731c | d.zip – E4del RAT |
| SHA256 | e0c41dc44368efdf504b28ce015dd3e91f4e711db12e92c159173f75b5320ddb | app_bootstrap/index.js – E4del NodeJS main |
| SHA256 | fcc6fdf40f4dea8f508ef0b8c45a657461310a3f7947a8c687b476e0f0b41e26 | app.asar – E4del RAT |
| SHA256 | 391a605878222f23bf5900a07bc17bedcbda124fb0738d50f6bbb0c1762ae172 | u.cmd – PINHOLE dropper |
| SHA256 | 27587e078b59173a92cf9746ab1839da9196089c00e8b694860361da309142a5 | calc.exe – PINHOLE |
| SHA256 | af769f3bff848bac7b73bf749769424b3df6c9175388980d99e0d6d0193237ba | api/bc fake JPEG – second stage PINHOLE |
| SHA256 | ff88974f51918238f0ea9a74f013ff3ac3c536fce369ead5252ed0137fd32d9e | final_stage – PINHOLE |
| File Path | C:\Users\<Username>\AppData\Local\Packages\<Token_String> | E4del RAT staging ZIP file from runpackage command |
| File Path | C:\Users\<Username>\AppData\Local\discord\resources\crypto32.node | E4del RAT privilege escalation module |
| File Path | %TEMP%u.cmd | PINHOLE dropper path |
| File Path | %TEMP%calc | PINHOLE base64-encoded payload masquerading as a certificate file |
| File Path | %TEMP%calc_runner.cmd | PINHOLE temporary stager script |
| File Path | %TEMP%calc.cab | PINHOLE intermediate Cabinet archive extracted from decoded base64 payload |
| File Path | %TEMP%calc.exe | PINHOLE first stage executable |
| File Path | %TEMP%{key}dl_{file_id} | PINHOLE output path template for files downloaded via C2 command 4 (download) |
| File Path | C:\Users\{Username}\AppData\Local\Packages\{random_name}\{random_name}.exe | Persistent copy of PINHOLE first stage in registry HKCUSoftwareMicrosoftWindows NTCurrentVersionWindows with value Load |
| File Path | %USERPROFILE%Downloadsdesktop.ini:bt | ADS storing PINHOLE’s build token (cc615d23122e1d221d9a1e43d64f121d814f0947d1cd7914a772ede5be5ba280) |
| File Path | %USERPROFILE%Downloadsdesktop.ini:ek | ADS storing PINHOLE’s DDR encryption key (0x6a8b8f4d7a63624b) |
| File Path | %USERPROFILE%Downloadsdesktop.ini:1 | ADS storing PINHOLE’s encrypted #1 DDR URL (Pinterest) |
| File Path | %USERPROFILE%Downloadsdesktop.ini:2 | ADS storing PINHOLE’s encrypted #2 DDR URL (Pinterest) |
| File Path | %USERPROFILE%Downloadsdesktop.ini:3 | ADS storing PINHOLE’s encrypted #3 DDR URL (SurveyMonkey) |
| File Path | %USERPROFILE%Documentsdesktop.ini:ili | ADS storing PINHOLE’s persistence installation path (C:\Users\{Username}\AppData\Local\Packages\{random_name}) |


