Overview
The goal here is for you to gain some hands-on practice. This is a companion guide to our lecture on this topic, and a required myCourses quiz. You’ll have written questions on the exam that resemble these questions.
We’re going to give you a script that emulates a basic permissions system. Importantly, each time we run our script, we’re starting from a completely clean container. This is intentional. Playing around with permissions is infamous for putting the system into a different state than you expect, and can get very confusing. So, for this practice, we’ll always start from a generic Linux operating system, add our users, groups, files, etc. so you can know exactly what state the system is in.
Secondarily, we’re giving you some practice with Docker.
Docker
Messing with permissions is not something you want to do to a regular machine. So for this project, we’re going to be using Docker. Docker is a containerization system that allows you to fake an entire operating system for a single program. We’re going to use a generic Docker container in Linux, and we’ll run a script to get the information we need. We’re going to use docker run to run a shell script, and that will output to our console.
To use Docker, you have a few options:
-
Install locally on your own machine. These days, Docker is becoming a standard software development tool - so you may already have Docker Desktop already installed.
-
Use our hydra servers. These are special servers that are isolated from other shared resources so that we can run docker containers from the command line. Here’s how you use it:
- There are six servers, named
hydra00.cs.rit.eduthroughhydra05.cs.rit.edu. (Yes, these are currently CS servers.) For basic load balancing, use the following servers based on the month you were born:
Birth Month Server Jan-Feb hydra00.cs.rit.eduMar-Apr hydra01.cs.rit.eduMay-Jun hydra02.cs.rit.eduJul-Aug hydra03.cs.rit.eduSep-Oct hydra04.cs.rit.eduNov-Dec hydra05.cs.rit.edu- SSH into your hydra server using your RIT username and password.
- Important Hydra itself runs Linux, however, you don’t have permissions to do what we’ll do in this project. That’s why we’re running our scripts inside a Docker container.
- When you SSH in, you’ll be able to do your
docker runcommands as you wish. - You’ll be editing a script on Hydra. You can use
vimornanoto get this done. Or, you can set up your local VS Code to connect to hydra using its Remote Explorer (your instructor may demo this).
- There are six servers, named
Note: we will not be able to run Docker from the SE lab machines.
Script Copypasta
Copy and paste the following script into a file called perms.sh.
Note about line endings. If you copy this from a Windows machine directly into an editor like Notepad, you might get errors about non-ASCII characters and other cryptic errors. Coding editors like (e.g. VS Code) will auto-detect the line endings and fix this for you. Alternatively, you can run dos2unix perms.sh on Hydra convert the line endings.
echo "\n--- CREATE USERS ---"
adduser paul --shell /bin/bash --disabled-password --gecos ""
adduser leto --shell /bin/bash --disabled-password --gecos ""
adduser vlad --shell /bin/bash --disabled-password --gecos ""
echo "\n--- CREATE GROUPS ---"
addgroup arrakis
adduser paul arrakis
adduser leto arrakis
# NOTE that vlad is NOT in arrakis
echo "\n--- UMASK ---"
umask
echo "\n--- SET UP DIRECTORY ---"
mkdir /dune
chmod 777 /dune # BAD SECURITY. This is for educational purposes.
ls -la /dune
echo "\n--- SET UP FILES ---"
echo "the spice must flow" >> /dune/melange.txt
chown paul /dune/melange.txt
chgrp arrakis /dune/melange.txt
chmod g+w /dune/melange.txt
chmod o-rwx /dune/melange.txt
mkdir /dune/vault
chmod 771 /dune/vault
chown paul /dune/vault
chgrp arrakis /dune/vault
echo "secrets!" >> /dune/vault/secret1234.txt
chmod o=rw /dune/vault/secret1234.txt
mkdir /dune/workspace
chgrp arrakis /dune/workspace
chmod g+s /dune/workspace # setgid
touch arrakis /dune/workspace/shared.txt
cp /usr/bin/whoami /dune
mv /dune/whoami /dune/whoamireally
chown paul /dune/whoamireally
chmod u+s /dune/whoamireally # setuid
echo "\n--- ACT AS PAUL ---"
echo -n "Who am I? "
su paul -c 'whoami'
su paul -c 'umask'
su paul -c 'cat /dune/melange.txt'
su paul -c 'touch /dune/paul_only.txt'
su paul -c 'chgrp arrakis /dune/paul_only.txt'
su paul -c 'chmod g-rwx /dune/paul_only.txt'
su paul -c 'echo -n "Running whoamireally: " ; /dune/whoamireally'
su paul -c 'umask 007 ; touch /dune/arrakis_only.txt'
su paul -c 'ls -l /dune/arrakis*'
echo "\n--- ACT AS LETO ---"
echo -n "Who am I? "
su leto -c 'whoami'
su leto -c 'umask'
su leto -c 'touch /dune/leto.txt'
su leto -c 'cat /dune/melange.txt'
su leto -c 'ls /dune/vault'
su leto -c 'cat /dune/vault/secret1234.txt'
su leto -c 'echo -n "Running whoamireally as leto: " ; /dune/whoamireally'
su leto -c 'cat /dune/arrakis_only.txt'
echo "\n--- ACT AS VLAD ---"
echo -n "Who am I? "
su vlad -c 'whoami'
su vlad -c 'umask'
su vlad -c 'touch /dune/vlad.txt'
su vlad -c 'cat /dune/melange.txt'
su vlad -c 'ls /dune/vault'
su vlad -c 'cat /dune/vault/secret1234.txt'
su vlad -c 'echo -n "Running whoamireally as vlad: " ; /dune/whoamireally'
su vlad -c 'cat /dune/arrakis_only.txt'
echo "\n--- PERMISSIONS ---"
ls -l /dune
ls -la /dune/vault
ls -la /dune/workspace
echo "" # newline at the end of the output
# bash
Running the Script
Your Docker command to run this will look like this. Note that it is all one line.
Compatibility note:
- This will work in Mac and Linux (Hydra).
- This will also work in most Windows Powershell (not CMD), prompts. If it doesn’t, try replacing
$(pwd)with your current directory path (see below).
docker run -it --rm --mount type=bind,source="$(pwd)",target=/root ubuntu:22.04 sh /root/perms.sh
Let’s break down each piece of this, using the documentation
docker runis our command-itessentially means “interactive”, or “show everything to the console stdout and use the shell when reading from stdin”.--rmmeans “delete everything when this run is done”, which makes our run clean and doesn’t fill up our hard drive with past runs.--mount type=bind,source="$(pwd)",target=/rootmeans “my current folder should be mapped to the/rootfolder in the container. This mount command allows us to run our script without having to create a whole new container. Thepwdmeans “print working directory”, so you could also replace this with the full filepath of your current directory (this part is what might vary from OS to OS)ubuntu:22.04is the image we want to run. If your machine doesn’t have it installed, Docker will call out to DockerHub and download the image. You may see downloading feedback the first time your run this. The Linux version we chose is pretty arbitrary - you can use lots of different Linux images for this project.sh /root/perms.sh- means “run the shell script”, which, since we mounted our local folder with--mountit’ll find our file to run.
Commands
Here’s a reference to all of the commands we are using:
lslists file permissions. The-awill show files that start with., including the pseudo-directories of.(“this” directory) and..(parent directory)mkdircreates a new directoryumaskshows the current default permissions mask if no number is given. Invoking with a number (e.g.umask 077) sets the current user’s umask.chmodchanges the permissions on a file or directory. See our lecture on how it works.chgrpchanges the group of a file or directorychownchanges who owns a file or directorycpcopies the filemvmoves the file, in this case effectively renaming the filesuallows you to act as another user, i.e. spoof them. (Note: this is why we need to be in Docker - you need root privileges to usesu). Ordinarily we might usesudo, butsudois no longer installed by default in Ubuntu, but the-coption tosuwill suffice for our purposes.adduserdoes two things:- Creates a new user. Our invocation is pretty non-standard and intended to make scripting easier
- Adds a user to a group
addgroupcreates a new groupechois a standard shell scripting command that prints stuff to the console. Also:- The
-noption omits the newline - We are using the “pipe append” (
>>) to create files and put some contents in them
- The
catmeans “concatenate to stdout”, effectively just “print the contents of the file to the console”;allows us to put two commands into one, simplifying our statementbash(commented out by default). If you want to try these commands interactively in this environment, you can uncomment this. You can also placebashbetween any other lines in this scrtipt and execution will halt there. Typeexitto finish running the script when you’re done.
Our Setup
We have the following users set up:
- Everything in our scenario takes place in the
/dunefolder. paulandletoare members of the grouparrakisvladis not a member of the grouparrakis
Note that, by default, all users have a group that is also named after them. So paul is in a group called paul, and so on. This is the default group that is set when you make a new file or folder.
From there we are doing the following:
- The file
/dune/melange.txtis a file that is group editable and in thearrakisgroup - The directory
/dune/vaultis in thearrakisgroup. It is set up so that anyone can open a file if they know the name, but people outside thearrakisgroup cannot uselsto find the name. We have a file calledsecret1234.txtin it. - The OS-standard binary
whoamiis copied and renamed towhoamireallyand thesetuidpermission is set. Ordinarilywhoamiprints what the current user’s name is, but in this case we’re tampering with a copy of the binary and changing the permissions to take advantage ofsetuid. Thus, when, say,vladrunswhoamireally, it sayspaul.
Default Output
From the copypasta above, the output should look something like this, e.g. your timestamps will look different. The Permission denied errors, however, are expected.
--- CREATE USERS ---
Adding user `paul' ...
Adding new group `paul' (1000) ...
Adding new user `paul' (1000) with group `paul' ...
Creating home directory `/home/paul' ...
Copying files from `/etc/skel' ...
Adding user `leto' ...
Adding new group `leto' (1001) ...
Adding new user `leto' (1001) with group `leto' ...
Creating home directory `/home/leto' ...
Copying files from `/etc/skel' ...
Adding user `vlad' ...
Adding new group `vlad' (1002) ...
Adding new user `vlad' (1002) with group `vlad' ...
Creating home directory `/home/vlad' ...
Copying files from `/etc/skel' ...
--- CREATE GROUPS ---
Adding group `arrakis' (GID 1003) ...
Done.
Adding user `paul' to group `arrakis' ...
Adding user paul to group arrakis
Done.
Adding user `leto' to group `arrakis' ...
Adding user leto to group arrakis
Done.
--- UMASK ---
0022
--- SET UP DIRECTORY ---
total 8
drwxrwxrwx 2 root root 4096 Aug 14 19:44 .
drwxr-xr-x 1 root root 4096 Aug 14 19:44 ..
--- SET UP FILES ---
--- ACT AS PAUL ---
Who am I? paul
0002
the spice must flow
Running whoamireally: paul
-rw-rw---- 1 paul paul 0 Aug 14 19:44 /dune/arrakis_only.txt
--- ACT AS LETO ---
Who am I? leto
0002
the spice must flow
secret1234.txt
secrets!
Running whoamireally as leto: paul
cat: /dune/arrakis_only.txt: Permission denied
--- ACT AS VLAD ---
Who am I? vlad
0002
cat: /dune/melange.txt: Permission denied
ls: cannot open directory '/dune/vault': Permission denied
secrets!
Running whoamireally as vlad: paul
cat: /dune/arrakis_only.txt: Permission denied
--- PERMISSIONS ---
total 44
-rw-rw---- 1 paul paul 0 Aug 14 19:44 arrakis_only.txt
-rw-rw-r-- 1 leto leto 0 Aug 14 19:44 leto.txt
-rw-rw---- 1 paul arrakis 20 Aug 14 19:44 melange.txt
-rw----r-- 1 paul arrakis 0 Aug 14 19:44 paul_only.txt
drwxrwx--x 2 root arrakis 4096 Aug 14 19:44 vault
-rw-rw-r-- 1 vlad vlad 0 Aug 14 19:44 vlad.txt
-rwsr-xr-x 1 paul root 31232 Aug 14 19:44 whoamireally
drwxr-sr-x 2 root arrakis 4096 Aug 14 19:44 workspace
total 12
drwxrwx--x 2 root arrakis 4096 Aug 14 19:44 .
drwxrwxrwx 4 root root 4096 Aug 14 19:44 ..
-rw-r--rw- 1 root root 9 Aug 14 19:44 secret1234.txt
total 8
drwxr-sr-x 2 root arrakis 4096 Aug 14 19:44 .
drwxrwxrwx 4 root root 4096 Aug 14 19:44 ..
-rw-r--r-- 1 root arrakis 0 Aug 14 19:44 shared.txt
This is now YOUR script
At this point, we’re giving you a toolbox and we’re asking you to explore and answer questions. We’ve demonstrated much of what we lectured on, and now it’s your turn to mess around in the sandbox.
You will undoubtedly have to edit this script and experiment on your own to answer these questions. You won’t be able to answer all of the questions by just studying the output - experiment!
Questions
The following questions are on myCourses, but are repeated here for convenience. All of these assume the system is in the state left by the above script.
Making vault personal
Which of the following chmod commands should be used to make the vault readable, searchable, and writeable only to paul and not anyone else (arrakis or not)?.
chmod 000chmod 777chmod 711chmod 700chmod 600
Why can Vlad see the secret?
Why can vlad read the contents of the file in /dune/vault/secret1234.txt?
Choose one:
- Because the
/dunedirectory is777 - Because Docker runs as root
- Because
/dunehas executable permissions on non-arrakisusers - Because
/dunehas read permissions for all users
Hide the secret
Suppose paul wants to change the permissions on only the file secret1234.txt so that anyone outside of arrakis could not open it - even if they knew the name of the file (but paul and leto could still access it since they are in arrakis). What chmod command should be used?
chmod ug=rw /dune/vault/secret1234.txtchmod o-r /dune/vault/secret1234.txtchmod a-r /dune/vault/secret1234.txt
For these permissions, what is the octal notation?
-rw--w----
Why the group?
Check the group ownership of /dune/vault/secret1234.txt and /dune/workspace/shared.txt. Why is shared.txt in the arrakis group and secret1234.txt not?
Choose one.
workspaceuses the sticky bitworkspaceuses setgid and is owned by thearrakisgroup.shared.txtuses setuid- We used
touchand notechoto create the file workspaceis owned byarrakisandvaultis not.- The
umaskis set to have permissive group permissions
Why no execute?
What would happen if we tried to execute melange.txt with su paul -c './melange.txt', and why?
- The code runs, because umask is
0022, but it’s not valid shell syntax so it fails - The code runs and nothing happens because umask is
0002forpaul - The code does not run because files are never created with execute permissions from umask, and we never gave execute permissions
- The code does not run because the directory also has execute permissions
- The code does run because
chmod 777 /dunewas run at the beginning.
Copying whoamireally?
Suppose vlad makes a copy of whoamireally into /dune and gives it read and execute permissions for non-group members. Then, paul attempts to execute it. What happens?
- The output is
paul - The output is
leto - The output is
vlad - The execution fails
Permission for standard tools
Changing passwords in Linux requires you to run passwd, which is located in /bin/passwd. You can only change your own password, however. Passwords are stored in the root-only file /etc/shadow, which means you would need to temporarily act as root to change your own password. But… you don’t need root access to change your own password. How does Linux accomplish this?
- The
/bin/passwdhas setuid and is owned byroot - The
/bin/passwdhas setgid and is in therootgroup - The
/etc/shadowand/bin/passwordare both owned by root - The
/bin/passwdis owned byroot, and when you execute a program, the owner becomes the acting user - Nobody knows, only Linus Torvalds knows this secret.