Three days is the average time between a high-severity vulnerability becoming public and its exploitation, according to the latest Quarterly Threat Landscape Report from Rapid7. And 71% of the exploitation tracked in Q3 occurred within the first seven days.
For security teams already managing growing vulnerability backlogs, this creates a difficult question: How do you reduce exposure when attackers can exploit vulnerabilities before your next patching window?
Rapid7's Q3 2026 research brings together vulnerability intelligence, ransomware activity, APT tracking, and underground forum intelligence to show where attacker activity is concentrated.
The exploitation window has narrowed, big time
Rapid7 tracked 43 newly exploited high- and critical-severity vulnerabilities this quarter, down 7% from Q2 but still 19% higher than the same period last year.
The number of newly exploited vulnerabilities isn't growing at the same rate as disclosures. The more pressing concern is how quickly attackers exploit the vulnerabilities they choose. On average, exploitation occurred just three days after public disclosure. The report also found that 80% of tracked exploitation occurred within 14 days and 90% within 30 days.
That timeline creates a serious challenge for organizations relying on fixed remediation schedules. It also reinforces the need to distinguish between vulnerabilities that are theoretically severe and those that pose an immediate, exploitable risk.
The report examines the exploitation timeline in greater detail, including the vulnerability characteristics that make certain exposures particularly attractive to attackers.
Attackers are exploiting vulnerabilities that require no interaction
Q3's vulnerability data reveals another concerning pattern: Of the 43 newly exploited high- and critical-severity vulnerabilities tracked, 34 (79%) required no authentication or user interaction.
This provides attackers a potential path into exposed systems, no stolen credentials or malicious content interaction necessary. An internet-facing service with an exploitable vulnerability may require immediate attention, particularly when an attacker can reach it without authenticating.
This makes attack surface visibility and contextual prioritization essential. Security teams need to understand which systems are externally accessible, which vulnerabilities are actively exploited, and whether existing controls can prevent or limit compromise.
A CVSS score alone won’t give you the answers. The report explores the characteristics of exploited vulnerabilities and why understanding reachability is critical to reducing risk.
AI is taking on a more operational role in attacks
In Q3, 8% of the threat reporting tracked by Rapid7 cited AI as an operational component. The research identifies a shift from using AI primarily to help draft content or code toward supporting tactical decisions and execution within attack campaigns.
In the documented cases, human operators continued to select targets and determine objectives, but relied on AI assistance for technique selection, target assessment, and adapting when an attack step failed.
The report also examines how threat actors split malicious objectives across multiple AI sessions to evade provider safeguards. There are serious implications for detection in these findings. AI-enabled attacks also reinforce the value of monitoring and quickly adapting to attacker behavior rather than relying exclusively on known malware signatures or threat actor identities.
The report provides additional context on how AI appeared in tracked campaigns and what defenders should monitor.
The next step: Prioritize exposure before attackers exploit it
Q3's findings reveal a challenge that vulnerability counts alone can’t explain. Attackers exploited 43 newly tracked vulnerabilities this quarter, yet the average exploitation window was just three days. Meanwhile, underground forum monitoring identified 41 posts advertising RDP or network access, demonstrating continued interest in selling access to compromised environments.
Security teams must account for both the vulnerabilities attackers can exploit directly and the access they can obtain through other means.
Start by identifying externally accessible assets and the vulnerabilities affecting them. Prioritize known exploitation, unauthenticated access paths, and systems supporting critical business functions. Where immediate remediation isn't possible, assess compensating controls and detection coverage.
The latest Rapid7 Quarterly Threat Landscape Report brings together vulnerability research, ransomware intelligence, nation-state activity, and dark web monitoring to help security teams understand where threats are concentrated and what to address first. Download and read it now.
Rapid7 tracked a set of Linux samples that blend into the software and device conventions of the telecom environments they target. The set spans a newly observed BPFDoor variant, a BPF Rekoobe build seen against South Korean targets, a dropper, and six builds of a Linux implant we track as AVERAT, deployed against Taiwanese appliances. Additionally, we provide source code details of the Rapid7 BPFDoor controller introduced in our April 2026 blog, Stealthy BPFDoor Variants are a Needle That Looks Like Hay.
The chain uses two binaries. A dropper writes a shell script to the appliance's storage mount and executes it. The script stages both payloads into /sbin under the names ntpdate and udevds, launches them, and deletes each file ten seconds later while the processes continue running. One of those payloads is the dropper itself, re-executing as a resident watchdog, leaving both processes running without an on-disk image.
The dropper derives its encryption key from the string ShareTech and lives in the appliance's own add-on package directory. The BPFDoor variants seen against South Korean systems impersonate the PID file of SpamSniper, a Korean anti-spam product, and rotate through ten Linux daemon names. Across the samples, each component adopts names and conventions designed to look unremarkable in the environment it targets.
The common thread is regionalized disguise: each sample is aware of the vendor’s software running on the targeted systems and implements process spoofing accordingly. Passive BPF implants avoid conventional port scans; while outbound beacons hide inside ordinary DNS, TCP, and traffic, the threat-actor(s) are leveraging SMTP to stay under the radar. Telecommunications and network-edge operators are most affected, including embedded devices such as CCTV and DVR systems that can sit close to the network core. Readers will learn how each component works, what binds the six AVERAT builds to one another, and which behaviors and indicators to hunt for.
Technical analysis
Rapid7 BPFDoor controller
Figure 1: Overview of BPFDoor HTTP-tunneled trigger flow through edge proxy
⠀
Following our introduction of the Rapid7 BPFDoor controller, published in March, this section examines new features from the reconstructed source code.
Earlier BPFDoor variants relied on raw "magic bytes" (like 0x7255 or 0x5293) sitting in the TCP or UDP headers. Once security vendors wrote static network signatures (Suricata/Snort) to detect these Layer 4 anomalies, the operators began targeting the edge proxies. By wrapping the magic packet in standard HTTPS POST requests and relying on SSL offloading common in telecom environments, the trigger can be delivered to the BPFDoor-infected node in a way that may evade conventional deep packet inspection.
Because proxies alter HTTP headers (adding X-Forwarded-For and changing User-Agent lengths), the malware can no longer rely on static byte offsets to find its payload. To solve this, the new controller sends fake, benign-looking web requests (e.g., POST /admin/login.aspx?id=99990) that are mathematically padded. This guarantees that the string "9999" lands at exactly offset 26 of the TCP payload consistently.
The backdoor uses this "9999" as a reference point, dynamically scans for the \r\n\r\n terminator, and extracts the hex-encoded command payload from the HTTP body.
The dogetlogin function contains the hardcoded paths blending in with legitimate requests:
Figure 2: Hardcoded web login paths used by the dogetlogin function
⠀
When running, the controller spoofs the identity of /usr/sbin/abrtd via set_proc_name and PR_SET_NAME. The #ifndef SOLARIS compiles safely across different operating systems, applying the abrtd disguise only where the Linux-specific prctl function is supported.
Figure 3: Process name spoofing logic applying the abrtd disguise on non-Solaris systems
⠀
The table below lists the Rapid7 controller flags, with new features identified relative to the TrendAI analysis marked accordingly.
Switch
Variable/Action
Description
-h
destip
Specifies the target host (the infected machine's IP address) to control.
-d
dport
Sets the destination port on the infected host to send the trigger packet to.
-l
lhost
Sets the remote IP address that the infected machine will connect back to (Reverse Shell).
-s
lport
Sets the destination port to listen for incoming connections on the attacker's machine.
-m
self = 1
Sets the attacker's local IP address as the remote host, automatically setting up the local listener (overwrites -l).
-b
bport
Instructs the controller to bind to a specified TCP port locally (Bind Shell mode).
-n
nopass = 1
Sends the packet without prompting for a password (sends an empty/hashed password). Often used just to check if the backdoor is alive.
-i
raw = 2
ICMP mode. Embeds the magic packet into an ICMP Echo Request.
-u
raw = 3
UDP mode. Sends the magic packet via a UDP datagram.
-w
raw = 1
TCP mode. Sends the magic packet via a raw TCP SYN packet.
-f
magic_flag
Allows the operator to manually define a custom magic byte sequence (integer value).
-o
magic_flag = 0x5571
Quick-sets the magic bytes/flag to 0x5571.
-H
hdestip
[NEW] Specifies a secondary "hidden" IP address to embed inside the newly added hip field used to relay the magic packet.
-g
gethost
[NEW] Activates the HTTPS POST tunneling mode (dogetlogin).
-D
dir
[NEW] Customizes the URI directory path to blend into specific web server logs when using the -g (HTTPS POST) mode.
-v
debug = 1
[NEW] Enables verbose/debug mode, which is particularly useful for printing out the crafted HTTP requests and responses.
-t
tmout
[NEW] Sets a custom timeout value.
-c
break;
[DEPRECATED] Parses the flag but takes no actions
Table 1: Rapid7 BPFDoor Controller Flags and Descriptions
A new BPFDoor variant tied to the South Korean cluster
The BPFDoor variants create a raw PF_PACKET socket, attaching a classic BPF filter matching Rapid7 Variant F and using magic bytes 0x6693 (UDP), 0x4274 (TCP) and 0x7820 (ICMP). On a match, the implant extracts the source address and connects back to the sender if the password is gZbpx0, opens a bind shell if the password is sT21xf, and otherwise defaults to a UDP knock.
Strings are hidden with a rotating substitution alphabet. Decoding reveals a direct product-spoofing artifact and a set of service-name disguises. The SpamSniper /var/run/spamsniper.pid mutex, together with the sample provenance, ties this build to the South Korean cluster.
SpamSniper is antispam software used mainly in South Korea, so this masquerade is consistent with targeting a Korean mail or telecom environment. The variants a37ea9897221d4495b538de72b74f2aa1d2ff09b7b6dcedd395aee58931adbf3 and 7e667ba5f9df912e02275d3cfe3809d16f822fe776f4035c84b118ebd925b1b5 share the same filter, packet parser, callback, and command paths.
The data plane variant
The BPFDoor sample (a6f3b7f932761fb1fd5e74123f2482e36c65dd13e769af2ce08c65da195bfa7a) attaches a SOCK_RAW 16-BPF instructions parsing IP/TCP offsets and gates on a 14-byte payload (2B 76 C0 63 83 E9 5F E1 EE 69 3F 32 CD 94, unique per sample).
Figure 4: BPF filtering for abc00922 TCP magic bytes
⠀
It spoofs its process name to ora_ppmond, mimicking the naming convention of Oracle-backed telecom subscriber and provisioning platforms (HSS, OSS/BSS), a disguise that only reads as legitimate on hosts actually running that class of infrastructure. Once triggered, it opens a stock Tiny Shell session and dispatches single-byte 'S'/'U'/'D' commands — interactive shell, upload, download — the same switch-case and iptables NAT-redirect staging/teardown logic found byte-for-byte in a second sample 4435fcd6862921092614dbeaa880e4192352984686ebcd98f0ba13ee8e226ef9 (the latter spoofing /sniper/snipe/bin/dtnpd and /sniper/bin/ofgmd). These samples show BPFDoor operating as a modular framework that adapts to the telecom layer it targets, integrating Tiny Shell and Rekoobe logic to support exfiltration.
Figure 5: Tinyshell logic integrated into BPFDoor
⠀
BPF Rekoobe
The sample 652508a9cf40bee883dc0e5e219dfeba71fe7dac591d01c89f74c21f73b4963f is a Rekoobe-based backdoor. It attaches a 26 BPF instruction filter, sniffing for TCP/UDP/SCTP IPv4 and UDP IPv6 traffic with source and destination ports equal 25. Strings are protected with a repeating-key XOR routine (uvTIgh47,@#R), which decodes internal markers and command tokens. The magic packet is authenticated against a 32-byte sequence: 5C A3 1E F9 72 84 DB 40 26 9F C8 35 E1 7D 0A B2 4D 68 93 0F E7 5A B4 21 8C D6 39 F2 47 1B 60 CE. C2 interactions begin by sending the following 12-byte handshake: 50 01 13 3F 08 5C 73 7B 1A 72 53 78 (decrypting to "%wGvo4GL62p*" using the XOR key above).
Process names are drawn from an encrypted table and set through argv rewriting (Table 2).
On a SpamSniper appliance, SMTP server-to-server relay traffic is the primary legitimate traffic type the appliance is designed to handle. A firewall in front of the appliance will commonly allow rules such as:
A magic packet withsrc=25, dst=25 would match the first rule and reach the raw socket before any stateful inspection. The implant authors understood exactly what traffic profile would be invisible on this specific class of host.
The command interface relies on the same cryptography (HMAC-SHA1, AES-CBC) and opcodes as the standard Tinyshell/Rekoobe.
By setting variables like VIMINIT="set viminfo=", HISTFILE=/dev/null, HISTSIZE=0, andHISTFILESIZE=0, the malware ensures that the attacker's commands are not logged to bash history nor to vim logs. The reverse shell spoofs "/sniper/autorun/rblsmtpd --start -n 9" and connects on the attacker's port 25. Rblsmtpd is a standard daemon used by mail servers (like qmail) to block mail from IPs listed in Real-time Blackhole Lists (RBLs).
A dropper likely built for ShareTech appliances
The dropper (update:2bedc26d4b29b435c21962beed7db21188a0219a0d28334bba8b4fb1656d7b15) is an x86-64 ELF with a minimal import table — fopen, fwrite, fputs, fclose, chmod, system, strlen, sleep, access, memcpy, exit — and no networking. It is a local installer, run after access is already established.
It carries four AES-128-ECB blobs keyed on the first sixteen bytes of SHA1("ShareTech"), or 6C CA D5 17 0E 3D B8 17 B3 DF 52 E0 D9 71 B1 48. The operators seeded their own key derivation with the target vendor's name.
Figure 6: AES key derivation seeding routine from SHA1("ShareTech")
Execution is gated on one precondition: the install branch fires only when /tmp/flag already exists on the filesystem and the .php script does not. When the gate passes, the dropper writes the script to the appliance's bulk-storage mount, chmods it 0777, hands it to system(), and exits. Because system() runs sh -c against a file carrying a real shebang, /HDD must be both writable and exec-capable. A noexec mount returns EACCES, for which the shell offers no interpreter fallback.
The script then copies two malicious binaries from /addpkg into /sbin as ntpdate and udevds, runs each, and unlinks them ten seconds later. Both keep running with no on-disk image: /proc/<pid>/exe resolves to (deleted), so there is nothing to hash, quarantine or submit, and a responder grepping /sbin finds nothing at all.
The elegant part is that /sbin/ntpdate is the dropper re-executing itself; the second instance finds the .php already present, fails the gate, and drops into a two-second watchdog that recreates execProcEnd and re-writes the script whenever either disappears. That also explains the absence of any persistence code: /addpkg/sbin/ is the appliance's own add-on package directory, so the firmware's package startup very likely relaunches it at boot.
AVERAT: A modular implant reaching into ORB
The dropper copies AVERAT into /sbin/udevds, marks it executable, launches it, sleeps ten seconds, and removes it.
Command and control
The implant connects outbound to port 25 and speaks SMTP: it issues EHLO, requests STARTTLS, and only then begins its own encrypted session. On a mail security gateway, outbound SMTP to arbitrary mail exchangers is the device's core function, so the traffic is indistinguishable from legitimate work in flow records.
The TLS layer is hand-built rather than linked from a standard cryptographic library. A fixed ClientHello template is compiled into the binary, including a 40-entry cipher suite list and a fixed extension ordering. Peer authentication is deferred entirely to the application layer via a shared-secret handshake carrying the magic value 1571 (0x0623).
Check-ins occur every 600 to 699 seconds. Each reports hostname, current user, OS version, network interfaces, and logged-in users. The interval is stored in a hidden file at /var/lib/.db and can be changed by the operator, persisting across restarts.
Figure 7: AVERAT beacon configuration details and persistent state file path structure
⠀
AVERAT takes its name from its only disk artifact: var, which reads as AVE when XOR-encoded (Figure 7).
Configuration
All operational values are held in a 276-byte encrypted blob. The key is derived from the blob's own first 16 bytes, folded with a further byte and a reverse XOR cascade; that key seeds RC4's key-scheduling algorithm, and the resulting S-box is used directly as a keystream. Each field starts at its own keystream offset, and the parity of that offset selects whether bytes are bitwise-inverted or nibble-rotated before the XOR.
Decrypted, the blob yields three 16-byte keys (transport, authentication, and a secondary handshake secret), the host table, the port table, a three-byte build tag, the timing state, and the .db path.
Figure 8: Key derivation and keystream offset mapping
⠀
The schema provides three host and port pairs; this build populates one.
Figure 9: Decrypted AVERAT host and port table configuration slots
⠀
Rapid7 developed an extractor for the AVERAT family. Figure 10 shows the results for the samples identified at the time of writing.
Figure 10: AVERAT extractor results and sample hashes identified at the time of writing
⠀
The MAC key and aux key are byte-identical in all six, while only one stream key is shared between a pair (Figure 10).
Command set
Command codes are uint16 values grouped into bands by subsystem. The most operationally significant are below.
Code
Capability
20
Enumerate directory contents
21
Download a file from the host, with resume support
22
Upload a file to the host in chunks, appending on resume
25
Recursively delete a file or directory tree
30
Recursively walk a directory tree, resolving file ownership
629
Enumerate running processes with command lines
632
Terminate a process (SIGTERM)
842
Overwrite the C2 host and port tables at runtime
912
Open an interactive shell session — up to ten concurrently
914
Write a command into an open shell session
916
Reboot the appliance, flushing buffers to disk beforehand
1010
Load or unload a shared-object module, extending the implant
1576
Set the callback interval and persist it to .db
1618
Open a proxy or port-forward channel through the appliance
unknown
Close the socket and terminate the process immediately
Table 4: AVERAT Command Codes and Capabilities
Infrastructure
The three IP addresses recovered from the configs represent compromised CPE belonging to third-party victims rather than intentional operator assets. Scan data shows all three sitting in Chunghwa Telecom's HiNet address space (AS3462), in three separate Taiwanese cities — Tainan, Banqiao and Taoyuan — each representing a distinct class of neglected, internet-facing consumer or SMB appliance.
59.125.211.65 is a Synology NAS belonging to a Taiwanese fuel-retail business, still serving a Laravel-based "cloud management system" on 81/82 behind a Let's Encrypt certificate that expired in October 2021, alongside an exposed MariaDB 5.5.62 instance that reached end of life in 2020. 122.116.138.33 is an embedded Taiwanese ADSL/FTTH SMB network appliance — gSOAP 2.8 on 8000 with a recording-management interface, HTTP Basic realms named SMB on 8081, 8082 and 10443, and a self-signed NetKlass Technology certificate valid from 2004 to 2014, MD5-signed with a 1024-bit key. 1.34.200.85 is a Dahua DH-XVR5116HS-I3 recorder. These are victim hosts repurposed as operational relays, selected on consistent criteria: reachable, unpatched, unmonitored, and unlikely to be audited.
The detail that binds them is PPTP on 1723, present on all three, returning a byte-identical banner (Firmware: 1, Hostname: local, Vendor: linux, fingerprint 261189147). A Dahua XVR ships no PPTP server. Synology's DSM offers one only as an optional package, disabled by default and deprecated in current releases. We assess this as operator-installed, which makes each node dual-purpose: an outbound relay terminating SMTP-disguised implant traffic, and an inbound routed VPN foothold into the host's own LAN. Combined with the RAT's own proxy commands, the campaign has relay capability at both ends of the connection.
The campaign is running two distinct C2 addressing strategies:
Strategy
Samples
Trade-off
Attacker-registered domain
bf8135f4, 2fe2dd40, a65048eb
Survives IP churn, re-pointable via DNS — leaves a seizable, sinkholable, monitorable name
Hardcoded consumer-broadband IP
4925bcca, a4379e11, 925c0418
No DNS artifact at all, brittle against address rotation
Table 5: C2 Addressing Strategies Comparison
The relay layer is composed of consumer and small-business broadband CPE: a fuel retailer's NAS, an obsolete NetKlass appliance, and a CCTV recorder, each sitting on a domestic-grade line.
AVERAT's command-and-control infrastructure matches the device-class profile that CISA, NCSC-UK, and partner agencies described in their April 2026 joint advisory (AA26-113A) as the standard building blocks of China-nexus covert/ORB networks: end-of-life NAS, edge appliances, and DVRs chosen because their vulnerabilities will never be patched. We found no infrastructure or indicator overlap with any specific named ORB network (LapDogs/UAT-7810, SPACEHOP, or FLORAHOX), whose documented targeting instead centers on SOHO routers; AVERAT's infrastructure is consistent with the broader ORB device-class pattern rather than confirmed membership in a known network.
Operator tradecraft
Three design decisions indicate operational maturity.
The dispatcher terminates the process on any unrecognized command code. This is inexpensive to implement and raises the cost of interactive probing or automated scanning against a live implant.
Support for ten concurrent shell sessions is consistent with provisioning for parallel operator access rather than a single interactive session..
The reboot handler calls sync() before forcing a restart through the kernel rather than through init. Flushing filesystem buffers before destroying volatile state is the behavior of an operator who knows precisely which artifacts persist across a restart and which do not — and in this chain everything happens in memory while the persistence needed to re-establish access is on disk.
Detectionguidance
File-based detection on the appliance is unlikely to succeed, because no payload persists in /sbin. We recommend prioritizing the following.
On the host, hunt for processes whose executable has been unlinked, which on Linux presents as a (deleted) suffix on the /proc/<pid>/exe target. To catch fileless and unlinked process execution, monitor process descriptors for instances where /proc/<pid>/exe points to an unlinked path, and inspect memory maps for executable pages lacking backing file paths on disk.
Additionally, alert on the presence of .db state files and dropper artifacts: the directory /HDD/ms6x2xTo64/, a shell script carrying a .php extension whose first bytes are #!/bin/sh, and a marker file execProcEnd containing the literal string end. A process-tree sequence of sh -c on a .php path, followed by cp and chmod into /sbin and an rm -rf of the same path within roughly ten seconds, provides high-fidelity detection of the staging sequence.
On the network, outbound SMTP from an appliance to mail-role hostnames that resolve to consumer-grade or embedded devices warrants investigation on its own.
Mitigation
Investigate unexpected raw packet sockets and classic BPF filters on Linux systems that do not require packet capture. Review outbound TCP port-25 callbacks from processes that are not mail services, particularly when the process renames itself to a common daemon or creates hidden PID and socket markers. Preserve short-lived staged binaries and collect process arguments, open file descriptors, socket metadata, and historical DNS records. Restrict management access to routers, DVRs, and other edge appliances, and monitor NFS or SMB mounts that could let an adjacent host write executables onto an embedded device.
YARA rules and more IoCs are available in Rapid7’s Intelligence Hub along with ongoing intelligence on the latest campaigns.
What defenders should take away from these campaigns
The components form a modular access ecosystem. The dropper executes AVERAT, which beacons to changeable infrastructure, while BPFDoor and Rekoobe samples wait for a magic packet before opening interactive access.
Across both campaigns, the network edge is a consistent focus. Each targets mail-security appliances that sit inline in front of the mail server, giving an implant positioned there visibility into an organization’s inbound and outbound traffic. Both also use port 25 to blend into expected SMTP activity, although the mechanism differs between the campaigns. In either case, command-and-control traffic can hide within a protocol that is normal for the device and may therefore attract less scrutiny.
This fits the broader BPFDoor pattern, where compromised IoT and SMB devices, including NAS units and DVRs, can act as operational relays that obscure the true source of magic-packet traffic before it reaches the passive backdoor. Newer samples also show how the malware continues to adapt to the environments it targets, including a second userland-level magic-packet check layered on top of the kernel BPF gate.
Rapid7 Variant G provides another example of that adaptation. It uses three BPF filters to preserve operational resilience on high-traffic edge nodes, with the filters left unoptimized because the libpcap version running on its end-of-life targets does not support filter optimization.
For defenders, the most useful detection opportunities remain raw packet sockets, BPF filters, port-25 callbacks from unexpected processes, process masquerading, and appliance-specific staging paths. Specific attribution should remain an ongoing assessment as new samples and infrastructure emerge.
A new Linux toolkit, identified by Rapid7 Labs, has been targeting organizations across South Korea’s automotive and media industries with minimal detection. The campaign made use of a HAProxy instance named “ted backdoor”, alongside trojanized versions of crond, agetty, atd, sshd, and polkitd. This previously undocumented framework enabled threat actors to execute remote commands on compromised servers, inject malicious scripts into web traffic, perform credential harvesting, and engage in long-term surveillance.
The standout feature of this toolkit is its depth of integration with the target environment. The ted backdoor is compiled as part of the victim’s existing HAProxy version 2.8.12. It uses its native filter API, internal memory pools, event scheduler, and process management infrastructure to intercept traffic and hide from monitoring, while genuine load balancing traffic operates as expected.
Operating alongside this are an SSH keylogger, a curl-based RAT, and a stager. The RAT maintains a watchdog thread dedicated to tracking HAProxy’s health, and reporting it back to the operator’s infrastructure. The earliest uploads on VirusTotal date back to mid-2025 and the involved HAProxy 2.8.12-0fdb194was released on 22 November 2024, establishing this as the earliest possible compilation date for this build.
The toolkit is attributed with medium confidence to DPRK APTs, given that the attacks Rapid7 observed were targeting South Korean media and automotive sectors, likely aiming at long-term espionage, the usage of simple xor-based encryption, custom substitution cipher, and the list of C2s hardcoded is associated to APT37 by ThreatFox and maltrail. Analysis shows that the ted backdoor could be part of a broader framework covering nginx backdoor as well. The ted plugin registers a custom HAProxy filter that hooks the HTTP parser to inspect and log high-value traffic, steal session cookies, and perform a client IP selection to decide whether to inject custom scripts in the webpage being rendered.
Technical analysis
Rapid7 researchers revealed that the toolkit was used in campaigns targeting South Korean automotive and media sectors likely dating back to early 2025. The number of trojanized binaries and functionalities found suggest the scope could be long-term cyber espionage and surveillance. However, gathered evidence does not suffice to establish a timeline nor how the initial access was performed.
At the time of analysis, both victims were running an edge webserver with ports 80, 443, and 25 exposed. Port 443 hosted the Groupware login portal and port 25 exposed a mail server. Either surface represents a plausible initial access vector consistent with documented Kimsuky tradecraft. Since the beginning of 2026 Kimsuky has been observed exploiting RCE vulnerabilities in externally accessible mail servers to compromise South Korean groupware vendors, while Groupware web portals represent the kind of exposed authenticated application that DPRK-nexus actors have repeatedly targeted for credential harvesting and exploitation. The specific entry point and any associated CVE remain unconfirmed pending further forensic evidence.
The scenario shown in Figure 1 assumes the initial access is obtained by exploitation of CVEs related to the Groupware portal.
Figure 1: Attack chain partially reconstructed
⠀
The threat actor begins by exploiting a vulnerability in the Groupware login portal running on the edge webserver, gaining an initial foothold in the DMZ. From there, they establish persistence and harvest credentials from the compromised edge host (e.g. SSH keylogger), which also doubles as a staging server hosting the trojanized system ELFs.
With a foothold on the edge, the attacker pivots inward and drops the stager onto internal servers. The stager checks for the presence of either crond or HAProxy, and only then deploys CurlRAT retrieving it either from its data section or the edge webserver.
In parallel, ted backdoor is dropped onto the HAProxy load balancer. Once active,it establishes its own C2 channel to the external operator infrastructure, enabling data exfiltration, command execution, and script injection. On the victim side, the compromised load balancer silently redirects or serves malicious content to selected clients browsing through it, completing the watering-hole loop.
SSH keylogger
4bb923eb040aa13ca8fd409c31ee4729c60ddff32e350efe1c5a4a9168a065f5 intercepts legitimate users' plaintext passwords and saves them to an encrypted log file under /var/lib/sshd/c8c68e629bba773a10ac80012d10bf19.
Figure 2: hardcoded master passwords in userauth_passwd()
⠀
After checking that entered credentials are not equal to TA’s master passwords, userauth_passwd() proceeds to encrypt them using a custom substitution cipher recurring throughout the toolkit and base64 encoding.
Figure 3: Substitution cipher used to encrypt credentials
⠀
Pivoting from the above cipher, instances of polkitd, crond, agetty and atd binaries were identified using a similar encryption algorithm. Crond binaries were found to be delivered by a stager.
CurlRAT Stager
The stager 5db1b6d52faf60b4f32d6fd0c7c938e4d05d29a14c32ded4a9668357c08b6a91 starts by decrypting its configuration strings using a 1-byte XOR, then verifies root privileges and profiles the OS checking system hostname, OS distribution and version IDs, kernel release and version numbers and CPU architecture to select the correct payload to drop. It decrypts the trojanized crond binary in memory, overwrites the system's legitimate daemon, and restarts the service. As shown below, only if HAProxy or cron are running on the system will it proceed to drop the backdoored crond.
Figure 4: Stager configuration
⠀
Checking for HAProxy presence is done as the binary, named by TA as ted backdoor. It also has RAT capabilities and plays a major role in the campaigns described. The embedded crond versions supported are CentOS 7.7, 7.8, 7.9 and Ubuntu 22.04 and after installing the backdoor, timestomping ensures the crond binary gets the same creation timestamp of /usr/bin/ssh. The stager ends by filtering out keywords such as tmp, wget cron and crond from Linux system logs using a staging file named /tmp/jasper-log, likely to blend in as the JSP (JavaServer Pages) engine in old Apache Tomcat versions, erasing any traces of the installation. The logs affected by the selective erasure are /root/.bash_history and the following under /var/log: messages, audit/audit.log, cmd.log, secure, syslog, auth.log.
09739441ed4599bac2f8159028f772f71e4b25c8badfff95574e56d7384f3dbe and fea1bc36632c71e5a839803469ef60ac47595d36b2c50934ac109ade6df06e61 are a different variant of the stager that fetches backdoored binaries from a compromised victim’s server without embedding any payloads.
CurlRAT
The Ubuntu version is analyzed below, though CentOS samples follow the same logic except for the filepath used to hide config/staging files.
As for the stager, feeea9d0bf6ae7396d28271baa51ae50df5169ce5d32a516865856f91abc50b3 starts by decrypting configuration strings using a 1-byte XOR key (0x58).
Figure 5: curlRAT configuration
⠀
The main logic added to crond is executed via two threads. The first thread runs the start_routine function that creates the staging directory snapd under /var/lib, where it attempts to load the victim ID from /var/lib/snapd/g580. If network failures were previously recorded, it reaches out to a secondary domain – img.darklights.store – authenticating with api_token/ecd427ea8330a4ff73618483e00b9b41 and setting the User-token header to the victim ID to fetch updated configuration under /tmp/nimon.unix-docbase.8564479396043450766-db6fb4443bc, where it’s then copied into /var/lib/snapd/g105.
To decrypt the configuration, the first byte of the file initializes the seed of a feedback xor based cipher. Each poll cycle, a config file is fetched from the C2 server over HTTPS (falling back to HTTP on failure) using libcurl, with the victim token embedded in the User-token header. The fetched config is parsed for three single-character delimiters — ! terminates the credential field, # marks the payload section, and * separates arguments — after which the credential field is compared against the local victim token.
If authentication succeeds, a single-character mode byte (ASCII '0' through '5') preceding the delimiter “#” selects one of six handler routines via a jump table. Payloads embedded in the config are decoded through a two-stage pipeline: standard Base64 decoding followed by a rolling cumulative XOR cipher keyed from the decoded header. The C2 task handler sleeps for 43,200 seconds (12 hours) between polls by default, but the operator can activate a fast-poll mode by setting a flag, reducing the interval to 30 seconds. A retry loop calls the handler up to six times per cycle with five-second intervals, failing fast if the first attempt does not succeed. The table below shows the C2 commands accepted.
Mode
Function
Description
0
cmd execution
Base64 + XOR-decodes a command list from the config, executes each line via popen with stderr redirected to stdout, saves output into a 1 MB buffer, and sends the result back.
1
config write
Decodes and writes a new config payload to disk, validates it, and sets the polling interval and fast-poll flag. If the validation fails, the C2 resets to img.monderhouse.space
2
staged payload drop
Issues an authenticated HTTP POST to the C2 host with a task path as the body, streams the response to a temporary file, decompresses and moves it to the final drop path, unlinking the temp.
3
reverse shell
Closes all file descriptors above 2, calls setuid(0) and setreuid(0, 0), forcing both its real and effective user IDs to root, and connects out before handing off to the shell dispatcher.
4
beacon
Populates a 10 KB system-info structure and transmits it as a check-in beacon.
5
PTY shell
A full interactive PTY shell, the payload consists of an ip:port.
Modes 0–2 and 4 use libcurl-based HTTP/HTTPS, hence the name curlRAT. All modes use Base64+XOR encoding/decoding applied to the payload. The victim ID is obtained by concatenating "cron_3.0pl1-137ubuntu3", system hostname, ipv4 address, and the hardware/OS UUID (read from /sys/class/dmi/id/product_uuid), then applying MD5 hash and converting it to uppercase.
The layer of encryption used for all C2 interactions consists of a feedback xor cipher using an initial random seed (modulo 240 + 10, 0<=seed<=249) and then applying Base64 encoding. The malware encapsulates the encrypted and encoded payload, the service name, and the telemetry type into a formatted application/x-www-form-urlencoded HTTP POST body (name=%s&value=%s&type=%d) which is sent to the C2 and authenticated using an hardcoded API token, including the victim ID in the User-token header.
The second thread acts as the HAProxy watchdog. Before entering the monitoring loop, it checks for the presence of the file /usr/lib/libvirtlog.so.0 to ensure the target is running in a virtualized environment, otherwise it sleeps 6 minutes and aborts. Then it accesses the MD5 victim ID under /var/lib/snapd/g580 to check if the node is active and compromised. Every hour the watchdog reads the pid at /var/run/haproxy.pid and monitors the status of HAProxy by polling /proc/pid. The status can be one of the following codes:
0 (Started): Process transitioned from stopped to running
1 (Stopped): Process is no longer active in the kernel process table
2 (Restarted): PID file timestamp modified, and a new PID is detected
3 (Reloaded): PID file timestamp modified, but the PID remained identical
The status is then sent to the C2 endpoint “writeservice_info” using the custom crypto layer and the telemetry type set to 0 (Figure 6).
Figure 6: writeinfo_service monitoring HAProxy status
⠀
The CentOS versions of curlRAT contain the same functionalities, except that functions are masqueraded as atd_ routines to blend in during static analysis.
Figure 7: The two threads running curlRAT logic
⠀
Below is the table summarizing the main RAT components.
The atd_get_info() is a recon routine likely used to decide which binary trojanized next to ensure persistence on the node. It collects the service name of the compromised machine and sends it to the C2 via the atd_response routine together with Ipv4 address, OS version, and the list of services and listening port (Figure 9).
Figure 9: Recon module output sent to the C2
⠀
MODE, DELAY and SERVER_URL are parsed from the config file discussed previously. During the campaign observed by Rapid7, the RAT acts as a framework and constitutes the codebase to edit legitimate system daemons. Other trojanized instances found are agetty and polkitd, where we identified a similar pattern lacking the HAProxy monitor: the creation of a thread to run curlRAT, reaching to img.worksongo.store and img.socialteams.store respectively.
atd_encrypt_url and atd_decrypt_url leverages the substitution cipher “E1x0X3f2R5w4g7u6D968kAeCdBPEpDhGJF4IiHHKzJvMtLlOnNcQmPNSjR2UFTUWOVTYIXZZ5aWcQbbeqd7gYf3i8hykGjCmsl9oonrqSp0sVrauKtLwAvBy1xMz=.#,+/--__" shared with the ssh keylogger.
Ted backdoor
The TA recompiled the HAProxy build 2.8.12 72e70936f0dbe459142a1d867617c35f8d0cce5d18c6a49e1090a2a5adc8e558 (18MB) to include a custom plugin (named ted_plugin) leaving debug strings naming the backdoor.
Figure 10: ted_plugin compiled as part of the source code
⠀
Figure 10 shows that the plugin was directly compiled with the rest of HAProxy source code and hooks directly the built-in HTTP parser relying on internal HAProxy structure for searching HTTP request headers.The custom filter defined to capture traffic is loaded via the ted_load_filter_config routine.
Figure 11: my_filter_config struct
⠀
The routine reads the implant's operational configuration from ~/cache/haproxy-1000.cache. Each field is decrypted in two layers: first ngx_decode applies a chained XOR seeded by the file's first byte; then ngx_decrypt_script applies a monoalphabetic substitution whose 67-entry mapping table is built at startup in ted_init_util from “E1x0X3f2R5w4g7u6D968kAeCdBPEpDhGJF4IiHHKzJvMtLlOnNcQmPNSjR2UFTUWOVTYIXZZ5aWcQbbeqd7gYf3i8hykGjCmsl9oonrqSp0sVrauKtLwAvBy1xMz=.#,+/--__" , and held in the ted_dec_dict uthash table keyed by Jenkins hash for O(1) lookup. The config carries the operating mode, all targeting regexes, every script rule with its payload paths and filenames, and the allowed operator keys. IP-based access control lists are loaded from haproxy-1001.cache and haproxy-1002.cache via the same decryption scheme. In other ted backdoor samples, the my_filter_config struct includes regexes to capture cookies as well.
After loading its configuration, it sets up signal handling via ted_register_reload_signal_handler() and saves its C2 pipe under HAPROXY_MWORKER_PP_READ and HAPROXY_MWORKER_PP_WRITE environmental variables to survive reloads and restarts, saving child process activity via ted_extra_log().
Below is the list of functions defined by the ted_plugin:
trace_chn_start_analyze() is hooked via ted_chn_analyze_for_htx_constprop_0() that parses the HTX buffer — the memory region where HAProxy stores parsed, SSL-decrypted HTTP request. If an incoming request matches the endpoint "/favorite_list_2x_m500_ico.jpg" (Figure 13), the malware drops into a Command & Control mode, setting the field flag to 1 in the ted_rep_state structure that tracks the response state.
⠀
Figure 13: Dropping into C2 mode
⠀
First, it reaches into HAProxy's internal counters to decrement active connection stats, referencing fields from the proxy struct via hardcoded 2.8.12 offsets to clear any trace left: the per-backend beconn/feconn and the global actconn, then 64-bit fields within be_counters (cum_conn, cum_req, bytes_in, bytes_out) guarded against underflow, and 32-bit peak metrics (sps_max, conn_max, cps_max) decremented only when exactly 1. Secondly, it parses a custom hardcoded 14-byte header to obtain the payload length, then creates FIFO pipes via ted_make_pipe_name and ted_create_multi_pipe_file keyed on HAProxy's connection ID under /tmp (e.g. /tmp/t[ID]_w.pipe). If HAProxy is running in master-worker mode (MODE_MWORKER, bit 0x80), the connection ID is written to the pp_w2m pipe so the master process runs the dispatcher; otherwise a detached thread runs ted_pipe_worker_thread locally (Figure 13).
The HTX walk filters on block type 4, which is HTX_BLK_DATA, and writes each block straight into fdPipe with write(). Any short write aborts and closes the pipe. Afterwards to_forward, output, buf.head and buf.data on the request channel are all zeroed. That tells HAProxy there is nothing left to forward, so the attacker's command body never reaches a backend server. The C2 request terminates at the load balancer, and no backend ever logs it.
The C2 dispatcher logic is resumed in the table below.
Command
Description
Opcode '0' (0x30)
Beacon: returns a version banner including build ID (24112201), HAProxy version (2.8.12-0fdb194), master-worker mode status, and chroot path.
Opcode '1' (0x31)
File upload: resolves path via ted_build_correct_path, writes file content via fopen(path, "wb"), and replies 1. Used to upload payload files for the injection path.
Opcode '2' (0x32)
File download: reads a path, stats it, writes the 8-byte size, and streams the contents back with EAGAIN handling.
Opcode '3' (0x33)
Command execution: executes commands via popen; merges stdout/stderr, appends " 2>&1", and streams output back XOR-encrypted.
Opcode '9' (0x39)
Config update: writes new config to ~/cache/haproxy-1000.cache.bak, re-encrypts using chained XOR, validates via ted_load_filter_config, and renames over the active config file if successful.
All five handlers write the same “HTTP/1.0 200 OK” header with Content-Type: text/html into the read pipe before the body. That's what the response task then relays out via send() on the raw socket, which is why the traffic looks like an ordinary HTTP response on the wire despite never passing through HAProxy's response path. Output back to the operator uses a rolling XOR cipher where each plaintext block is the key used to encrypt the next block with a random 1-byte seed.
If the initial endpoint check does not match "/favorite_list_2x_m500_ico.jpg" and the filter is in capture mode, then traffic is selectively logged and victims are identified based on the capturelist_set field within the my_filter_config struct (Figure 11), containing the list of targeted IPs and subnets. It uses regular expressions to filter the incoming HTTP traffic, waiting for high-value requests (like a user hitting a /login endpoint or an admin panel).
When a victim's request matches the attacker's filters, the backdoor goes to work.
It extracts the victim's source IP, the requested Host, the Referer, and the User-Agent formatting the data in a single-line record using exclamation marks as separators.
Figure 14: Real-time capturing of selected HTTP headers matching specific regexes
⠀
The execution flow continues based on conf->action; zero means passive logging only, non-zero starts the injection path. A request then has to clear four conditions. It needs a User-Agent, and if agent_pattern is configured that regex has to match. Second, the code scans the User-Agent for the bytes x,6,4, it selects between the two payload paths the matched rule retrieving them ted_script_config struct (path_32 at offset 0x18 and path_64 at 0x20). Third, the script rule list is walked until one ted_script_config entry's URL and referer regexes both match, with a null referer counting as an automatic pass. Thus the operator catches a victim arriving at a specific page from a specific referrer, rather than spraying at everyone hitting a URL.
⠀
Figure 15: Custom ted structure defined to inject malicious code in the page, and store regex rules and the connection context
⠀
Fourth, the implant parses Accept-Language splitting on ; and =, pulling four operator-controlled fields: mrt for the 64-byte uid credential, msc for an 8-byte status, mst for an 8-byte score, and a fourth keyword read from off_355407 for a 1024-byte infoblob. Parsing is order-independent and any subset can appear. If mrt yields a key, it must exist in allow_id_set, and that credential overrides IP filtering entirely, letting the operator reach the requested page from anywhere. It also upgrades the log record to the *-prefixed format carrying uid, status,score, and info. With no key, the fallback is IP-based:action == 1requires whitelist membership, action == 2 requires blacklist absence, both checked twice, once with the final octet zeroed for /24 subnet matching and once for the exact host.
Once all checks are cleared the chosen file is opened, stored in the per-connection ted_rep_state as fpAppend and nTotal, alongside a script_conf back-reference to the matched rule. The replace byte at offset 0x00 of that rule sets flag to 4 when zero and 2 when non-zero, distinguishing appending content from substituting it. Finally the code sets its filter flag and increments nb_rsp_data_filters or nb_req_data_filters on the stream, which is HAProxy's documented opt-in for body access– this time reusing the internal structure of the load balancer to inject code into the page at delivery time.
Figure 16: Hooking the HTTP response
⠀
Once a victim is marked for injection, two callbacks finish the job on the way out. ted_http_headers_for_htx runs first, and only when the data is on the response side, a state block is initialized during the request, and the transaction flag is set. It rechecks the response against the rule that matched earlier, testing Content-Type and the status line, so a payload is delivered only when the reply is a document worth modifying. It then reshapes the response to fit the incoming file: sets Content-Type, adds a Content-Disposition filename if the rule has one, writes the new body length into the custom length header, deletes Accept-Ranges so the client cannot request byte ranges and spot the size mismatch, and forces the status to 200OK if it was anything else.
ted_http_payload performs the swap. For each body chunk, it takes only as much as the payload file has left, reads that slice from disk, decrypts it with ngx_decrypt_script, and substitutes it through HAProxy's own body-editing calls. When the replacement changes the body length, the code shifts every remaining filter's offset by the difference, so nothing downstream sees an inconsistency. With the rewritten length header and range support stripped, the size change leaves no trace.
trace_http_end handles the leftover bytes. The previous callback can only overwrite bytes that already exist in the response, so when the payload is larger than the original body there is a remainder with nowhere to go. This function runs at the end of the response and appends it. It checks that the state block is in an injection mode, that the headers were already rewritten, and that fewer bytes have been delivered than the payload holds. If so, it measures the free space left in the response buffer, reads exactly that much from the payload file, decrypts it with ngx_decrypt_script, and appends it as a new data block, bumping the channel's output count to match.
The result is that a payload of any size can be delivered across as many passes as it takes, using HAProxy's own scheduler to drive the process.
To ensure persistence, curlRAT is integrated and hidden as libc routines.
Figure 17: ted backdoor including curlRAT configuration a8bfab4de81a1acb04aacdf757346946b0f5e30f0c9f402004016d0e425119c7
⠀
Attacker infrastructure
The observed infrastructure follows a consistent pattern: Domains are registered under low-cost commodity TLDs —.store, .space, .site, .autos — and use subdomain schemes mimicking image-serving CDN endpoints (img.) They then blend payload delivery traffic into normal web browsing. The naming convention across suggests a shared registration workflow rather than ad-hoc infrastructure. Theimg.responsive.pstatic.autos mimics Naver'spstatic.net static content domain, a South Korean web platform, which combined with the watering-hole delivery model adopted by the ted backdoor is consistent with targeting of Korean-speaking users.
Attribution
At the time of the analysis, compromised servers had exposed the Groupware login portal on port 443, which is heavily present in Korean enterprise environments. The targeting of regional software (Groupware), mimicking Naver's static content domain, usage of simple xor and substitution ciphers and the watering-hole model already documented in the Operation Code on Toast (APT37)and Operation Synchole (Lazarus),allows medium confidence attribution to DPRK APT. The list of C2s hardcoded is associated with APT37 by ThreatFox and maltrail.
The campaign's timeline and delivery mechanism overlap with Operation SyncHole, a concurrent Lazarus campaign documented by Kaspersky running from November 2024 through February 2025, in which Lazarus compromised South Korean media sites to redirect visitors to pages serving malicious JavaScript payloads. APT37 and Lazarus Group are distinct North Korean state-sponsored threat clusters assessed by Mandiant to operate under different DPRK agencies — APT37 under the Ministry of State Security, Lazarus under the Reconnaissance General Bureau — though both conduct cyber espionage targeting South Korean entities. Lazarus has been observed to deploy backdoored open-source programs to deliver malware and use feedback XOR + base64 to interact with the C2 by Kaspersky. As of July 2026, similar suspected initial access has been reported by ENKI WhiteHat, suggesting that if a vulnerability in South Korean mail appliances exists, the exploitation could still be ongoing and leveraged by DPRK APTs.
Further evidence is necessary to make a more definitive assessment. Moreover, the presence ofngx_* prefixed routines within the ted backdoorsuggest code reused from an nginx backdoor. The ngx_* prefixed routines were observed during the latest Funnull campaign, where (similar to our case) a custom nginx filter was registered to hook HTTP traffic, and simple XOR encryption was applied to the configuration file. However, other than a similar naming convention, no significant code-level overlaps exist to support a stronger linkage.
Conclusion
ted backdoor and curlRAT were designed to persist during long-term espionage operations with the ability to steal cookie sessions, credentials, redirect selected users, conduct drive-by download attacks, and hide evidence of the tampered page to a specific range of IPs to evade detection. Defenders should treat any edge component managing user traffic, SSL, or runtime modules with the same strict security standards as their main application servers. Relying on the component's own logs is not enough; securing these systems requires independent network correlation, memory behavioral analysis, and binary integrity checks.
MITRE ATT&CK techniques
Tactic
Technique
Detail
Component
Initial access
[T1190] Exploit public-facing application
HAProxy filter API abused as injection point; watering-hole payload delivery via compromised load balancer
ted backdoor
Execution
[T1059.004] Unix shell
popen() used for one-shot command execution per opcode '3'; PTY shell spawned per opcode '5'; reverse shell per opcode '3' in CurlRAT
ted backdoor, CurlRAT
Execution
[T1106] Native API
pthread_create / pthread_detach for detached shell threads; HAProxy pool_alloc / task_wakeup for async response scheduling
ted backdoor
Persistence
[T1574.006] Hijack execution flow: dynamic linker
Implant loaded as HAProxy shared library filter at process start; persistent across HAProxy restarts
ted backdoor
Persistence
[T1543] Create or modify system process
Legitimate crond binary overwritten in-place; service restarted; timestomping to match /usr/bin/ssh creation time
Stager, CurlRAT
Privilege escalation
[T1548] Abuse elevation control mechanism
setuid(0) / setreuid(0,0) called before reverse shell daemonisation; stager verifies root before payload drop
Stager, CurlRAT
Defence evasion
[T1036.005] Masquerade: match legitimate name
crond, polkitd, agetty, atd binary names used; CentOS variant masquerades functions as atd_ routines in static analysis
Stager, CurlRAT
Defence evasion
[T1070.002] Clear Linux logs
Selective keyword erasure (tmp, wget, cron, crond) from bash_history, messages, audit.log, secure, syslog, auth.log via /tmp/jasper-log staging file
Stager
Defence evasion
[T1070.006] Timestomp
Backdoored crond given same creation timestamp as /usr/bin/ssh post-install
Response body replaced or appended with decrypted payload script via HAProxy data filter callbacks; Content-Type, Content-Length, Content-Disposition rewritten; 200 OK forced; Accept-Ranges stripped
ted backdoor
Collection
[T1119] Automated collection
Passive capture logs timestamped records per matched request; expanded * records written when Accept-Language mrt key present
ted backdoor
C2
[T1071.001] Application layer protocol: web protocols
ted C2 tunnelled as HTTP through load balancer; CurlRAT polls C2 over HTTPS with libcurl fallback to HTTP; all payloads as application/x-www-form-urlencoded POST
CurlRAT, ted backdoor
C2
[T1132.001] Data encoding: standard encoding
All CurlRAT C2 payloads Base64-encoded after feedback XOR; ted pipe protocol uses raw bytes with rolling XOR session key
CurlRAT, ted backdoor
C2
[T1102] Web service
CurlRAT falls back to secondary C2 img.monderhouse.space on config validation failure; img.darklights.store used as backup config host
CurlRAT
C2
[T1572] Protocol tunnelling
Interactive shell tunnelled through HAProxy HTTP pipeline via named FIFOs; response exfiltrated via raw send() on TCP socket bypassing HAProxy logging
ted backdoor
C2
[T1568] Dynamic resolution
CurlRAT victim ID derived from hostname + IP + hardware UUID + cron version string, MD5'd and uppercased; used as User-token header in all C2 requests
CurlRAT
Exfiltration
[T1041] Exfiltration over C2 channel
SSH credentials exfiltrated via CurlRAT C2; session capture logs written by ted; CurlRAT mode 0 streams command output back over same channel
Stager, CurlRAT, ted backdoor, SSH keylogger
Exfiltration
[T1560] Archive collected data
SSH keylogger output encrypted with substitution cipher before writing; CurlRAT applies feedback XOR + Base64 to all outbound data