← Back to all writeups

/usr/bin/strace — Sudo GTFOBins Abuse to Root

A SUID bit on a debugging tool most people never think to lock down. Here's how a stray strace binary turned a www-data shell into full root in two commands.

stracegtfobinssudolinuxprivilege-escalationsuid

strace is a diagnostic tool. It traces system calls a process makes — nothing more, in theory. But like a lot of “just a debugging utility” binaries, it’s powerful enough that if it’s misconfigured with elevated privileges, it stops being a diagnostic tool and starts being a root shell.

This lab was a clean example of exactly that.


The Setup

I landed a shell as www-data after exploiting a web application. Low privilege, but a foothold. From there I ran LinPEAS to sweep the box for anything exploitable, and cross-checked its SUID findings manually.


Enumeration

The classic first move on any fresh Linux foothold:

find / -perm -4000 2>/dev/null

find -perm -4000 output listing SUID binaries, with /usr/bin/strace at the top

/usr/bin/strace
/usr/bin/fusermount
/usr/bin/sudo
/usr/bin/su
...

Most of that list is expected — sudo, su, mount, passwd all legitimately need SUID to function. strace does not. A debugging utility that can attach to and manipulate arbitrary processes has no business running with the SUID bit set, because tracing a process gives you a front-row seat to everything it does — including spawning a shell on your behalf.

I checked GTFOBins to confirm the abuse path, since strace’s SUID entry is documented there directly.

GTFOBins strace page showing the SUID shell escalation payload


Exploitation

The GTFOBins payload for the SUID case is a single line:

strace -o /dev/null /bin/sh -p

strace command executed, id output showing euid=0(root) after the shell spawns

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

euid=0(root). That’s the effective UID — the one that actually governs what the shell is allowed to do. Root, confirmed.

Breaking down the command:

  • strace — invoked with its full SUID privileges intact, since it’s the binary that owns the elevated bit
  • -o /dev/null — redirect strace’s own trace output to /dev/null; I don’t care about the trace log, only about the process it spawns
  • /bin/sh -p — the program strace launches and attaches to. The -p flag tells the shell to stay in privileged mode instead of dropping to the real UID

Why This Works

When a SUID binary executes, the kernel sets the process’s effective UID to the file owner (root, here) while leaving the real UID as the calling user. Programs like strace need to be able to spawn and trace a child process as part of normal operation — that’s their entire purpose. When strace itself is SUID root, the child process it launches inherits that same privileged execution context before any privilege-dropping logic in the shell has a chance to kick in.

Normally, a shell spawned in this situation would notice real UID != effective UID and immediately drop back down to the real UID as a security measure — this is standard defensive behavior in bash and dash. The -p flag explicitly disables that check, telling the shell “no, keep the privileges you were just handed.” Without -p, the exact same command drops straight back to www-data and the exploit does nothing.

Since strace was SUID root, its child /bin/sh -p inherited euid=0 and kept it.


Root Cause

There is no legitimate reason for strace to carry the SUID bit in a production environment. It most likely ended up that way through a misconfigured provisioning script, a manual chmod +s during debugging that was never reverted, or a stale image built from an insecure base.

Fix:

# Remove the SUID bit immediately
chmod u-s /usr/bin/strace

# Sweep for other unexpected SUID binaries and cross-reference GTFOBins
find / -perm -4000 -type f 2>/dev/null

Any binary capable of executing arbitrary code, spawning shells, or attaching to other processes — strace, gdb, interpreters, debuggers — should never carry SUID unless there is a specific, documented, and narrowly scoped reason for it.


Key Takeaways

  • SUID enumeration (find / -perm -4000 2>/dev/null) should be one of the first things you run on any new foothold — it takes seconds and frequently pays off immediately
  • Not every SUID binary is a false positive just because it “looks like a system tool” — debugging and tracing utilities like strace are just as dangerous as shells when SUID
  • GTFOBins is the fastest way to check whether an unusual SUID binary has a documented escalation path
  • The -p flag on /bin/sh (or /bin/bash) is what keeps the elevated effective UID alive — without it, the shell silently drops privileges and the exploit fails

Questions? Hit me up on X.