Now that we’ve looked at the basics of setting up a good sudo configuration, we’re confronted with a bit of a paradox. That is, even though sudo is a security tool, certain things that you can do with it can make your system even more insecure than it was. Let’s see how to avoid that.
The sudo timer
By default, the sudo timer is set for five minutes. This means that once a user performs one sudo command and enters a password, he or she can perform another sudo command within five minutes without having to enter the password again. Although this is obviously handy, it can also be problematic if users were to walk away from their desks with a command terminal still open.
If the five-minute timer hasn’t yet expired, someone else could come along and perform some root-level task. If your security needs require it, you can easily disable this timer by adding a line to the Defaults section of the sudoers file. This way, users will have to enter their passwords every time they run a sudo command. You can make this a global setting for all users, or you can just set it for certain individual users.
Let’s also say that you’re sitting in your nice, cozy cubicle, logged in to a remote Linux server that still has the five-minute timer enabled. If you need to leave your desk for a moment, your best action would be to log out of the server first. Short of that, you could just reset the sudo timer by running this command:
This is one of the few sudo actions you can do without entering a password. But the next time you do a sudo command, you will have to enter your password, even if it has been less than five minutes since you entered your password previously.
View your sudo privileges
Are you unsure of what sudo privileges that you possess? Not to worry, you have a way to find out. Just run this command:
When I do this for myself, I first see some of the environmental variables for my account, and then I see that I have full sudo privileges:
donnie@packtpub1:~$ sudo -l [sudo] password for donnie: Matching Defaults entries for donnie on packtpub1: env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin User donnie may run the following commands on packtpub1: (ALL : ALL) ALL donnie@packtpub1:~$
When Frank, my formerly feral flamepoint Siamese cat, does this for his account, he sees that he can only do the fdisk -l command:
frank@packtpub1:~$ sudo -l [sudo] password for frank: Matching Defaults entries for frank on packtpub1: env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin User frank may run the following commands on packtpub1: (ALL) /sbin fdisk -l frank@packtpub1:~$
But since he’s a cat, he doesn’t complain. Instead, he’ll just try to do something sneaky, as we’ll see in just a bit.
Hands-on lab for disabling the sudo timer
For this lab, you’ll disable the sudo timer on your CentOS VM:
- Log in to the same CentOS virtual machine that you used for the previous lab. We’ll be using the user accounts that you’ve already created.
- At your own user account command prompt, enter the following commands:
sudo fdisk -l sudo systemctl status sshd sudo iptables -L
You’ll see that you only needed to enter the password once to do all three commands.
- At your own user account command prompt, run the following:
sudo fdisk -l sudo -k sudo fdisk -l
Note how the sudo -k command resets your timer, so you’ll have to enter your password again. Open visudo with the following command:
In the Defaults specification section of the file, add the following line:
Defaults timestamp_timeout = 0
Save the file and exit visudo.
- Perform the commands that you performed in Step 2. This time, you should see that you have to enter a password every time.
- Open visudo and modify the line that you added so that it looks like this:
Defaults:lionel timestamp_timeout = 0
Save the file and exit visudo.
- From your own account shell, repeat the commands that you performed in Step 2. Then, log in as Lionel and perform the commands again.
- View your own sudo privileges by running the following:
Preventing users from having root shell access
Let’s say that you want to set up a user with limited sudo privileges, but you did so by adding a line like this:
maggie ALL=(ALL) /bin/bash, /bin/zsh
I’m sorry to say that you haven’t limited Maggie’s access at all. You have effectively given her full sudo privileges with both the Bash shell and the ZSH shell. So, don’t add lines like this to your sudoers because it will get you into trouble.
Preventing users from using shell escapes
Certain programs, especially text editors and pagers, have a handy shell escape feature. This allows a user to run a shell command without having to exit the program first. For example, from the command mode of the Vi and Vim editors, someone could run the ls command by running :!ls. Executing the command would look like this:
# useradd defaults file GROUP=100 HOME=/home INACTIVE=-1 EXPIRE= SHELL=/bin/bash SKEL=/etc/skel CREATE_MAIL_SPOOL=yes ~ ~ :!ls
The output would look like this:
[donnie@localhost default]$ sudo vim useradd [sudo] password for donnie: grub nss useradd Press ENTER or type command to continue grub nss useradd Press ENTER or type command to continue
Now, imagine that you want Frank to be able to edit the sshd_config file and only that file. You might be tempted to add a line to your sudo configuration that would look like this:
frank ALL=(ALL) /bin/vim /etc/ssh/sshd_config
This looks like it would work, right? Well, it doesn’t, because once Frank has opened the sshd_config file with his sudo privilege, he can then use Vim’s shell escape feature to perform other root-level commands, which includes being able to edit other configuration files. You can fix this problem by having Frank use sudoedit instead of vim:
frank ALL=(ALL) sudoedit /etc/ssh/sshd_config
sudoedit has no shell escape feature, so you can safely allow Frank to use it. Other programs that have a shell escape feature include the following:
Preventing users from using other dangerous programs
Some programs that don’t have shell escapes can still be dangerous if you give users unrestricted privileges to use them. These include the following:
If you must give someone sudo privileges to use one of these programs, it’s best to limit their use to only specific files. And that brings us to our next tip.
Limiting the user’s actions with commands
Let’s say that you create a sudo rule so that Sylvester can use the systemctl command:
sylvester ALL=(ALL) /usr/bin/systemctl
This allows Sylvester to have full use of the systemctl features. He can control daemons, edit service files, shut down or reboot, and carry out every other function that systemctl does. That’s probably not what you want. It would be better to specify what systemctl functions that Sylvester is allowed to do. Let’s say that you want him to be able to control just the Secure Shell service. You can make the line look like this:
sylvester ALL=(ALL) /usr/bin/systemctl * sshd
It will gives you output similar to below:Sylvester can now do everything he needs to do with the Secure Shell service, but he can’t shut down or reboot the system, edit other service files, or change systemd targets. But what if you want Sylvester to do only certain specific actions with the Secure Shell service? Then you’ll have to omit the wildcard and specify all of the actions that you want Sylvester to do:
sylvester ALL=(ALL) /usr/bin/systemctl status sshd, /usr/bin/systemctl restart sshd
Now, Sylvester can only restart the Secure Shell service or check its status.
When writing sudo policies, you’ll want to be aware of the differences between the different Linux and Unix distributions on your network. For example, on Red Hat and CentOS systems, the systemctl binary file is located in the /usr/bin directory. On Debian/Ubuntu systems, it’s located in the /bin directory. If you have to roll out a sudoers file to a large enterprise network with mixed operating systems, you can use host aliases to ensure that servers will only allow the execution of commands that are appropriate for their operating systems.
Also, be aware that some system services have different names on different Linux distributions. On Red Hat and CentOS systems, the Secure Shell service is sshd. On Debian/Ubuntu systems, it’s just plain ssh.
Letting users run as other users
In the following line, (ALL) means that Sylvester can run the systemctl commands as any user:
sylvester ALL=(ALL) /usr/bin/systemctl status sshd, /usr/bin/systemctl restart sshd
This effectively gives Sylvester root privileges for these commands because the root user is definitely any user. You could, if desired, change that (ALL) to (root) in order to specify that Sylvester can only run these commands as the root user:
sylvester ALL=(root) /usr/bin/systemctl status sshd, /usr/bin/systemctl restart sshd
Okay, there’s probably not much point in that because nothing changes. Sylvester had root privileges for these systemctl commands before, and he still has them now. But there are more practical uses for this feature. Let’s say that Vicky is a database admin, and you want her to run as the database user:
vicky ALL=(database) /usr/local/sbin/some_database_script.sh
Vicky could then run the command as the database user by entering the following command:
$ sudo -u database some_database_script.sh
This is one of those features that you might not use that often, but keep it in mind anyway. You never know when it might come in handy.
Preventing abuse via user’s shell scripts
So, what if a user has written a shell script that requires sudo privileges? To answer that, let’s have Frank create the frank_script.sh shell script that looks like this:
#!/bin/bash echo "This script belongs to Frank the Cat."
Okay, he wouldn’t need sudo privileges for that, but let’s pretend that he does. After he sets the executable permission and runs it with sudo, the output will look like this:
frank@packtpub1:~$ sudo ./frank_script.sh [sudo] password for frank: Sorry, user frank is not allowed to execute './frank_script.sh' as root on packtpub1.tds. frank@packtpub1:~$
So, naturally frustrated, Frank requested that I create a sudo rule so that he can run the script. So, I open visudo and add this rule for Frank:
frank ALL=(ALL) /home/frank/frank_script.sh
Now when Frank runs the script with sudo, it works:
frank@packtpub1:~$ sudo ./frank_script.sh [sudo] password for frank: This script belongs to Frank the Cat. frank@packtpub1:~$
But since this file is in Frank’s own home directory and he is its owner, he can edit it any way he wants. So, being the sneaky type, he adds the sudo -i line to the end of the script so that it now looks like this:
#!/bin/bash echo "This script belongs to Frank the Cat." sudo -i
Be prepared for a shock as you watch what happens next:
frank@packtpub1:~$ sudo ./frank_script.sh This script belongs to Frank the Cat. root@packtpub1:~#
As you can see, Frank is now logged in as the root user.
What sudo -i does is to log a person in to the root user’s shell, the same way that sudo su - does. If Frank were to do sudo -i from his own command prompt, it would fail because Frank doesn’t have the privilege to do that. But he does have the sudo privilege to run his own shell script. By leaving the shell script in his own home directory, Frank can put root-level commands into it. By running the script with sudo, the root-level commands in the script will execute with root-level privileges.
To remedy this, I’ll use my awesome powers of sudo to move Frank’s script to the /usr/local/sbin directory and change the ownership to the root user so that Frank won’t be able to edit it. And of course, before I do that, I’ll make sure to delete that sudo -i line from it:
donnie@packtpub1:~$ sudo -i root@packtpub1:~# cd /home/frank root@packtpub1:/home/frank# mv frank_script.sh /usr/local/sbin root@packtpub1:/home/frank# chown root: /usr/local/sbin/frank_script.sh root@packtpub1:/home/frank# exit logout donnie@packtpub1:~$
Finally, I’ll open visudo and change his rule to reflect the new location of the script. The new rule looks like this:
frank ALL=(ALL) /usr/local/sbin/frank_script.sh
Frank can still run the script, but he can’t edit it:
frank@packtpub1:~$ sudo frank_script.sh This script belongs to Frank the Cat. frank@packtpub1:~$
Detecting and deleting default user accounts
One challenge of dealing with Internet of Things (IoT) devices is that you don’t do a normal operating system installation on them as you would when setting up a normal server. Instead, you download an image that has the operating system pre-installed, and burn that image to a microSD card. The installed operating system is set up with a default user account, and many times that user is set up with full sudo privileges and isn’t required to enter a sudo password. Let’s take, for example, the Raspex Linux distribution for the Raspberry Pi. (Raspex is built from Ubuntu source code.) On the documentation page of the Raspex download site, we see that the default user is raspex, and the default password for that user is also raspex. We also see that the default password for the root user is root:
So, the default credentials are out there for all the world to see. Obviously, the first thing you want to do when setting up an IoT device is to set up your own user account, give it a good password, and give it sudo privileges. Then get rid of that default account, because leaving it in place, especially if you leave the default password, is just asking for trouble.
But let’s dig deeper. Look in the /etc/password file on Raspex, and you’ll see the default user there:
Then, look in the /etc/sudoers file, and you’ll see this line, which allows the raspex user to do all sudo commands without having to enter a password:
raspex ALL=(ALL) NOPASSWD: ALL
Another thing to watch out for is that some Linux distributions for IoT devices have this rule in a separate file in the /etc/sudoers.d directory, instead of in the main sudoers file. Either way, you’ll want to delete this rule, as well as the default user account, when you set up your IoT device. And of course, you’ll also want to change the root user password, and then lock the root user account.
All righty, I think that that about does it for the sudo topic. Let’s move on to the next topic.