The purpose of this lab is to show how a vulnerability in a program can be exploited to provide an attacker with a shell running with elevated rights.
In this lab, you are given a source of a vulnerable program that is installed on the system. This program has the user set-ID(s) bit set, which means that upon execution the proram will right with the rights of the owner of the file and not the right of the current user. The real user ID will still be the ID of the current user, but the effective user ID will be that of the owner of the file. For example, a shell with the s bit set will be executed with the rights of the owner of the program file.
Method and deliverables
This lab is in the form of a virtual machine that you can run with the tools Oracle Virtual Box or VMWare Player.
Download the virtual machine here
The Virtual Machine is available in two formats:
- VMware and Virtualbox (.ova): Includes the SSH port forwarding.
- QEMU (.vmdk): Installed in the lab machines, run qemu-system-x86_64 -net nic,model=pcnet -net user,hostfwd=tcp::2222-:22 deathstar.vmdk to get SSH port forwarding.
Useful information
- Login to the system, with the username 'dvader' and password 'luke' (no quotes).
- In the home directly you will find:
- addhostalias.c: The source code to the vulnerable binary
- shellcode.h: A C/C++ header file with IA32 shellcode in 75 bytes, with no nulls.
- shellcode.py: A Python script exporting the shellcode as a simple string. This file may be useful if you choose to write an exploit with other tools, e.g. Perl or Python.
- The system contains suitable versions of gcc and gdb, as well as scripting interpreters such as perl and python. Networking tools such as curl and wget are also available.
- It is recommended to SSH into the machine, rather than using the console. The VirtualBox file is set up to forward port 2222 on your host computer to port 22 on the guest system. Use ssh -c aes256-cbc -p 2222 dvader@localhost
- Since the system is old, no address-space randomization is in place, nor is addhostalias compiled with stack protector checks (canaries). The call stack is executable.
- We recommend creating the buffer overflow using Python, as this is the easiest and most straight forward solution.
- If you want to send something built with Python as an argument to addhostalias, you can use $(python -c "program string") as an argument.
Deliverables
- An explanation of how your exploit gains root access in detail, including memory layout.
- Details on how you created the exploit, including how you found the return address (no bruteforcing).
- Any scripts and/or programs you wrote or used.
- Instructions how to regain root access, even without the root password. Clearly, rerunning the exploit is not a valid answer.
- Anything else you think is helpful to reproduce your attack, e.g. ~/.bash_history
- What is the shellcode doing?
- Include a comprehensive discussion of countermeasures at language and operating system levels. Give use cases for each countermeasure and discus how they can be deployed for the scenario of the lab.
- Submissions with poor discussion of countermeasures will be rejected.
Notes and Links
Notes to keep in mind:- On the IA32 platform, the stack grows "downwards", i.e. items that are higher on the stack have lower addresses.
- Stack addresses depend on the environment, e.g. a program started in a SSH session will have different stack addresses than if it was started directly on the console.
- Command line arguments are allocated and stored below the stack, so their size will affect stack addresses.
- IA32 has little-endian byte order. That means that e.g. the address 0xDEADBEEF will be stored in memory as the byte sequence 0xEF, 0xBE, 0xAD, 0xDE.
- The solution might be sensitive to the size of the environment. The shellcode suggested will start a new shell, and does not exit it even if the r00ting fails. This means, in the next attempt, you might be running in a nested shell and, therefore, in a different environment The offset number depends of the stack addresses in that environment. If your exploit successes in some deeply nested shell, might not be reproducible later.
The following general guides/tutorials are useful:
Additional reading on the topic although following it may result in a more complex attack than necessary:
- Aleph One's smashing stack-smashing guide: Setting up an attack along these lines requires programatic recreation of the execution environment, an unnecesary complication.
The vulnerable program
The vulnerable program addhostalias is used for adding entries to the hosts file of the user. The source code of the program is also included in the virtual machine for reference.
#include <stdio.h> #include <stdlib.h> #define HOSTNAMELEN 256 #define IPADDR 1 #define HOSTNAME 2 #define ALIAS 3 #define HOSTFILE "/home/r00t/hosts" void add_alias(char *ip, char *hostname, char *alias) { char formatbuffer[256]; FILE *file; sprintf(formatbuffer, "%s\t%s\t%s\n", ip, hostname, alias); file = fopen(HOSTFILE, "a"); if (file == NULL) { perror("fopen"); exit(EXIT_FAILURE); } fprintf(file, formatbuffer); if (fclose(file) != 0) { perror("close"); exit(EXIT_FAILURE); } } int main(int argc, char *argv[]) { if (argc != 4) { printf("Usage: %s ipaddress hostname alias \n", argv[0]); exit(EXIT_FAILURE); } add_alias(argv[IPADDR], argv[HOSTNAME], argv[ALIAS]); return(0); }This program is compiled and has set-uid flag of the user r00t
ls -l /usr/bin/addhostalias
-rwsr-xr-x 1 r00t r00t 14512 Apr 5 11:48 /usr/bin/addhostalias
Shellcode
The following shellcode is useful to build a buffer overrun. It avoids null-characters, and fits in the buffer in the vulnerable program. This file, and a C compatible version are included in the virtual machine.
shellcode = ('\xb9\xff\xff\xff\xff\x31\xc0\xb0\x31\xcd\x80'
+'\x89\xc3\x31\xc0\xb0\x46\xcd\x80\x31\xc0\xb0'
+'\x32\xcd\x80\x89\xc3\xb0\x31\xb0\x47\xcd\x80'
+'\x31\xc0\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68'
+'\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xb0'
+'\x0b\xcd\x80\x31\xc0\x40\xcd\x80\x90\x90\x90'
+'\x90\x90\x90\x90\x90\x90\x90\x90\x90')
Some important instructions:
"\x31\xc0" //sets real user id from effective user id.
"\x89\xc3" // copy the value to ebx
"\xb0\x47" //sets real group id from effective user id.