Linux for Defenders 01: Who Can Become Root? Audit sudo and Groups
0 / 7 steps
The goal
By the end you will know exactly who can become root on your Linux machine, and how. You will read the group that grants admin rights, add a user to it, write one safe narrow rule with visudo, see why one risky rule quietly hands over the whole machine, and find every use of admin rights in the logs. This is the first thing to check on a box you have just been handed, and the first thing an attacker checks too.
Your own VM only. Every command here changes who can administer a machine, so run them on a Linux VM you own and can roll back — the Kali or target VM from Lab 00, or any throwaway Ubuntu. Take a snapshot first. Nothing here touches another person’s system.
Why this lab. “Who can run things as root” is the single most important question about a Linux box, and almost nobody can answer it for their own machine. A SOC analyst reads this to spot a backdoor; an auditor reads it to pass a control; an attacker reads it to find the easy way up. Same three files, three different reasons.
Steven once gave a contractor sudo “just for the afternoon.” That was in 2019. The account is still there. — Nyx
Before you start. You need a Linux VM and a terminal on it. The walkthrough is Ubuntu/Debian; the Red Hat differences are called out at each step and summed up at the end. You will create two throwaway users, alex and sam, so nothing you do lands on a real account.
Steps
01See who you are and who holds admin
Create the two test users, then ask the system who is in the admin group. On Ubuntu and Debian that group is sudo.
$ sudo useradd -m -s /bin/bash alex $ sudo useradd -m -s /bin/bash sam $ id sam $ getent group sudo
You should see, straight off the machine this lab was built on:
$ id sam uid=1002(sam) gid=1002(sam) groups=1002(sam) $ getent group sudo sudo:x:27:ubuntu
Right now sam is in only their own group, and the sudo group holds just the ubuntu account the VM shipped with. That is your baseline: anyone listed after that last colon can become root.
Why this matters. Group membership is the quiet way in. An attacker who adds a name here has handed themselves root, and the only sign is one extra name on this line. You cannot notice a name that should not be there until you know the names that should.
02Grant admin the normal way, and read the result
Add alex to the admin group — the ordinary way a person is made an administrator — and watch both views change.
$ sudo usermod -aG sudo alex $ getent group sudo sudo:x:27:ubuntu,alex $ id alex uid=1001(alex) gid=1001(alex) groups=1001(alex),27(sudo)
That is real output. alex now appears on the group line and shows group 27(sudo) in their own id. Either view answers “can this person become root?” — and the two must always agree.
The -a matters. usermod -aG adds a group. Forget the -a and usermod -G sudo alex replaces every one of alex’s groups with just sudo — a classic way people lock themselves out of things. Always -aG.
03Read the rulebook: /etc/sudoers and its drop-in folder
Group membership is one half. The other half is the sudoers rulebook, which says what each person or group may run. Read it — the non-comment lines only.
$ sudo grep -Ev '^\s*(#|$)' /etc/sudoers
Defaults env_reset
Defaults mail_badpass
Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin"
Defaults use_pty
root ALL=(ALL:ALL) ALL
%admin ALL=(ALL) ALL
%sudo ALL=(ALL:ALL) ALL
@includedir /etc/sudoers.d
Read the line %sudo ALL=(ALL:ALL) ALL as: members of group sudo (the % means a group), on any host, may run any command as any user. That one line is why adding alex to the group in step 2 was enough. The last line pulls in extra rules from a folder, and that folder is where real systems keep most of their rules:
$ sudo ls -la /etc/sudoers.d/ $ stat -c '%a %U:%G %n' /etc/sudoers 440 root:root /etc/sudoers
The rulebook is mode 440, owned by root: readable only by root, writable by no one, not even root without forcing it. That is deliberate — sudo refuses to run if these permissions are loose.
Why this matters. People check the group and stop. Half the real grants live in /etc/sudoers.d/ as one-line files, and a backdoor rule hides there far more comfortably than in the main file. Always read the folder too.
04Write one narrow rule the safe way
Give sam exactly one power: restart the SSH service, nothing else. Never edit sudoers with a normal editor — visudo checks your syntax before it saves, and a syntax error in sudoers can lock everyone out of root.
$ sudo visudo -f /etc/sudoers.d/50-sam
Put one line in it, save and close:
sam ALL=(root) /usr/bin/systemctl restart ssh
Now confirm it took, by asking sudo what sam may do:
$ sudo -l -U sam
User sam may run the following commands on labvm:
(root) /usr/bin/systemctl restart ssh
Exactly one power, and sudo -l -U sam is the report that proves it. See what visudo saves you from — feed it a broken rule on purpose:
$ echo 'sam ALL=root' | sudo visudo -cf -
stdin:1:9: expected a fully-qualified path name
sam ALL=root
^~~~
It names the line, the column and the problem, and refuses to save. A plain editor would have written that broken line straight into your rulebook.
Why this matters. “Least privilege” stops being a slogan here: sam can bounce SSH and do nothing else. That is how production access should look, and how rarely it does.
05See how one “helpful” rule hands over the whole box
Now the attacker’s-eye view. A rule that looks harmless — let the help desk read logs with less, no password — is actually full root. Add it, then read why.
$ echo 'sam ALL=(root) NOPASSWD: /usr/bin/less' | sudo tee /etc/sudoers.d/60-helpdesk $ sudo chmod 0440 /etc/sudoers.d/60-helpdesk $ sudo -l -U sam User sam may run the following commands on labvm: (root) /usr/bin/systemctl restart ssh (root) NOPASSWD: /usr/bin/less
The attacker’s view. less can launch a shell from inside itself (type !sh while viewing a file). Run as root with no password, that shell is a root shell. The public GTFOBins list catalogues dozens of everyday commands — less, vi, find, awk, tar — that each turn a narrow sudo grant into full root.
The defender’s move. Treat every sudo rule as “can this binary start a shell or write a file as root?” If yes, the scope is a fiction. NOPASSWD on any such command is a finding. Hunt them across every rule file at once:
$ sudo grep -rnwE 'less|more|vi|vim|nano|man|find|awk|python3?|perl|tar|git|env' /etc/sudoers /etc/sudoers.d/ | grep -v '#'
/etc/sudoers.d/60-helpdesk:1:sam ALL=(root) NOPASSWD: /usr/bin/less
One hit, and it is the rule you just planted. On a real box, that is the line you escalate to whoever owns the server.
06Find every use of admin rights in the logs
Every sudo call is logged whether it succeeds or fails. Make a little activity, then read it back. First, run a command through the risky rule and try one that is not allowed:
$ sudo journalctl _COMM=sudo --since today -o cat | grep COMMAND=
sam : PWD=/home/sam ; USER=root ; COMMAND=/usr/bin/less /etc/shadow
alex : a password is required ; PWD=/home/alex ; USER=root ; COMMAND=/usr/bin/cat /etc/shadow
That is real log output. Two entries: sam ran less on the password file through that no-password rule, and alex was stopped — “a password is required” — trying something not covered. Both the allowed and the blocked attempt are recorded. On a system without journald, the same lines are in a file:
$ sudo grep sudo /var/log/auth.log | tail -4
... labvm sudo: sam : PWD=/home/sam ; USER=root ; COMMAND=/usr/bin/less /etc/shadow
... labvm sudo: pam_unix(sudo:session): session opened for user root(uid=0) by (uid=1002)
Why this matters. This is the audit trail. “Who ran what as root, and when” is answered here — and the blocked attempts matter as much as the successes, because a run of “a password is required” or “user NOT in sudoers” lines is somebody testing the fence. On Red Hat the file is /var/log/secure instead of /var/log/auth.log.
07Clean up, and prove the fix
Remove the dangerous rule and confirm it is gone. Removing the file is the whole fix — no restart needed, sudo re-reads the folder every time.
$ sudo rm /etc/sudoers.d/60-helpdesk $ sudo -l -U sam User sam may run the following commands on labvm: (root) /usr/bin/systemctl restart ssh
Back to one narrow power. That before-and-after — the sudo -l -U sam report with the bad rule, then without it — is exactly the evidence you would attach to a ticket: here was the finding, here is the fix, here is proof it is closed.
Why this matters. A finding without proof of the fix is half a job. The same one-line report is your evidence both times.
What you learned
- getent group sudo — who can become root through group membership (Red Hat: group wheel)
- /etc/sudoers and /etc/sudoers.d/ — the rulebook and its drop-in folder; read both, every time
- visudo — the only safe way to edit sudo rules; it refuses to save a broken one
- sudo -l -U name — the one report that says what a user can actually run
- NOPASSWD on a shell-capable command — a narrow-looking rule that is really full root; a finding every time
- journalctl _COMM=sudo / /var/log/auth.log — the audit trail of who ran what as root, successes and refusals alike
On Red Hat (RHEL, Rocky, Fedora) and Debian. Tested on Rocky Linux 9: the admin group is wheel, not sudo (getent group wheel, and the rule reads %wheel ALL=(ALL) ALL), and the sudo log is /var/log/secure. Add a user with usermod -aG wheel name. Everything else — visudo, /etc/sudoers.d/, sudo -l, journalctl _COMM=sudo — is identical. Debian 12 matches Ubuntu exactly: group sudo, /var/log/auth.log.
Put it on your resume. Audited sudo/privilege configuration on Linux (group membership, /etc/sudoers.d rules, GTFOBins-style over-grants) and reconstructed admin activity from the authentication logs. Change it to match what you actually did.
Tried it? Tell us
Nova built this lab from Steven’s ideas, and every command above was run on a real machine before it went up. If a step behaved differently for you, or you know a better way, tell us. Ideas for the next lab are welcome too — no promises on timing.
NextLinux for Defenders 02 — What’s running that you didn’t start?→
Go deeper
- Linux users, passwords and permissions — the /etc/passwd and /etc/shadow side of accounts
- Linux privilege escalation cheat sheet — why less, vi and find are on the GTFOBins list
- Lab 09 — Read your own logs — the wider first-response triage this fits into
Original walkthrough. Every command and every output block above was run on Ubuntu 24.04 (sudo 1.9.15p5, systemd journald) and the Red Hat differences on Rocky Linux 9.8; Debian 12 was checked for the group and log-file names. If something does not match your machine, tell me and I’ll fix it.