Linux command line, privilege escalation: su, sudo commands
Greetings!

We continue studying the Linux command line. Today we’ll learn how to properly run commands on behalf of another user, including the root user. We’ll get familiar with the su and sudo commands, and also learn how to correctly grant limited privileges to users and groups.

Along the way, let’s figure out why sudo su is like saying: “Open the door for me,” and then demanding again: “And let me in right now!"😁.

If you’re new to the world of Linux, I recommend reading my previous command-line articles:

Preface

The topic of privileges in Linux is very extensive. In this article we’ll only cover working with the su and sudo commands, as the most popular tools. But there are also many other mechanisms, for example capabilities, SELinux, AppArmor, and PolicyKit in general, and of course ACL (Access Control Lists). You can go crazy just from the variety🤯.

So, let’s get started.

The su command

su (Substitute User or Set UID or Switch User or Super User — substitute/switch user, superuser) is a classic command and utility of the same name in Unix-like operating systems, allowing a user to log in under a different name without ending the current session. Most often used to run some commands or temporarily log in with superuser privileges to perform administrative tasks. Simple and clear 😉.

The author of this program is Dennis Ritchie. If you believe the English Wikipedia, the first release of this utility was on November 3, 1971. Almost 53 years ago😲. And despite this, it’s still popular today. Truly the Unix philosophy in action: “a program should do one thing and do it well.”

So, the syntax:

BASH
su [options] [-] [username]
Click to expand and view more

If you don’t explicitly pass a username to the command, the name root will be used.

A feature of the command is that it asks for a password every time it’s run. Only if it isn’t already being run as the root user.

Commonly used options:

Let’s get to practice. If you type in the terminal:

BASH
su -
Click to expand and view more

We’ll be asked for the root superuser password, after which we’ll switch to it.

If you explicitly pass the desired username to the command, for example:

BASH
su - ivan
Click to expand and view more

Then, accordingly, we’ll activate a shell session under their name.

There’s a fundamental difference between specifying the - or -l option and omitting it. If you don’t specify the option, then when switching to another user, your current working directory and part of the user’s environment (env) won’t change. Here’s an example:

BASH
whoami

echo $USER

su

whoami

echo $USER
Click to expand and view more

Here we can see that after switching to the superuser account, the $USER environment variable, which contains the name of the current user, was not updated. It’s important to remember this nuance, especially when writing scripts, if they use the su command.

Now let’s try running a single command, without switching users:

BASH
su -c 'whoami'
Click to expand and view more

And now using a hyphen:

BASH
su -c 'pwd'

su - -c 'pwd'
Click to expand and view more

I hope you understood the difference. And a couple more examples to reinforce it.

With a hyphen:

BASH
su -

su - ivan -c 'whoami'
Click to expand and view more

Without:

BASH
su -c 'whoami && pwd'
Click to expand and view more

The sudo command

sudo (Substitute User and do, literally “substitute the user and do”) is also a command and utility of the same name, allowing you to delegate certain privileged resources to users while logging their actions.

And for almost the whole time I thought that sudo = super user do 😳

sudo comes preinstalled with most UNIX and UNIX-like operating systems, but, for example, “pure” Debian is not on that list. In the case of this distribution, the sudo utility needs to be installed separately!

Unlike the classic su, sudo provides more flexible tools for configuring privilege escalation. Most often, sudo is used to set a clear list of commands available to run on behalf of another user, including root.

Syntax:

BASH
sudo [options] command
Click to expand and view more

Commonly used options:

Let’s start practicing with a common but rather comical situation — when the following command is used to obtain root privileges:

BASH
sudo su
Click to expand and view more

Essentially, there’s nothing terrible about it, but it’s incorrect syntactically.

Instead, it’s recommended to use the following commands:

BASH
sudo -s

# or

sudo -i

# or

su -
Click to expand and view more

The thing is, when you run sudo su, you create an extra process. You end up running two different commands at once.

For a demonstration, let’s run:

BASH
sudo su

ps

exit

sudo -s

ps
Click to expand and view more

As you can see at the top of the screenshot, there’s one more process🤷‍♂️.

Now let’s try running a single command, without switching to another user:

BASH
sudo -u postgres 'whoami'
Click to expand and view more

And to switch to another user’s shell (analogous to su - <user>), let’s run:

BASH
sudo -iu postgres

whoami

pwd
Click to expand and view more

In this case both the working directory and the environment will belong to the target user.

Sudoers files

We’re now smoothly getting to the main feature of the sudo utility — sudoers files. These are files in which, following a strict syntax, you can finely configure the delegation of privileges for users and groups.

The main configuration file is located at: /etc/sudoers. It’s usually already filled with default and commented values.

By default, this file already sets maximum privileges for the sudo group on Deb systems (Debian, Ubuntu, Linux Mint) and wheel for RPM (RHEL, Centos, Fedora, OpenSuse).

Users of this group have the ability to switch to the root account.

To check, run:

BASH
sudo cat /etc/sudoers

groups
Click to expand and view more

To extend the standard sudo configuration, it’s recommended to create separate files in the /etc/sudoers.d directory. Often, various distributions already have some files there. For example, in Linux Mint, there’s:

