10/25/2018 CSC347H5 Assignment 2
CSC347H5 Assignment 2 Due 11:59PM on Wed. Oct. 31, 2018
Assignment out of 40 marks total
Submission Requirements (2 Marks)
This assignment must be completed in pairs.
Both group members must submit a copy of the assignment on Quercus. You should submit a tar le that contains the following:
1. A PDF of your assignment report, including a cover page with the assignment details and the names of both group members.
2. A directory containing all code and/or scripts that you wrote. Any included les MUST be referenced in the PDF report.
For each question, your report should include both your answer as well as the process by which you determined this answer, i.e., the exact commands you ran, and the output those commands generated. Provide enough detail in your answers to demonstrate that you understand the concepts and commands you are running.
Any code included in the tar archive is for the TA to test, and should therefore be submitted in a format that is easy to run/compile, e.g., with an appropriate directory structure (if needed) and with the required Makeles. Code that you include in your report is for the TA to read, and may therefore be formatted to best explain what you did, e.g., by sectioning the code, highlighting lines of interest and including additional comments, etc. SUBMITTING CODE WITHOUT EXPLANATION WILL RESULT IN SEVERE PENALTY! When in doubt, include an explanation.
Acknowledgement: This assignment is based on exercises originally developed by Daniel McCarney (https://binaryparadox.net/) and Prof. Paul Van Oorschot (https://people.scs.carleton.ca/~paulv/), Carleton University.
Introduction
This assignment will be done on the Assignment 2 VM (../vm_store/csc347_a2.img). Please see Tutorial 4 (./tutorials/t4.shtml) for instructions on how to run the VM.
Please prex your PDF and tar le names with your UTORid: e.g., smithjoh-assignment1.pdf
https://mcs.utm.utoronto.ca/~alacafur/courses/csc347_f18/a2.shtml
1/9
10/25/2018 CSC347H5 Assignment 2
In Part A of this assignment, you will exploit a setuid binary with a race condition in order to gain root privilege on the box. But then what? If you were a real attacker it could be a matter of minutes before the system admin patches the vulnerable program and gives you the boot. In Part B, we will look at how you would install a backdoor to maintain root access even after the vulnerable program is patched, thereby ensuring that you aren’t a one-trick pony!
Part A – Race Conditions (13 Marks)
In this part of the assignment you will learn to exploit a classic time of check versus time of use (ToCToU) vulnerability in order to gain root access on your VM. You should prepare for this part of the assignment by reading the general description of this class of vulnerability. You may read the Wikipedia article on TOCTOU (https://en.wikipedia.org/wiki/Time_of_check_to_time_of_use), the Time- of-Check Time-of-Use Race Conditions section from Chapter 5 (p. 10) of the course textbook (./private/textbook/ch5-long.pdf), and the Safe Temporary File Use (./private/a2/temples_stallings.pdf) section from Computer Security: Principles and Practice by Stallings and Brown.
When answering these questions, please provide a brief narrative explaining the problem and what steps you took for the solution. Provide enough detail to demonstrate that you understand the problem and solution.
a. In /A2/Racing/Slow you will nd a vulnerable application called vuln_slow. In order to ease you into exploiting a ToCToU race condition this example vulnerable application has been written to accept two arguments: a delay in seconds and a message to write to a debug le. In order to ease the exploitation process, vuln_slow checks the permissions on its debug le, sleeps for the provided number of seconds, and then writes to the debug le. A real vulnerable program would not let you determine how long it sleeps between time of check and time of use! This is to allow you to exploit the binary with high success using manually entered commands.
In the /A2/Racing/Slow directory you will also nd a le named root_file that is owned by root and has no write permissions for any other users. Your objective is to exploit vuln_slow into writing a message you provide into root_file .
In order to do this you will need to:
- Use the strace command to learn the location of the debug le that vuln_slow writes its
output to. Inspect the debug le to check that the message you provided to vuln_slow
was appended to the debug le.
- Invoke vuln_slow with a test message and a large delay, 30 to 60 seconds is
recommended.
- While vuln_slow is sleeping, you must delete the log le it checked, and replace it with a
symbolic link to root_file using the ln command.
Provided you’ve followed all three steps successfully, and timed the commands right inside the sleep window, you should nd your message appended to the end of root_file . Remember:
https://mcs.utm.utoronto.ca/~alacafur/courses/csc347_f18/a2.shtml
2/9
10/25/2018 CSC347H5 Assignment 2
Timing is everything! Use a larger sleep time and be prepared to enter the correct commands quickly, and without error.
Describe the exploitation process in detail, including commands invoked and a log of successfully adding a message to root_file . Include an explanation of why the attack works.
b. Now that you’ve successfully exploited a toy race condition vulnerability it’s time to step up the challenge. In /A2/Racing/Fast you will nd the same vulnerable program (this time named
vuln_fast ) modied to no longer accept a sleep time argument. This program uses the same debug le location you found in Part A, Step 1 (you can verify this again using strace if you want).
Since the vulnerability in this program does not occur after a congurable sleep you will only be able to exploit it in a probabilistic fashion by automated means. In order to aid you in this task you have been provided with two skeleton bash scripts to modify: vuln.sh and exploit.sh .
The rst script, vuln.sh , removes the debug le (to clean up from any old exploit attempts) and runs the vulnerable program in a tight loop with a high nice value (to increase your chances of exploitation, see man nice to understand why).
The second script, exploit.sh , removes the debug le, and generates a symbolic link to a specied target in its place. This also happens in a tight loop such that exploit.sh and
vuln.sh when run at the same time are competing to access the debug le (or symlink).
Your objective for this part is to gain access to the root user by exploiting the vuln_fast program to add your username to the root user’s .rhosts le to allow passwordless login using the rsh and rlogin commands.
For an example of how this le would be used in practice, lets say the root user trusts you to log in with superuser (root) privileges without requiring a password. The root user would put your userid into HIS .rhosts le.
But the root user of this machine does not trust you, so we are trying to exploit this behaviour. In order to do this you will need to:
- Edit the vuln.sh script (using nano , or another text editor) to provide it the location of the debug le
- Edit the vuln.sh script to give it the payload string you want written to the target le (see Hint!).
- Edit the exploit.sh script to provide it the location of the debug le
- Edit the exploit.sh script to give it the target le for your attack (See Hint!).
5 Marks
Hint:
This should include a discussion of the execution order, the access() system call in relation to real UIDs and eective UIDs, and a reference to setuid).
https://mcs.utm.utoronto.ca/~alacafur/courses/csc347_f18/a2.shtml
3/9
10/25/2018 CSC347H5 Assignment 2
- Run the vuln.sh script in one terminal
- Run the exploit.sh script in another terminal
- Wait ~a minute and terminate both scripts by pressing Ctrl+C in the respective terminals
- Check if your exploit was successful by running rsh -l root localhost whoami . If it was
successful you should not be asked for a password and will receive the reply root to the whoami command. Remember, if it did not work you may have to repeat steps 5 onward due to the probabilistic nature of race conditions (if it failed, you will receive a permission
denied error).
Once the exploit is successful, you can execute rsh -l root localhost bash to spawn a new superuser privileged shell with full control over the system.
Describe the exploitation process in detail, including commands invoked and a log of you successfully gaining root privilege on the box. Include an explanation of why the attack works.
8 Marks
Hint:
This explanation should reference setuid, how rsh/rhosts is being abused, and why the
nice command is needed this time).
Hint:
The server has been congured to allow the (very insecure) rsh and rlogin commands. The rsh command allows you to run a shell command as a specied user on a remote (or local) machine. It rst checks the specied user’s .rhosts le for a list of hosts and users that can execute commands without a password!
Hmmm… Sounds juicy. If only there was a way to get localhost (since you’re exploiting the local machine) and your username added to the root user’s .rhosts le…
You can learn more about the location and format of this le on the Ubuntu Manuals page (http://manpages.ubuntu.com/manpages/hardy/man5/rhosts.5.html).
To nd the location of root’s home directoy, you can check the passwd le (http://manpages.ubuntu.com/manpages/hardy/man5/passwd.5.html) manual pages.
Part B – Preparing for the Backdoor (5 marks)
Although your exploit from Part A allows you to gain root access to the system whenever you need to, you will only be able to use it for as long as the vulnerability remains present. To ensure that we can continue to have root privileges even after the vulnerable program is xed, we will develop and deploy a rootkit. A garden variety Linux rootkit is generally written as a Loadable Kernel Module or LKM.
https://mcs.utm.utoronto.ca/~alacafur/courses/csc347_f18/a2.shtml
4/9
10/25/2018 CSC347H5 Assignment 2
There is a free guide to programming Linux Kernel Modules (http://tldp.org/LDP/lkmpg/2.6/html/index.html) available online. This guide explains benign kernel module functionality, and you’ll likely want to read (or at least skim) Sections 1, 2, 3, and 8.
Only root can insert and remove modules (using insmod and rmmod respectively). In real life, you would obtain root privileges via an exploit like we did in Part A. But for your convenience, you have been given root access on the VM so technically it is not a requirement that you complete Part A before moving on to Parts B and C.
Hint:
This assignment assumes familiarity with the C programming language. If your C kung-fu is rusty you’ll probably want to Google some reference material. The classic choice is the K&R book (http://books.google.ca/books/about/C_Programming_Language_2E.html? id=kWrfMAAACAAJ&redir_esc=y). The Carleton library has at least one copy. I also enjoy Learn C the Hard Way (http://c.learncodethehardway.org/book/) by Zed Shaw, available free online.
You’ll want to make sure you understand pointers, memory management, arrays, and structures. You’re a kernel programmer now.
Rootkits:
Rootkit LKMs alter the state of the system to tamper with the information provided to processes interacting with the kernel, or to add new functionality convenient for an attacker. A classic way this is done is by hooking system calls. For an idea of what system calls a process invokes, you should revisit your use of the strace command from Part A. The guide to programming Linux Kernel Modules introduces syscall hooking (http://tldp.org/LDP/lkmpg/2.6/html/x978.html) briey.
To hide les from appearing in directory listings for instance, you would nd the syscall that ls used to get lesystem directory entries and hook it. By hooking syscalls related to the lesystem a malicious rootkit (http://en.wikipedia.org/wiki/Sony_BMG_copy_protection_rootkit_scandal) might hide all les with a $sys$ prex, allowing it to stash its own les from the system. Rootkits also frequently serve as backdoors that allow a user to elevate their priviledges, or get a remote shell without logging in. The latter is what we will do for this assignment.
Back to the Future:
You no doubt saw the grave warnings axed to both the getdents() man page (http://www.kernel.org/doc/man-pages/online/pages/man2/getdents.2.html) and the LKM guide section on hooking syscalls (http://tldp.org/LDP/lkmpg/2.6/html/x978.html). Not only are these warnings correct, things are worse than you might imagine. These techniques are dangerous, and often unreliable. No sane engineer would design their device driver in this fashion, we’re hacking in the true denition.
The details in the LKM guide are unfortunately specic to Linux Kernel versions < 2.6.x and a 32bit architecture. We’re running Linux Kernel version 3.2.x on a 64bit architecture. This aects us in two major ways:
https://mcs.utm.utoronto.ca/~alacafur/courses/csc347_f18/a2.shtml
5/9
10/25/2018 CSC347H5 Assignment 2
1. The sys_call_table symbol is no longer exported by the kernel to LKMs. This is to prevent developers from doing stupid things with it. We’re going to have to nd the address manually so that we can do stupid things with it.
2. The page of memory where the sys_call_table lives is now marked read only to prevent things from going wrong. We can’t write a new hook into the table without rst making the page writable, thereby allowing things to go wrong.
Writing a rootkit from scratch is going to be a grueling endeavour. Thankfully your connections in the underground have hooked you up with some super eleet warez (./private/a2). With their C code you should be able to write a respectable piece of kernel malware without losing your mind. Unfortunately your hookup only got you so far. The code’s author must have uploaded it before it was completely nished. It looks like you’ll have to pick up where they left o…
Important Notes:
You’re writing code that runs in kernel space, with full privileges. The slightest mistake in your code is going to lead to legitimately weird things happening including (but not limited to):
All of the binaries on your system segfaulting. Including ssh. Data being lost.
Kernel modules being stuck loaded.
Full kernel panics, leaving the box frozen
Don’t keep anything on your VM you aren’t ready to lose! Keep your code on your own machine and copy it over to compile/test.
You’re going to want to work in very small, veriable steps. Do not attempt to sit down and program the whole assignment. Instead, start with very small steps in mind and progress further only when you get that step working.
Oblig. XKCD (http://xkcd.com/371/)
Hint:
When in doubt, read the source code! The Linux kernel is open source. The kernel installed on your VM is version 3.2. The corresponding source code is available in /usr/src/linux-3.2.0 . Another great online resource is the Linux Cross Reference (https://elixir.bootlin.com/linux/v3.2/source) (please note the ?v=3.2 appended to the URL).
1. Download the rootkit framework code for this assignment (./private/a2) to your VM using wget .
https://mcs.utm.utoronto.ca/~alacafur/courses/csc347_f18/a2.shtml
6/9
10/25/2018 CSC347H5 Assignment 2
2.
3.
4. 5.
6. 7. 8.
Run sudo bash to give yourself a bash shell with root privileges. We’ll pretend that you got this from the race condition in Part A. For most of this assignment you’re going to be switching between a root user and a normal user, so I recommend you keep two windows open (the gurus might want to try using tmux to multiplex multiple terminals over a single SSH session (http://blog.hawkhost.com/2010/06/28/tmux-the-terminal-multiplexer/)).
Find the address of the sys_call_table symbol using the System.map (http://en.wikipedia.org/wiki/System.map)
Edit the insert.sh script to provide the right memory address for the table_addr parameter in the insmod command. It should be equal to the address you found in the System.map.
Conrm you can build the rootkit framework by running make . You can safely ignore the warning about dened but not used variables, as you will be xing that as you complete the assignment.
Conrm you can insert the rootkit module by running ./insert.sh as root. Ensure it was inserted by running lsmod and by checking the syslog.
Conrm you can remove the rootkit module by running ./eject.sh as root. Ensure it was ejected by running lsmod and by checking the syslog.
Finish the rootkit code so that the example open() hook works. Look for the TODO markers. Show a snippet of the syslog output it generates once loaded.
0.5 Marks
0.5 Marks
0.5 Marks
0.5 Marks
2 Marks
Hint:
There is a bit of logging in the incomplete framework. Run tail /var/log/syslog to display the last few lines of the syslog. You may also want to try tail -f /var/log/syslog to interactively tail the syslog le. In interactive mode as new lines are printed to the log your terminal will update immediately. Press Ctrl+C to end the tail command and get back to the shell.
Part C – Backdoor (15 Marks)
For this Part of the assignment you will be creating a backdoor for gaining root privileges on the machine. As long as the LKM remains installed on the system, you will be able to come back at any time and quietly become the root user. From a kernel module, basically anything inside the kernel is fair game to be edited and messed with. In general you just have to nd it, understand it, and subvert it reliably. For your backdoor you’ll be subverting execve() , the system call that is used to invoke executables like commands, daemons, and scripts.
1.
Write a new hook for the execve() syscall using the framework code from Part B. Consult the execve man page (http://linux.die.net/man/2/execve) to learn the details and function signature of execve() . You will need to know which __NR_X dene is used to nd the oset in sys_call_table to hook for execve() (where X will vary syscall to syscall). You might nd /usr/src/linux-3.2.0/include/asm-generic/unistd.h useful in this regard.
1 Mark
5 Marks
The hook should print the name of all les being executed, and the eective UID of the user
https://mcs.utm.utoronto.ca/~alacafur/courses/csc347_f18/a2.shtml
7/9
10/25/2018 CSC347H5 Assignment 2
executing the le to syslog using printk() . Example output:
Jan 28 20:49:17 CSC347-A2 kernel: [81423.749198] Executing /usr/bin/tail Jan 28 20:49:17 CSC347-A2 kernel: [81423.749200] Effective UID 0 Jan 28 20:49:19 CSC347-A2 kernel: [81425.950497] Executing /bin/ls Jan 28 20:49:19 CSC347-A2 kernel: [81425.950499] Effective UID 1000
2.
The current_* macros dened in the /usr/src/linux-3.2.0/include/linux/cred.h include will help you get the information you need to include in your printk() message.
Modify your hook code so that when the eective UID of the user executing an executable is equal to the value of the root_uid parameter, they are given uid/euid 0 (i.e. root privs). The root_uid parameter must be provided via the insmod command in insert.sh like the sys_call_table address, and not hard coded. Note that the root_uid parameter should be set to your user’s UID to get root, not root’s UID. You will need to add this behaviour.
10 Marks
Hint:
The header le /usr/src/linux-3.2.0/include/linux/cred.h and the corresponding code in /usr/src/linux-3.2.0/kernel/cred.c are likely of interest. Specically, the
prepare_kernel_cred() , and commit_creds() functions.
In order to get full marks you must demonstrate the module working. Set the root_uid param in insert.sh equal to your user’s UID, and provide the input/output from:
a. Building the module code
b. Runing whoami as a normal user in one terminal
c. Inserting the module as a root user by running ./insert.sh in a second terminal. d. In your normal user terminal running whoami again and being told you are root.
Example output (from normal user term):
student@csc347-a2:/A2/code/rootkit_framework$ whoami student student@csc347-a2:/A2/code/rootkit_framework$ whoami root
Remember:
Provide enough detail in your report to demonstrate that you understand the problem and solution.
SUBMITTING CODE WITHOUT EXPLANATION WILL RESULT IN SEVERE PENALTY!
https://mcs.utm.utoronto.ca/~alacafur/courses/csc347_f18/a2.shtml
8/9
10/25/2018 CSC347H5 Assignment 2
Part D – Preparing to Add More Features (5 Marks)
Now that you have implemented a backdoor to elevate your privileges, you have secured yourself root access on the system. Even if the system administrator notices and xes the vulnerability in the SetUID program from Part A, you can still rely on your backdoor to elevate your privileges whenever required. However, you now need to worry about hiding your tracks to ensure that the system administrator doesn’t notice any of your activities on the system and thus realize that the system is compromised. You must now do some research and answer the following questions regarding how you would hide your tracks (no actual implementation is required for this part):
- You have a server application that you would like to secretly run on the system, so you need to ensure that the system administrator doesn’t see the corresponding process when they run ps aux . Explain which system call you would need to hook, and provide a brief explanation along with some pseudocode for how your hooked system call would achieve this. It may be helpful to use strace on the ps command, and check man ps for any useful information on how the command works internally (you could also just read the source code for the command, but this is not required or necessary). You must gure out specically which data structure(s) or le(s) your kernel code will need to read and/or modify. You may assume that your kernel module already knows the PID of the process that needs to be hidden. For full marks, explain how you arrived at your answer (e.g., any commands you ran, along with any relevant output).
- You would like to prevent the system administrator from unloading your kernel module with rmmod , in case they notice it running on the system (it is also possible to hide the module
completely from lsmod , but you don’t need to gure that out for the assignment). Explain which system call you would need to hook to achieve this, along with any necessary pseudocode. For full marks, explain how you arrived at your answer (e.g., any commands you ran, along with any relevant output).
Hint:
Make use of man pages and the Linux Cross-Reference, especially for identifying any data structures that you will need to read and/or modify. You may nd the function prototypes for all system calls in include/linux/syscalls.h (https://elixir.bootlin.com/linux/v3.2/source/include/linux/syscalls.h). And this page on man7.org contains links to the man pages of all system calls (http://man7.org/linux/man- pages/man2/syscalls.2.html).
CSC347: Intro. to Information Security (Fall 2018), Furkan Alaca (https://mcs.utm.utoronto.ca/~alacafur), University of Toronto Mississauga
https://mcs.utm.utoronto.ca/~alacafur/courses/csc347_f18/a2.shtml
9/9