Bypassing Configurations: setuid, ssh execution, job control

Welcome back to my 9th iteration of this blog series. In this series, we’re growing our cybersecurity knowledge starting from the very basics using the overthewire.org challenges as a guide.
First, I’d like to thank everyone for their feedback, I’ll do my best to implement it and as always, more feedback is always welcome. Now let’s start!
Security and convenience don’t usually play together well. As things become more convenient, they also become less secure and vice versa. Convenience is inherently less secure because, well, it’s convenient to access.
In today’s challenges, we’ll take a look at a few ways that bad configurations for the sake of convenience can lead to security gaps. We already have the password for bandit18 from the last time. Let’s log in:

Interesting…As the challenge hint suggested, we’ve been instantly logged out. If we take a look at the permissions for “.bashrc”, we can see that it’s not much of an option to edit it and remove the logout line. Fortunately (for us), ssh lets us add commands to execute as soon as we log in. It’s so fast in fact that these commands get executed before any other configuration. All we have to do is pass our command in quotes and specify what will run it:

It works out to our advantage in this case that we know exactly where the flag is and we can just pass the command to it. We can see that it didn’t let us stay logged in because after our command executes and exits, the configuration file kicks in and logs us out. If we wanted to stay logged in, all we would need to do is run a program that doesn’t terminate until we tell it: an interactive shell (this will come in handy later). We can also pass programs to run bypassing the file path to ssh, something like /bin/dash; this also launches an interactive shell and will not log us out until we terminate dash.
This next part takes us back to permissions. The hint tells us to use the setuid binary present in the home directory of bandit19. Let’s first talk about setuid permissions. The permission bits are arranged in 3 sets of 3 to specify permissions at each level of users. The setuid function lets a user attach their own permissions to that file. At first glance, it sounds like a terrible idea and a useless function to allow in the first place but let’s take a practical example. Say you had access to a machine where you weren’t given a privileged account and you wanted to change your password. Since changing the password uses elevated privileges, you’d have to ask the administrator to do it for you and tell them your old and new password. Besides the obvious privacy issue involved (although root has access to all your files, root is still not “you” and actions still get logged as root), it’s an insanely arduous task to require an individual with elevated privileges for, especially at scale. Enter setuid.
An administrator can instead apply their own setuid to the passwd command and now everyone can change their own password. Since the command still requires the old password as verification, an employee can’t just change another’s password. The security flaw of setuid is when it’s applied to an application or program that isn’t specific enough. Let’s take a look at a great example:

We can identify the file as having setuid permissions by looking at the user’s executable bit: it’s an “s” instead of the normal “x”. The “s” signifies that any user with execute permissions on this file can execute this file as the owner of the file. In this case, the file is owned by bandit20 and has setuid enabled. We also observe that bandit19 group has execut and read permissions. So if we, as bandit19, run the file, it’ll actually run as if bandit20 ran it. Let’s see what it does:

As the name of the file suggests it simply executes the command that follows using bandit20 as a user. We can double-check this:

Running whoami with using the setuid binary shows us as bandit19 but using the file shows us as bandit20. We can now just grab the password for bandit20 from the password archive at /etc/bandit_pass/bandit20:

There it is.
- *EDIT: use the command nc -l -p 54321 < [your path to password file]
- I forgot to add -p initially but it’s necessary to actually make the connection
We’re once again presented with a setuid binary file but it instead creates a server that will give us the password of bandit21 if we give it bandit20’s password. We just have to specify an unused port so let’s give it a shot:

The program isn’t connecting because there’s nothing to connect to. We need to first set up a server that pushes bandit20’s password which we can using nc. First, we have to create a file to “broadcast” on the port of our choice so we’ll create a file with the password in it and then broadcast that:

Well, we’re stuck. We created the server but now it’s just listening and we can’t put any more commands. Fortunately, Linux has a function to create multiple sessions, screens, and even “minimize” running programs. We’ll use the job control function since it serves our current function well without too many complications.
Generally, when running programs in CLI they persist in the foreground and you can’t use the terminal until the process is terminated one way or another. If you’re using a GUI terminal, most come with the ability to create new tabs or even start new terminal instances that would be more GUI friendly. We can, however, send the running process to the background instead, and that way it can still function without impeding our use of the CLI.
Let’s go over some quick “signals” we can send to a CLI using our keyboard: first we have ctrl + c which functions to “force quit” a current foreground process. We also have ctrl + z which instead pauses a process and gives us control of the terminal. Here’s how each look:

ctrl +c sends an “interrupt signal” to the program. In some cases there might be a cleanup process that runs to close off any running processes so that other programs can use them or cleanup files that would otherwise cause issues or just clutter the system. ctrl + z on the other hand pauses the process but doesn’t close it. We can check paused and running processes by using jobs:

jobs lists for us all the processes running or paused by the terminal command we used to start the process. Keep in mind that a “stopped” process is still in memory and just paused. We can resume a stopped process in two ways: either bring it back to the foreground so we can directly interact with it again or resume in the background so we can still have control of the terminal:

The command for resuming in the foreground is fg and for the background is bg. You also have to specify which process and in this case, the processes are listed with the ID in the square brackets. Do you see a difference between the commands when the process is running in the foreground, stopped, and running in the background? The & serves to run a program directly to the background. Let’s stop the process and run it again but add the & to the end of our command this time, we can bring a process back into the foreground if it’s the background:

Also notice that now that the process is “running” the background, it’s also indicated as such when we use jobs. Also notice how using the & gives us an output of the job number and process ID:

Now that we have our server waiting for a connection from the setuid binary, let’s give it a shot and use the same port we passed to nc:

Awesome! Observe that when a task running in the background ends it reports “Done”. Check jobs again now, what do you see?
We’ve explored a few different Linux functions today that can have a major impact on security. We’ve also explored one way as to how to multitask in CLI. I urge you to explore the other methods such as session which allows for multiple instances or “windows” of CLI running independently.
It’s important to note that machines do as they’re told and it’s really up to us as security professionals to appropriately provision conveniences while still maintaining security best practices. A piece of advice you’ll get a lot is to test the security of your implementations before actually pushing them into a production environment: be creative and think like a hacker.