BASH
ls -l /etc/sudoers.d
Click to expand and view more

It’s recommended to create such files using the special visudo command, which checks the file’s syntax before saving it, and shows a warning in case of an error.

Let’s create such a file. But first let’s choose the default console editor with this command (for Deb systems):

BASH
sudo update-alternatives --config editor
Click to expand and view more

Of course we choose 😉, because I haven’t restarted my computer in a while😁

Now let’s create a file with the list of available commands for the account from the example above — postgres and the group — ivan:

BASH
sudo visudo -f /etc/sudoers.d/postgres
Click to expand and view more

The content might look like this:

BASH
Cmnd_Alias PG = \ 
    /usr/sbin/ldconfig, \ 
    /usr/sbin/setcap CAP_NET_ADMIN\,CAP_NET_BIND_SERVICE+epi /usr/lib/postgresql/16/bin/postgres, \ 
    /usr/bin/systemctl status postgresql, \
    /usr/bin/systemctl start postgresql, \
    /usr/bin/systemctl stop postgresql, \
    /usr/bin/systemctl restart postgresql, \
    /usr/bin/journalctl * postgresql, \
    /usr/bin/cat /var/log/auth.log

postgres ALL = (root) NOPASSWD: PG
%ivan ALL = (postgres) NOPASSWD: ALL
Click to expand and view more

I won’t go through the commands themselves, I’ll just describe the sudoers directives:

Save and exit the editor.

If you make a mistake, you’ll see a message like this indicating where you went wrong:

Type e and press Enter to return to the editor. You need to know about the letter e, since the program doesn’t give any hints, quite harsh really🤔.

If you filled everything in correctly, visudo will let you save the file and close the editor.

In the example above, we set up full access to the postgres user for members of the ivan group. And in turn, we allowed postgres to run a strict list of commands on behalf of root.

Let’s check:

BASH
sudo -l

sudo -iu postgres

sudo -l
Click to expand and view more

When entering an allowed command, it will simply run🤷‍♂️. And when using a command not in the allowed list, and if your user isn’t added to the admin group (sudo or wheel), the sudo utility will, as expected, deny its execution. Example:

BASH
sudo systemctl status postgresql

sudo systemctl enable postgresql
Click to expand and view more

Well, I think I’ve told you everything.

Oh, and just recently I learned that when using sudo, the $PATH environment variable becomes irrelevant. For the sudo utility, a special secure_path directive is set in the /etc/sudoers file with a list of directories where executable files are stored:

BASH
Defaults  secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin:/opt/bin"
Click to expand and view more

Now you know about this too☺️.

Viewing the sudo event log

By default the sudo program logs its actions to the system log, aka syslog. In Linux distributions using systemd as the init system, you can view the log of actions related to sudo using the journalctl utility:

BASH
sudo journalctl | grep -i sudo
Click to expand and view more

If you need to watch sudo usage in real time — add the -f or --follow option:

BASH
sudo journalctl --follow | grep -i sudo
Click to expand and view more

Note that the executed commands also end up in the log.

If you need to save the action log to a file, you can configure this by adding the corresponding parameter to the main config file /etc/sudoers. Open it for editing with the command:

BASH
sudo -E visudo
Click to expand and view more

And add the line:

PLAINTEXT
Defaults    logfile="/var/log/sudo.log"
Click to expand and view more

Save the file and close the editor. Just in case, let’s check the permissions on the log file:

BASH
sudo ls -l /var/log/sudo.log
Click to expand and view more

It should look like this:

If not, set restricted permissions manually:

BASH
sudo chmod 600 /var/log/sudo.log
Click to expand and view more

If you need to record the output of commands executed via sudo, similarly add the following logging setting to the /etc/sudoers file:

PLAINTEXT
Defaults    log_input, log_output
Click to expand and view more

Now, after every command executed with sudo, its entire output will be saved in the /var/log/sudo-io directory.

To view saved output, a special sudoreplay command is used (damn magic). Example of viewing the first saved command:

BASH
sudo head -n15 /etc/sudoers

sudo sudoreplay /var/log/sudo-io/00/00/01
Click to expand and view more

It’s worth warning you that in this mode even sessions of pseudo-graphical programs, such as console editors (vim, nano) and visualizers (top, htop), are recorded, which can quickly fill up disk space.

Afterword

We’ve taken another step on the path of studying the Linux command line. As I said at the beginning of the article, the topic of privileges, and security in general, in the world of Linux is very extensive and will always be relevant. So try to spend time not only learning technologies, but also using them safely.

Thanks for reading. Good luck! And try to do everything with a sound dose of security in mind.

Useful materials

Copyright Notice

Author: Ivan Cherniy

Link: https://r4ven.me/en/linux/komandnaya-stroka-linux-povyshenie-privilegij-komandy-su-sudo/

License: CC BY-NC-SA 4.0

Blog materials may be used with attribution to the author and source, for non-commercial purposes, and under the same license.

Start searching

Enter keywords to search articles

↑↓
ESC
⌘K Shortcut