← Back to all writeups

SUID php7.4 — From www-data to Root in One Command

During a lab exercise I landed a shell as www-data. A quick SUID enumeration revealed php7.4 with the SUID bit set. Here's how I went from a low-privilege web shell to full root access.

suidphpprivilege-escalationlinuxgtfobins

Some privilege escalation paths take hours of enumeration, chaining multiple misconfigurations together before you finally land root. And then there are the ones that take thirty seconds.

This was one of those.


The Setup

I was working through a lab on a Linux machine. After exploiting a web vulnerability I had a shell running as www-data — the default low-privilege user Apache and Nginx run under. Stable shell, but nowhere near root.

Time to enumerate.


Enumeration — Hunting for SUID Binaries

The first thing I always check on a Linux machine after getting a foothold is SUID binaries. SUID (Set User ID) means the binary runs with the file owner’s privileges rather than the caller’s. If root owns a binary with the SUID bit set and that binary can be abused — you’re root.

The command for finding them is simple:

find / -perm -4000 2>/dev/null
  • find / — search from the root of the filesystem
  • -perm -4000 — find files with the SUID bit set
  • 2>/dev/null — suppress permission errors so the output stays clean

SUID enumeration output showing php7.4 at the bottom

Most of the output was standard — sudo, passwd, mount, su. Nothing unusual. But right at the bottom of the list, one binary stood out:

/usr/bin/php7.4

PHP with the SUID bit set. That’s not standard. That’s a misconfiguration. And it’s a very exploitable one.


Why php7.4 With SUID Is Game Over

PHP is a fully featured scripting language. It can execute system commands, spawn shells, read files — basically anything you’d want to do as an attacker. If it runs with elevated privileges because of the SUID bit, you can use it to execute arbitrary code as root.

GTFOBins documents exactly how to abuse this. The payload uses pcntl_exec — a PHP function that replaces the current process with a new one — to spawn /bin/sh with the -p flag, which preserves the elevated effective UID.


Exploitation

One command. That’s all it took:

/usr/bin/php7.4 -r "pcntl_exec('/bin/sh', ['-p']);"

Breaking it down:

  • /usr/bin/php7.4 — calling PHP directly with its full path
  • -r — run PHP code inline without a file
  • pcntl_exec('/bin/sh', ['-p']) — replace the current process with /bin/sh, passing -p to preserve the SUID effective UID

Shell spawned as root — whoami returns root, euid=0

The shell dropped immediately. Running whoami returned root. Running id confirmed it:

uid=33(www-data) gid=33(www-data) euid=0(root) groups=33(www-data)

euid=0 — effective user ID of 0. That’s root. The real UID is still www-data but the effective UID — which is what actually matters for privilege checks — is root.

Root confirmed. Mission complete.


Why This Works — The -p Flag Explained

When you run /bin/sh -p, the shell enters privileged mode. Normally, if a shell detects that the real UID doesn’t match the effective UID, it drops the elevated privileges as a security measure. The -p flag disables that behavior and keeps the effective UID intact.

Without -p:

/usr/bin/php7.4 -r "pcntl_exec('/bin/sh', []);"
# → shell drops to www-data, privileges lost

With -p:

/usr/bin/php7.4 -r "pcntl_exec('/bin/sh', ['-p']);"
# → shell keeps euid=0 (root) ✅

One flag. The difference between a useless shell and full root access.


Root Cause

The SUID bit was set on php7.4 — almost certainly by accident. This kind of misconfiguration typically happens when:

  • A developer sets SUID on PHP temporarily for testing and forgets to remove it
  • An automated setup script incorrectly applies permissions
  • Someone copies a binary from another system without checking its attributes

Fix: Remove the SUID bit from PHP immediately:

chmod u-s /usr/bin/php7.4

And audit ALL SUID binaries on your systems regularly. Any binary that isn’t explicitly required to be SUID should have that bit removed.


Key Takeaways

  • Always run find / -perm -4000 2>/dev/null early in your enumeration — SUID misconfigurations are common and often trivially exploitable
  • Cross-reference any unusual SUID binaries against GTFOBins — it covers almost every binary you’ll encounter
  • The -p flag in /bin/sh is what preserves the elevated effective UID — without it, privilege escalation via SUID won’t work in most cases
  • PHP should never have the SUID bit set in any environment

Questions? Hit me up on X.