the_open_door
coffee
ESEN
← Back to index

sudo over a writable script (or directory)

A sudo rule that lets you run a script (or an interpreter with a script as its argument) as root is only safe if that script can't be modified. If the file is writable by our user, or if the directory containing it is (we can delete and recreate it even when the original is protected), we control what sudo executes with root privileges.

The first step is reading sudo -l and checking the ownership of the script and its folder:

sudo -l
ls -l /path/to/script.py
ls -ld /path/to/

Two common variants:

The typical payload when the rule is sudo python <script> is to set the SUID bit on a shell or copy/edit sensitive files:

import os
os.system("chmod u+s /bin/bash")   # then: bash -p  ->  [[suid-abuse|euid=0]]

It's a special case of the general sudo-with-interpreters problem (GTFOBins): running python, perl or bash as root over a file we control scopes nothing. It differs from the cron over a writable script in who triggers execution (us, via sudo, instead of the scheduler).

How to detect it. sudo leaves the executed rule in /var/log/auth.log (or journalctl _COMM=sudo) with its user and arguments; the abuse shows because the privileged script does something out of character: a chmod +s /bin/bash, a sh/bash child, or a write to /root/.ssh (auditd/Sysmon for Linux over execve/open with the script's ppid). At rest, the signature is a script referenced by a sudo rule that is writable by a user or whose directory is (ls -ld), and its modification with a recent mtime just before a sudo is the preceding sign.

Defence. The binary or script a sudo rule points to, and its directory, must be owned by root and not writable by others. Never grant via sudo an interpreter with an editable script argument; pin absolute, non-tamperable paths.

Machines where it's used