Description
Can you read the flag? I think you can!
Setup
Launch the challenge instance and SSH in.
Check what sudo privileges the current user has.
Solution
Walk me through it- Step 1Check sudo permissionsRun
sudo -l. The first move on any sudo box. If a NOPASSWD rule exists for any binary that can shell out (vim, less, find, awk, perl, emacs), GTFOBins has a tested escape sequence.bashsudo -lLearn more
sudo reads rules from
/etc/sudoersdescribing which user can run which command as which target user, with or without a password.sudo -lprints the rules that apply to you. Always run it first.The classic misconfigurations: text editors (vim, emacs, nano), interpreters (python, perl, ruby), file utilities that shell out (find with
-exec, awk withsystem()), pagers (less, man), and the NOPASSWD directive which makes the escape silent.Always go to GTFOBins first. It is the canonical, version-tested catalog of Unix binaries that bypass local restrictions when invoked with elevated privileges, and the listed escape sequence almost always works on the first try. Memorizing escapes is a waste of time; reading GTFOBins is not.
- Step 2Escape to a root shell from emacsPick the right escape. Interactive (
M-x term) if you want a stable root shell to poke around in - good for learning, good when you control the terminal. Non-interactive (--batch --eval) if the environment is restricted (no PTY, no proper terminal allocation, automation pipeline) - dumps the file in one shot and exits.bashsudo emacsbash# Inside emacs:bash# Press Alt+X (M-x), type 'term', press Enterbash# Then at the terminal prompt: cat /home/ctf-player/flag.txtbashbash# Non-interactive alternative:bashsudo emacs -Q -nw --eval '(term "/bin/bash")'bash# Or direct file read:bashsudo emacs -Q --batch --eval '(with-temp-buffer (insert-file-contents "/home/ctf-player/flag.txt") (message "%s" (buffer-string)))'Learn more
GNU Emacs is a Lisp-based computing environment that happens to edit text. M-x term (Meta+X, type "term", Enter) spawns an interactive terminal emulator inside Emacs. The shell it launches inherits the process privileges of Emacs itself - which, when Emacs is run via
sudo, means root.Annotated batch escape:
sudo emacs -Q --batch --eval ' (with-temp-buffer ;; create a throwaway buffer (no UI) (insert-file-contents "/home/ctf-player/flag.txt") ;; read as root (message "%s" (buffer-string)))' ;; print to stderrwith-temp-buffercreates an in-memory scratch buffer;insert-file-contentsperforms the privileged read;(message ...)writes to stderr, which the calling shell captures and displays. No PTY, no interactive shell, no flag-text-to-screen indirection - exactly what you want when the box is locked down.The challenge name nods to xkcd #149: "sudo make me a sandwich." The serious lesson behind the joke is the principle this challenge embodies: any program that can shell out, when run via sudo, becomes a full privilege escalation primitive. Editors, pagers, scripting interpreters, file-finding tools - they all collapse the "run X as root" permission into "run anything as root." See the Linux CLI for CTF guide for adjacent enumeration patterns.
- Step 3Read the flagWith root privileges in the spawned shell, read the flag file.bash
cat /home/ctf-player/flag.txtbash# or: find / -name flag.txt 2>/dev/nullLearn more
In CTF challenges, flag files are commonly placed in the home directory of a specific user (
/home/ctf-player/), in/root/, or in/flag.txtat the filesystem root. With a root shell, all of these are accessible. Thefind / -name flag.txt 2>/dev/nullcommand searches the entire filesystem for files namedflag.txt, with stderr redirected to/dev/nullto suppress permission errors from directories you cannot read (though with root, that is no longer an issue).In real-world privilege escalation scenarios, post-exploitation tasks are more varied: reading sensitive configuration files (
/etc/shadow, database credentials), accessing other users' home directories, modifying system files to maintain persistence, or pivoting to other networked systems. In a CTF, the target is simply the flag file, making the privilege escalation goal clear and specific.Proper defenses against sudo abuse include: applying the principle of least privilege (grant only the specific capabilities users truly need), auditing sudoers files regularly, using sudo -l output as part of security reviews, and preferring container-based privilege separation over UNIX user permission models where possible.
Flag
picoCTF{g0tt4_l0v3_s4ndw1ch3s_...}
The sudo config allows running emacs as root. Emacs includes a full terminal emulator (M-x term) - any shell spawned from within it runs as root, giving direct access to the flag file.
How to prevent this
How to prevent this
Granting sudo to a feature-rich binary (vim, less, emacs, find, awk, perl) is equivalent to granting sudo ALL. GTFOBins enumerates them.
- Audit your
/etc/sudoersagainst GTFOBins. Any binary with a shell-out command (:!shin vim,!shin less,M-x termin emacs) breaks the principle of least privilege. - If you genuinely need a user to run one task as root, write a tiny purpose-built script and grant sudo on that script only. Validate every argument; reject anything starting with
-. - Replace sudo grants with capabilities. Capabilities split UID 0 into ~40 fine-grained privileges; sudo hands over the whole thing. The canonical case: a Python web server that needs to bind port 80 (a privileged port). Don't do
sudo python server.py- that gives the script root. Instead:# Grant *only* "may bind low ports" to the python interpreter: sudo setcap cap_net_bind_service+ep $(readlink -f $(which python3)) # Now this works without sudo, with no other root powers: python3 -m http.server 80
cap_net_bind_service+epis permitted+effective for that one capability. The script cannot read /etc/shadow, modify /root, or shell out as root - it can only bind low ports. systemd unit files express the same idea viaAmbientCapabilities=.