Rapid7 Labs has disclosed a previously undocumented DPRK-aligned Linux intrusion framework used against South Korean media and automotive organizations. The reporting describes a HAProxy instance carrying a component named the 'ted unauthorized access mechanism', plus trojanized versions of core daemons: crond, agetty, atd, sshd and polkitd. The campaign supported remote command execution, web-traffic script injection, credential harvesting and long-term surveillance with minimal detection.
The defensive urgency is not a single patchable bug. No CVE identifier is provided in the source summary, so teams should not wait for a CVE-centric playbook. The risk is trusted Linux control-plane binaries and edge proxy services being converted into resident surveillance and command-execution infrastructure. If you operate internet-facing HAProxy, Linux SSH bastions, build hosts, vendor-managed appliances or any South Korea-adjacent media/automotive supplier systems, assume credential theft and integrity failure are possible and run integrity hunts this week.
Why this matters to defenders
This campaign targets the places SOCs often trust most: reverse proxies, SSH, cron and authentication helpers. HAProxy sits in the plaintext path for TLS termination or header rewriting, sshd gates administrative access, cron and at provide scheduled execution, agetty touches console login flows, and polkitd can influence privileged action authorization. Trojanizing those components gives an adversary durable access that survives casual malware scanning because the malicious logic rides inside expected service names and normal ports.
The automotive and media victimology also matters. Automotive suppliers hold CAD, firmware signing material, dealer portals, OT-adjacent jump hosts and supplier credentials. Media organizations hold pre-publication content, source communications, ad-tech tags and high-traffic web properties where script injection can become watering-hole distribution. A loader inside HAProxy can selectively alter responses for particular users or paths, making client-side compromise a downstream effect even when the web application itself is clean.
Technical analysis
Affected products, versions and platforms from the source: Linux servers running HAProxy version 2.8.12 with the ted component compiled into the victim's existing HAProxy build, using HAProxy's native filter API and internal memory pools. The summary also identifies trojanized instances of crond, agetty, atd, sshd and polkitd. Treat exact file names and paths as environment-dependent until validated against Rapid7 indicators and your own forensic images.
Attack chain, defensive view: initial access details are not included in the summary, but the post-access pattern is clear. The actor establishes or co-opts an internet-reachable service path, integrates with HAProxy rather than dropping a noisy standalone implant, then preserves access through modified service binaries. Remote command execution likely rides through authenticated or covert channels that blend with proxy, SSH or scheduled-task telemetry. Web script injection occurs at the proxy layer, before application logging sees a changed origin response. Credential harvesting can occur through sshd or login-adjacent components, and surveillance persists because cron/at/systemd units and polkit authorization paths can be shaped to re-launch or re-permit the implant.
Exploitation status: the source reports confirmed in-the-wild activity against named sectors. It does not provide a public PoC, a CVE, a CISA KEV entry or CVSS score. Do not fabricate one. Operationally, classify this as active nation-state tradecraft with high impact and moderate-to-high stealth. The absence of a KEV entry does not reduce urgency because integrity compromise of sshd or HAProxy is an incident-response event, not a patch-management ticket.
Key defensive hypothesis: if HAProxy is compiled with an unauthorized filter, package integrity will often fail, process lineage will look abnormal, memory maps may show unexpected objects, outbound connections may originate from proxy or service contexts, and web clients may receive scripts that never existed on the origin. The strongest signals are cross-layer: package metadata disagreement, unexpected child processes, service binary drift, anomalous proxy egress and credential access after SSH interactive sessions.
Detection and response
---
title: HAProxy Or Core Linux Daemon Spawning Shell Or Downloader
id: 8c6f0c7e-2a19-4b52-9c1d-0e2f5d7a91b4
status: experimental
description: Detects HAProxy, sshd, cron, at, agetty or polkit contexts launching shells, interpreters, curl, wget or tunneling tools consistent with the reported ted/curlRAT Linux tradecraft.
references:
- https://www.rapid7.com/blog/post/tr-dprk-apts-ted-backdoor-curlrat-target-south-korean-media-automotive-sectors
- https://attack.mitre.org/techniques/T1059/
- https://attack.mitre.org/techniques/T1105/
author: Security Arsenal
date: 2026/04/06
tags:
- attack.execution
- attack.command_and_control
- attack.t1059
- attack.t1105
logsource:
category: process_creation
product: linux
detection:
selection_parent:
ParentImage|endswith:
- '/haproxy'
- '/sshd'
- '/crond'
- '/cron'
- '/atd'
- '/agetty'
- '/polkitd'
selection_child:
Image|endswith:
- '/bash'
- '/sh'
- '/dash'
- '/zsh'
- '/curl'
- '/wget'
- '/python'
- '/python3'
- '/perl'
- '/nc'
- '/ncat'
- '/socat'
condition: selection_parent and selection_child
falsepositives:
- HAProxy health checks should not spawn interactive shells or downloaders
- cron jobs legitimately invoking curl must be allowlisted by exact command line, user and destination
level: high
---
title: Integrity Change To HAProxy Cron SSH polkit Or Login Service Binaries
id: 1f4b8a21-77d4-43a0-b6de-5aa12f0c93e7
status: experimental
description: Detects file changes to service binaries, systemd units, HAProxy filters/modules and cron/at artifacts associated with trojanized Linux daemons.
references:
- https://www.rapid7.com/blog/post/tr-dprk-apts-ted-backdoor-curlrat-target-south-korean-media-automotive-sectors
- https://attack.mitre.org/techniques/T1554/
- https://attack.mitre.org/techniques/T1543/
- https://attack.mitre.org/techniques/T1053/
author: Security Arsenal
date: 2026/04/06
tags:
- attack.persistence
- attack.defense_evasion
- attack.t1554
- attack.t1543
- attack.t1053
logsource:
category: file_change
product: linux
detection:
selection_paths:
TargetFilename|startswith:
- '/usr/sbin/haproxy'
- '/usr/local/sbin/haproxy'
- '/usr/lib/haproxy/'
- '/usr/libexec/haproxy/'
- '/usr/sbin/sshd'
- '/usr/sbin/crond'
- '/usr/sbin/cron'
- '/usr/sbin/atd'
- '/usr/sbin/agetty'
- '/sbin/agetty'
- '/usr/lib/polkit-1/polkitd'
- '/usr/libexec/polkitd'
- '/etc/systemd/system/'
- '/lib/systemd/system/'
- '/usr/lib/systemd/system/'
- '/etc/cron'
- '/var/spool/cron'
- '/var/spool/at'
condition: selection_paths
falsepositives:
- Signed package updates and configuration management; correlate with package logs and change windows
level: high
---
title: curlRAT-Like Insecure Curl From Service Context
id: 5d20c913-9ba1-4d3c-80bb-19f6a44e0c72
status: experimental
description: Detects curl or wget using TLS validation bypass or silent flags when launched by service accounts or remote-access daemons, a curlRAT-consistent egress pattern.
references:
- https://www.rapid7.com/blog/post/tr-dprk-apts-ted-backdoor-curlrat-target-south-korean-media-automotive-sectors
- https://attack.mitre.org/techniques/T1071/
- https://attack.mitre.org/techniques/T1573/
author: Security Arsenal
date: 2026/04/06
tags:
- attack.command_and_control
- attack.t1071.001
- attack.t1573
logsource:
category: process_creation
product: linux
detection:
selection_tool:
Image|endswith:
- '/curl'
- '/wget'
selection_flags:
CommandLine|contains:
- ' -k '
- '--insecure'
- '--silent'
- '-s '
- '--output /tmp'
- '-o /tmp'
- '-o /dev/shm'
- '--header'
selection_parent:
ParentImage|endswith:
- '/sshd'
- '/haproxy'
- '/crond'
- '/cron'
- '/atd'
- '/systemd'
condition: selection_tool and selection_flags and selection_parent
falsepositives:
- Monitoring agents and automation using curl; tune by service account, destination domain and package owner
level: medium
let core_daemons = dynamic(['haproxy','sshd','crond','cron','atd','agetty','polkitd','systemd']);
let tools = dynamic(['bash','sh','dash','zsh','curl','wget','python','python3','perl','nc','ncat','socat']);
DeviceProcessEvents
| where TimeGenerated > ago(14d)
| where InitiatingProcessFileName has_any (core_daemons) or FileName has_any (core_daemons)
| where FileName has_any (tools)
| extend SuspiciousFlag = tobool(ProcessCommandLine has_any ('--insecure',' -k ','/dev/shm','/tmp/','--header','base64'))
| summarize FirstSeen=min(TimeGenerated), LastSeen=max(TimeGenerated), Hosts=dcount(DeviceName), Commands=make_set(ProcessCommandLine, 20) by DeviceName, InitiatingProcessFileName, InitiatingProcessCommandLine, FileName, ProcessCommandLine, AccountName, SuspiciousFlag
| where SuspiciousFlag or InitiatingProcessFileName in~ ('haproxy','sshd','polkitd','agetty')
| join kind=leftouter (
DeviceNetworkEvents
| where TimeGenerated > ago(14d)
| where InitiatingProcessFileName has_any (dynamic(['haproxy','sshd','curl','wget','python','perl','socat']))
| summarize NetFirst=min(TimeGenerated), NetLast=max(TimeGenerated), RemoteIPs=make_set(RemoteIP, 25), RemoteUrls=make_set(RemoteUrl, 25), Ports=make_set(RemotePort, 25) by DeviceName, InitiatingProcessFileName, InitiatingProcessCommandLine
) on DeviceName, InitiatingProcessFileName
| project FirstSeen, LastSeen, DeviceName, AccountName, InitiatingProcessFileName, FileName, ProcessCommandLine, SuspiciousFlag, RemoteIPs, RemoteUrls, Ports
| order by FirstSeen asc;
-- Scope: Linux endpoints with Velociraptor. Hunt proxy/service process trees, modified service binaries and egress from service contexts.
LET procs = SELECT Pid, Ppid, Name, Exe, CommandLine, Username, CreateTime FROM pslist()
WHERE Name =~ 'haproxy|sshd|crond|cron|atd|agetty|polkitd|curl|wget|python|perl|socat'
OR CommandLine =~ '--insecure|/dev/shm|/tmp/|base64'
LET bins = SELECT FullPath, Size, Mtime, hash(path=FullPath).SHA256 AS SHA256 FROM glob(globs=['/usr/sbin/haproxy','/usr/local/sbin/haproxy','/usr/sbin/sshd','/usr/sbin/crond','/usr/sbin/cron','/usr/sbin/atd','/sbin/agetty','/usr/sbin/agetty','/usr/lib/polkit-1/polkitd','/usr/libexec/polkitd','/usr/lib/systemd/system/*.service','/etc/systemd/system/*.service'])
LET conns = SELECT Pid, Name, LocalAddr, LocalPort, RemoteAddr, RemotePort, Status, Family, Type FROM netstat()
WHERE Name =~ 'haproxy|sshd|curl|wget|python|perl|socat' AND RemotePort IN {443,80,53,22,8080,8443}
SELECT * FROM procs
UNION ALL SELECT NULL AS Pid, NULL AS Ppid, 'FILE:' + FullPath AS Name, FullPath AS Exe, 'sha256=' + SHA256 AS CommandLine, '' AS Username, Mtime AS CreateTime FROM bins
UNION ALL SELECT Pid, NULL AS Ppid, 'NET:' + Name AS Name, Name AS Exe, LocalAddr + ':' + format(format='%d', args=LocalPort) + ' -> ' + RemoteAddr + ':' + format(format='%d', args=RemotePort) AS CommandLine, '' AS Username, NULL AS CreateTime FROM conns
#!/usr/bin/env bash
# Ted/curlRAT integrity triage for Debian/Ubuntu and RHEL-family Linux. Run as root; read-only by default.
set -euo pipefail
OUT=/tmp/ted_haproxy_triage_$(date -u +%Y%m%dT%H%M%SZ); mkdir -p "$OUT"
# Capture volatile evidence first
ps auxww > "$OUT/ps.txt"
ss -tulpen > "$OUT/sockets.txt" 2>&1 || netstat -tulpen > "$OUT/sockets.txt" 2>&1 || true
lsof -nP -iTCP -sTCP:ESTABLISHED > "$OUT/established.txt" 2>&1 || true
for p in haproxy sshd crond cron atd agetty polkitd curl wget python python3 perl socat; do pgrep -a "$p" >> "$OUT/procs_$p.txt" 2>&1 || true; done
# Package integrity: Debian/Ubuntu and RHEL-family
if command -v dpkg >/dev/null 2>&1; then
dpkg -l haproxy cron cronie util-linux at openssh-server policykit-1 > "$OUT/dpkg_list.txt" 2>&1 || true
debsums -ac > "$OUT/debsums_changed.txt" 2>&1 || true
apt-cache policy haproxy openssh-server policykit-1 cron at util-linux > "$OUT/apt_policy.txt" 2>&1 || true
fi
if command -v rpm >/dev/null 2>&1; then
rpm -q haproxy cronie util-linux at openssh-server polkit > "$OUT/rpm_list.txt" 2>&1 || true
rpm -Va > "$OUT/rpm_verify.txt" 2>&1 || true
rpm -V haproxy cronie util-linux at openssh-server polkit > "$OUT/rpm_verify_targeted.txt" 2>&1 || true
fi
# Hash and metadata for reported trojanized component classes
for f in /usr/sbin/haproxy /usr/local/sbin/haproxy /usr/sbin/sshd /usr/sbin/crond /usr/sbin/cron /usr/sbin/atd /sbin/agetty /usr/sbin/agetty /usr/lib/polkit-1/polkitd /usr/libexec/polkitd; do
[ -e "$f" ] && { stat "$f"; sha256sum "$f"; readlink -f "$f"; } >> "$OUT/core_binary_hashes.txt" 2>&1 || true
done
find /usr/lib/haproxy /usr/libexec/haproxy /etc/haproxy /etc/systemd/system /usr/lib/systemd/system /lib/systemd/system /etc/cron.d /etc/crontab /var/spool/cron /var/spool/at -maxdepth 3 -type f -printf '%TY-%Tm-%TdT%TH:%TM:%TSZ %u %g %m %p\n' > "$OUT/persistence_files.txt" 2>&1 || true
grep -RniE 'ExecStart=|Environment=|LD_PRELOAD|LD_LIBRARY_PATH|haproxy|curl|wget|base64|/dev/shm' /etc/systemd/system /usr/lib/systemd/system /lib/systemd/system /etc/haproxy /etc/cron.d /etc/crontab 2>/dev/null > "$OUT/unit_config_grep.txt" || true
# HAProxy build/config sanity: compare running version, config and mapped objects
haproxy -vv > "$OUT/haproxy_vv.txt" 2>&1 || true
haproxy -c -f /etc/haproxy/haproxy.cfg > "$OUT/haproxy_cfg_check.txt" 2>&1 || true
for pid in $(pgrep haproxy 2>/dev/null || true); do cat /proc/$pid/maps > "$OUT/haproxy_maps_$pid.txt" 2>&1 || true; done
# High-signal anomalies for analyst review
grep -E 'S|5|missing|MD5|sha256' "$OUT/rpm_verify_targeted.txt" "$OUT/debsums_changed.txt" 2>/dev/null > "$OUT/integrity_fail_hits.txt" || true
grep -E 'haproxy|sshd|crond|cron|atd|agetty|polkitd' "$OUT/ps.txt" | grep -E 'curl|wget|bash|sh |python|perl|socat|nc ' > "$OUT/service_child_hits.txt" || true
grep -E 'haproxy|sshd|curl|wget|python|perl|socat' "$OUT/established.txt" > "$OUT/service_egress_hits.txt" 2>&1 || true
printf 'Evidence bundle: %s\nReview first: integrity_fail_hits.txt, service_child_hits.txt, service_egress_hits.txt, rpm_verify_targeted.txt/debsums_changed.txt\n' "$OUT"
# Containment examples, intentionally commented: confirm forensic capture before changing state.
# systemctl stop haproxy sshd cron atd polkit
# apt-get --reinstall install haproxy openssh-server cron at util-linux policykit-1
# dnf reinstall haproxy openssh-server cronie at util-linux polkit
Immediate actions
Treat confirmed binary drift on sshd, HAProxy, cron/at, agetty or polkitd as a probable credential-theft incident. Isolate the host at the switch or security-group layer, capture memory before shutdown where legal and resourced, rotate all credentials that touched the host including SSH keys, API tokens in environment files, CI secrets, cookie/signing keys and service accounts, then rebuild from known-good media rather than cleaning in place. If HAProxy terminated TLS, review downstream client injection risk and rotate session secrets.
Hunt laterally using the same parent-child logic on bastions, build runners, repository mirrors, update servers, Kubernetes ingress nodes and vendor-managed Linux appliances. Review southbound egress from proxies to rare ASNs, newly registered domains, direct-IP TLS and low-and-slow 443 traffic. Preserve HAProxy logs, syslog auth logs, auditd, systemd journals, package manager history, EDR telemetry and load-balancer access logs with client IP, URI, status, bytes and user agent.
Remediation and hardening
Because the source does not publish a CVE or fixed build, remediation is integrity-led. Reinstall signed packages for HAProxy, OpenSSH, cron/cronie, at, util-linux and polkit from trusted repositories, then verify with debsums or rpm -Va. Move HAProxy to a currently supported vendor or distribution build; if you must remain on the 2.8 line, use the latest maintained 2.8.x security release from your distro or haproxy.org and confirm provenance, signatures and build flags. Do not compile production HAProxy from unreviewed source on the same host that serves traffic.
Enforce egress denial by default for proxies and service accounts; allow only required update, OCSP/CRL, API and upstream destinations. Enable auditd rules for writes to service binaries, systemd units, cron spools and HAProxy module/filter directories; alert on chattr, setfacl, mount of /dev/shm with exec, and package manager invocations outside change windows. Require signed packages only, disable root SSH password login, use FIDO2-backed or short-lived certificate SSH, restrict polkit rules, remove compiler toolchains from production edge nodes, and pin systemd services with ProtectSystem, ProtectHome, NoNewPrivileges and read-only paths where compatible.
Reference the Rapid7 disclosure for indicators and update your detections as hashes, paths and infrastructure are published: https://www.rapid7.com/blog/post/tr-dprk-apts-ted-backdoor-curlrat-target-south-korean-media-automotive-sectors. Also track HAProxy security notes at https://www.haproxy.org/ and your distribution security tracker. Monitor CISA KEV at https://www.cisa.gov/known-exploited-vulnerabilities-catalog; the provided summary does not list a KEV CVE, so absence from KEV should not delay integrity verification.
Validation checklist
Confirm every internet-facing Linux proxy and SSH host passes package verification, has no unexpected loaded objects in HAProxy maps, has no service-context shell/downloader children, has no unauthorized systemd drop-ins, has reviewed cron/at spools, has egress policy hits alarmed, and has credential rotation completed for any host with unexplained drift. Re-run the triage bundle after rebuild to prove clean baseline and store hashes in your CMDB.
Related Resources
Security Arsenal Managed SOC Services AlertMonitor Platform Book a SOC Assessment soc-mdr Intel Hub
Is your security operations ready?
Get a free SOC assessment or see how AlertMonitor cuts through alert noise with automated triage.