Category
Web
Chall Author
jotone
Stats
Total Solves: 14/15 Teams
Description
I've managed to infiltrate their network, but I wasn't able to hack their authentication system. Maybe you can help me out?
Preface
First of I'd just like to say that this CTF was an awesome experience. Meeting new people, locking in on the ctf and just the overall vibe was amazing, thank you SNHT for having me.
During the CTF I had a solution around a few hours in but due to a small oversight by me it had to take an extra few ._.
First look at the website
I opened an instance and was greeted with a simple login page:

Registering a user we get this nice little profile viewer:

Trying to view the flag we get this error:

As we can see we are able to change our profile picture to whatever URL we choose, and I am assuming it will just fetch it from that url.
My first instinct was to try using local ips and webhooks to see if the website had any checks:

Safe to assume it worked, probably just the wrong port used in this case. Oh yeah remember the word "sloop", it will become important later.
Well not much to do now, let's take a look at the pcaps!
💯Pcaps💯 >>>>> Source Code
Instead of getting source code for this challenge we got ourselves 2 pcap files, one from the client and one from the backend:

I mainly analyzed the server side pcap as it had the "logic" behind how the website worked
From the pcap I got a rough idea of how the website worked, these are the parts i put the most weight to:
# microrealm
- Backend has a bunch of microservices that speak with each other.
## Services:
### wayfinder
- overall stuff - Works like a list of pointers to where all the microservices are located.
Only does this for buccaneer and treasure.
- register - Registers a new service with args: type, address and port.
- unregister - Just unregisters the service, needs args: type, address and port.
- get-service - Gets the ip and port of the specified service type.
### buccaneer
- overall stuff - Handles the login and auth stuff.
- verify-token - Verifies a JWT token.
- register - Registers users.
- login - Logs in users and gives a JWT token.
### treasure
- get-flag - If the user is admin they get the flag.
### sloop
- set-user-photo - Sets the user photo with a url.
- get-user-photo - Gets the url of a user's photo.
- other random shit that I didn't look into :D
### 172.20.0.3
- Im gonna be honest here, I have no clue what this service does lmao.
That was a lot, time to exploit!
Backend Final Boss
From the pcap we got out a lot of info about how the backend behaves, the most interesting being the wayfinder.
For example, let's say we (the user) go to get-flag, how would the backend handle this?
1. Firstly the frontend sends a request to the backend.
2. Then sloop handles this and sends it accordingly to treasure, but where exactly is treasure?
3. To find the ip and port of the treasure service sloop sends a request to wayfinder like this: http://wayfinder:8080/get-service?service_type=treasure
4. Wayfinder returns: {"service_type":"treasure","ip":"172.19.0.4","port":8080} to sloop which then sends the request to treasure.
5. Treasure checks the JWT to see if the user is admin. To check this it sends it to buccaneer. But it doesn't know where buccaneer is, so it has to do the same process again with wayfinder.
6. Finally treasure can check the admin status with buccaneer with this request: http://172.19.0.3:8080/verify-token?token=eyJhbGciOblahblahblahjwttoken
7. Buccaneer returns {"id":6130241,"username":"macedonga","password_hash":"2dc25392538918c96bcbca9e6d24eb4191953d716828162197aeade9be6db18c","is_admin":false} to treasure which then doesn't send the flag.
This is why I loved the pcap concept, it makes you semi-reverse engineer the logic of the backend.
Wayfinder v0.1
Recall how we were able to
We can try to imitate how the backend and wayfinder normally communicate, lets try getting the ip for the treasure service:


Decoding the base64 encoded image we get this:

BINGO!!
Now that we have the ip and port for both treasure and buccaneer we can just access them right and get the flag?
Well, we can only get the flag if we are admin. We cannot bypass this check even if treasure contains the flag.
Wayfinder v0.2
During the CTF I got stuck here for a bit, so i decided to reread the pcap file.
Lo and behold the answer was right in front of my eyes:


If we can interact with wayfinder AND regsiter/unregister services; can we not just make ourselves into treasure?
If we unregister buccaneer and then reregister buccaneer with a different ip and port that for example, we control. Then we can control exactly what happens.
Remind me again, what does buccaneer do?
6. Finally treasure can check the admin status with buccaneer with this request: http://172.19.0.3:8080/verify-token?token=eyJhbGciOblahblahblahjwttoken
7. Buccaneer returns {"id":6130241,"username":"macedonga","password_hash":"2dc25392538918c96bcbca9e6d24eb4191953d716828162197aeade9be6db18c","is_admin":false} to treasure which then doesn't send the flag.
hehe 67
If we become bucanner and instead of actually checking the JWT treasure gives us, we just return one that rets "is_admin":true?
Proxy time
Then all we need to do is create a little flask app that does the same stuff as buccaneer but instead of checking anything we return is_admin=true.
import flask
import jwt
app = flask.Flask(__name__)
@app.route("/verify-token")
def verify_token():
token = flask.request.args.get("token", "")
decoded = jwt.decode(token, options={"verify_signature": False})
decoded["is_admin"] = True
return flask.jsonify(decoded)
@app.route("/login")
def login():
return flask.jsonify({"token": ""})
if __name__ == "__main__":
app.run(host="0.0.0.0", port=1234)
Registering our ip:1234 (ngrok ftw btw) and then unregistering the old buccaneer we geeeeet:
Flag
snakeCTF{1ns1d3_the_micr0re4lm_03f9372d016c1799}
Afterwords
Really cool way of doing a web challenge with all the microservices and especially using pcaps instead of source code.
Also credit to LiamoOo for the solve script, goat