# Sudo iptables NOPASSWD Misconfiguration Enables Local Privilege Escalation via Comment Injection

> Shielder researchers (suidpit, smaury) demonstrate two local privilege-escalation techniques on Linux systems that grant a low-privileged user sudo NOPASSWD rights to iptables/iptables-save: injecting newline characters into an iptables rule comment via bash $'...' quoting and using iptables-save -f to overwrite /etc/passwd with a forged root entry, plus a secondary --modprobe/execv abuse most relevant to embedded/POS devices. No CVE is assigned because the root cause is a sudoers policy choice, not a software defect.

- **Published:** 2026-09-13T00:00:00Z
- **Last reviewed:** 2026-09-13T00:00:00Z
- **Canonical:** https://intel.threadlinqs.com/threat/TL-2026-2478
- **ID:** TL-2026-2478
- **Severity:** MEDIUM
- **Category:** VULNERABILITY
- **Status:** ACTIVE
- **Detections:** 9 · **IOCs:** 7 (full data via the Threadlinqs MCP server — Purple tier)
- **CVEs:** CVE-2020-28044, CVE-2020-28045, CVE-2020-28046

## Description

On 20 September 2024, Shielder security researchers suidpit and smaury published "A Journey From sudo iptables To Local Privilege Escalation," documenting a practical root-compromise path on systems (demonstrated on Ubuntu 24.04 LTS) where a low-privileged user has been granted sudo NOPASSWD access to both /usr/bin/iptables and /usr/bin/iptables-save — a common convenience misconfiguration intended to let non-root users manage firewall rules. The attacker first confirms the grant with sudo -l and enumerates the live ruleset with iptables -L / iptables -S (the classic GTFOBins-style reconnaissance for sudo-delegated security software).

The primary technique abuses the iptables -m comment --comment option, which stores an arbitrary string associated with a rule. Using bash ANSI-C ($'...') quoting, an attacker can embed literal newline characters inside the comment value, e.g. sudo iptables -A INPUT -i lo -j ACCEPT -m comment --comment $'controlled\ninjected\nlines'. Because iptables-save faithfully reproduces stored comments verbatim when dumping the ruleset, and iptables-save -f <path> writes that dump as root to an attacker-chosen path, the injected newlines let an attacker craft output that resembles arbitrary file content rather than iptables rules — a file-write primitive independently catalogued by GTFOBins under the iptables-save entry ("the data is written alongside iptables rules... works with sudo privileges since acquired privileges aren't dropped"). By generating a password hash with openssl passwd, copying the existing root /etc/passwd entry and swapping in the new hash, embedding that crafted line via the comment-injection technique, and finally running sudo iptables-save -f /etc/passwd, the attacker overwrites /etc/passwd with a modified root entry that authenticates with an attacker-known password (su root), yielding full root access.

A secondary, less broadly practical technique abuses the iptables/ip6tables --modprobe=<command> flag. Netfilter's xtables_load_ko()/xtables_insmod() logic invokes the modprobe binary specified via --modprobe (via the execv syscall) to load a kernel module required by a referenced table/target/match when that module is not already loaded. On modern desktop/server Linux the relevant modules are almost always pre-loaded, making this path impractical, but it is highly relevant to embedded devices and appliances that ship with incomplete or blacklisted module sets. This exact technique was documented years earlier in a TurinCTF 2017 Finals challenge (JBZ CTF Team writeup): with iptables listed NOPASSWD in /etc/sudoers and the nat table module deliberately blacklisted in /etc/modprobe.d/iptables.conf, contestants ran `echo -e "#!/bin/sh\n/bin/sh" > /tmp/shell; chmod +x /tmp/shell; sudo iptables -L -t nat --modprobe=/tmp/shell` to obtain an arbitrary root shell. It was later used in the real world: CVE-2020-28046 (CVSS 3.1 7.8 HIGH — CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H, CWE-269) describes how, on PAX Technology ProLinOS-based Android payment terminals (D190, D200, D210, Q80, Q92, S80, S300, S800, S900, S920) running ProlinOS up to 2.4.161.8859R, a low-privileged MAINAPP user can run the setuid xtables-multi binary as `xtables-multi ip6tables -t nat -L --modprobe=/data/app/MAINAPP/bin/MablApp`; because the device lacks /proc/net/ip6_tables_names for IPv6, the modprobe path always triggers, executing the MAINAPP application binary as root. In the pax-pwn research (Giulio/lsd.cat, crediting cogitoergot00t and the JBZ crew; disclosed to PAX from June 2020), this final privesc step is chained after two earlier PAX-specific bugs: an XCB debug-service arbitrary read/write primitive (CVE-2020-28044) used to push a cross-compiled malicious shared object (built with `arm-none-eabi-gcc -shared -fPIC -o privesc.so privesc.c -nostartfiles`, embedding `setreuid(0,0); setuid(0); system("/bin/sh")`) over libsqlite3.so in a writable MAINAPP application directory, and PAX's lack of library signature verification (CVE-2020-28045) that lets that hijacked .so load and execute inside the root-executed MAINAPP process via LD_PRELOAD-style dynamic-linker hijacking — yielding uid=0(root) on the payment terminal.

Both techniques require the attacker to already hold local, low-privileged shell access and a sudoers grant covering the relevant binaries; there is no remote vector and no vendor patch is possible for the primary technique because the vulnerability is a sudoers policy decision, not a code defect. Defenders should audit sudoers/sudoers.d for NOPASSWD grants on iptables and iptables-save, avoid granting both together without strict argument restrictions, and ensure embedded/appliance Linux images pre-load all Netfilter kernel modules referenced by their iptables/ip6tables configuration so the --modprobe execution path can never trigger.

## MITRE ATT&CK

- T1587.001 Malware
- T1518.001 Security Software Discovery
- T1059.004 Unix Shell
- T1106 Native API
- T1136.001 Local Account
- T1548.003 Sudo and Sudo Caching
- T1548.001 Setuid and Setgid
- T1078.003 Local Accounts
- T1574.006 Dynamic Linker Hijacking
- T1565.001 Stored Data Manipulation

## Sources

- [A journey from sudo iptables to local privilege escalation](https://www.shielder.com/blog/2024/09/a-journey-from-sudo-iptables-to-local-privilege-escalation/)
- [TurinCTF 2017 - Finals](https://jbz.team/turinctf2017/turinctf_finals)
- [CVE-2020-28046 Detail](https://nvd.nist.gov/vuln/detail/CVE-2020-28046)
- [pax-pwn — PAX payment terminal root exploit writeup](https://git.lsd.cat/g/pax-pwn)
- [Shielder (@ShielderSec) — sudo iptables privilege escalation announcement](https://x.com/ShielderSec/status/1837124331756777885)
- [r/netsec share — A Journey From sudo iptables To Local Privilege Escalation](https://x.com/_r_netsec/status/1837125332496945192)
- [Shielder — suidpit author profile](https://www.shielder.com/authors/suidpit/)
- [pax-pwn Readme — PAX ProLinOS exploit chain (CVE-2020-28044/28045/28046)](https://git.lsd.cat/g/pax-pwn/src/branch/master/Readme.md)

## Full data

Detection queries (Splunk SPL / Microsoft KQL / Sigma) and IOC values require the Threadlinqs MCP server (Purple tier): https://intel.threadlinqs.com/mcp

Canonical: https://intel.threadlinqs.com/threat/TL-2026-2478
