Overview
In this lab we will:
- Play around with file permissions and umask settings in order to confirm we understand how they work
- Do some setuid programming, temporarily dropping privileges, raising them again and finally dropping them permanently
- Launch a shell from a setuid program and examine whether the shell inherits elevated privileges
- Examine what can happen if we leave file descriptors open across an exec
A. Unix file permissions
The following shell commands may be of use to you in carrying out the operations below (look them up in the man pages if you do not know what they do):
- cd
- chmod
- echo
- id
- ln
- ls
- mkdir
- ps -To command,ruid,euid,suid
- ps -u root -o command,ruid,euid,suid
- rm
- stat
- touch
- umask
Use the above commands to help you answer the following questions:
- What is your user ID?
- To what groups do you belong?
- Create a directory, let's call it p for permissions. Look at the permissions on p, what do they mean?
- Change into p, create a file called fred and put some text in it
- Look at the permissions on fred, what do they mean?
- What is fred's inode number? How many links to the file fred exist?
- Create a hard link to fred, what is its inode number? How many links are there now to the file fred? Can you distinguish between fred and the link to it?
- Create a symbolic/soft link to fred, what is its inode number? How many links are there now to the file fred?
- Can you create a hard link to a directory? Can you create a symbolic link to a directory? Why the difference?
- What is the difference between the last modified and the last changed time for fred?
- Change the permissions on the p directory so you can no longer list its contents, verify this is so but also verify that you can still open fred
- Do you need write permission on a file to delete it? What permissions do you need to delete a file?
- Change the permissions on the p directory so you can no longer delete any files from it and verify this is the case irrespective of the permissions on its contents
- Is the sticky bit set on /tmp? Is passwd really setuid root?
- Check your umask setting, what does its current setting mean when it comes to creating files?
- Set your umask to zero and create a new file called mary. Compare the permissions on mary to the ones on fred when first created. Why the difference?
- Determine the real, saved and effective user IDs of the bash shell you are currently running
- List the processes currently running on your machine with an effective user ID of zero
B. Setuid programming
To do any meaningful setuid programming we need to work with files that are not owned by us and that have their setuid bit turned on. That presents us with a problem since we need root privileges to change file ownership. We cannot give out root privileges on lab machines. So what can we do?
Well, you'll find /usr/local/bin/chruth may help. Look at its permissions and verify that it is a setuid root program. (If you find any vulnerabilities in it, let me know!) The program takes a file as its single input parameter. If the file is an executable, chruth will change its owner to ruth and turn on its setuid bit. (You are doing setuid ruth rather than setuid root programming!) If the file is not an executable, chruth will change its owner to ruth and give only ruth read permission on the file.
To start off create a directory under /tmp where you will do the exercise. You must carry out all setuid programming in a directory off /tmp or the exercises will not work! Next create a file called suidruth.c which does nothing (i.e. its main is empty). Now we can make our program setuid ruth by running chruth against it.
$ gcc -o suidruth suidruth.c
$ chruth suidruth
$ ls -l suidruth
-rwsrwxrwx 1 ruth mse 8588 2008-10-20 13:39 suidruth
Each time you build a new version of suidruth you will have to run chruth against it in order to test it. Sorry!
Now by following the steps outlined below we can practise some setuid programming inside setuidruth.c. If you are unsure on how to carry out any of these steps then look at your setuid lecture notes and the man pages for the various setuid system calls.
If the man pages have not been installed on the machines in the lab you should find them on the web. Verify each setuid call works before proceeding to the next, do this by running your program and having it print out the three user IDs along the way.
- Add code which temporarily drops privileges
- Add code which then raises privileges again
- Add code which then permanently drops privileges
- Add code which attempts to raise privileges once more and verify it fails
- Between each step be sure to print out the current real, effective and saved user IDs: you may use getresuid for this purpose
- Try to achieve the same effects without calling setresuid (it is not available on some Unix variants e.g. Solaris)
- Make sure you understand why user IDs are changing and any effects of such changes
When finished, running your program you should see something like the following:
$ ./suidruth
Real uid: 100 # This is your user ID
Effective uid: 13753 # This is ruth's user ID
Saved uid: 13753
Hit return to continue
Real uid: 100
Effective uid: 100
Saved uid: 13753
Hit return to continue
Real uid: 100
Effective uid: 13753
Saved uid: 13753
Hit return to continue
Real uid: 100
Effective uid: 100
Saved uid: 100
C. Launching a bash shell from a setuid program
Now write a setuid ruth program which exec's a bash shell. Since privileges are carried across an exec your bash shell should run with elevated privileges (in this case as ruth). Typing whoami at the prompt will tell you whether or not this is the case.
- Does the shell run as ruth?
- Why not? (You may have to do a little research on the web to answer that question.) Can you fix it so your new bash shell does in fact run as ruth?
D. File descriptors, setuid and exec
Create a new file called readme and put a few lines of text inside it. Use chruth to give only ruth read permission on the file. Write a setuid ruth program called suidopen which opens the readme (before you make it setuid verify that, when you run it, it fails citing a permission denied error on trying to open the readme file).
- Keep a note of the file descriptor that corresponds to the open file (should be 3 since 0, 1, 2 are occupied)
- Write another program (not setuid) which opens file descriptor 3 (fdopen is your friend here) and reads and displays its contents
- Now add code to your setuid program which, before closing the file descriptor, exec's this reader program
- Your reader program should display the contents of the file
- What does this tell you about privileges, file descriptors, exec?
You should see something like the following:
$ echo "This is a secret" > readme # Create the readme file
$ chruth readme
$ gcc -o suidopen suidopen.c
$ chruth suidopen
$ gcc -o reader reader.c
$ ls -l
-rwxr-xr-x 1 dobrien users 9224 2008-10-20 16:08 reader
-rw--w--w- 1 ruth mse 46 2008-10-20 12:10 readme
-rwsrwxrwx 1 ruth mse 9250 2008-10-20 16:08 suidopen
$ ./suidopen
This is a secret