Holiday Hack Challenge 2023 Report Cody Travis <cwtravis@gmail.com>
Top

The Captain's Comms

Difficulty:

Description:

Speak with Chimney Scissorsticks on Steampunk Island about the interesting things the captain is hearing on his new Software Defined Radio. You'll need to assume the GeeseIslandsSuperChiefCommunicationsOfficer role.


Solution

Solution

The Captain's Comms challenge is a fun one that will teach you about Software Defined Radio without actually having to know much about it going in. It will definitely, however, teach you about JWT's. I have talked about JWT's in other challenges in this years Holiday Hack, such as Elf Hunt.

This is the first one where we must actually forge a signed JWT using a private key.


Radio Shack

Radio Shack

The Captain's radio shack (lol) is located near the south eastern side of Brass Bouy Port on Steampunk Island. It is near Chimney Scissorsticks.

The Captain's Radio Shack

When you first enter the shack you get some background information about it.

Captain's Comms: Background

The goal here is to elevate our privileges until we can transmit over the radio, and then thwart the bad guys by sending them a message with a certain time and date on a particular frequency to trick them into arriving four hours early.

But how does the app know which permissions we have?

I inspected the traffic with the in BURP http proxy:

  </>
HTTP
Set-Cookie: justWatchThisRole=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJISEMgMjAyMyBDYXB0YWluJ3MgQ29tbXMiLCJpYXQiOjE2OTk0ODU3OTUuMzQwMzMyNywiZXhwIjoxODA5OTM3Mzk1LjM0MDMzMjcsImF1ZCI6IkhvbGlkYXkgSGFjayAyMDIzIiwicm9sZSI6InJhZGlvVXNlciJ9.BGxJLMZw-FHI9NRl1xt_f25EEnFcAYYu173iqf-6dgoa_X3V7SAe8scBbARyusKq2kEbL2VJ3T6e7rAVxy5Eflr2XFMM5M-Wk6Hqq1lPvkYPfL5aaJaOar3YFZNhe_0xXQ__k__oSKN1yjxZJ1WvbGuJ0noHMm_qhSXomv4_9fuqBUg1t1PmYlRFN3fNIXh3K6JEi5CvNmDWwYUqhStwQ29SM5zaeLHJzmQ1Ey0T1GG-CsQo9XnjIgXtf9x6dAC00LYXe1AMly4xJM9DfcZY_KjfP-viyI7WYL0IJ_UOtIMMN0u-XO8Q_F3VO0NyRIhZPfmALOM2Liyqn6qYTjLnkg;
Initial JWT in Cookie

A quick refresher on JWT. JWT or JSON Web Tokens are a way of storing state data between two parties, typically used as a cookie to store cryptographically signed data client side. This data can be verified server side, so the server knows it has not been tampered with. A JWT comes in 3 parts separated by a period. A header, a body, and a signature. The values are base64 encoded. The header contains information about the crypto algorithm used to sign the token. The body contains the data you wish to store, and the signature is a hash generated against the header and body. If the server side signature matches the client side one, you know it hasn't been tampered with. Find out more info about JWT here:

https://jwt.io/introduction

Decoding this JWT:

  </>
JWT
{
  "alg": "RS256",
  "typ": "JWT"
}.{
  "iss": "HHC 2023 Captain's Comms",
  "iat": 1699485795.3403327,
  "exp": 1809937395.3403327,
  "aud": "Holiday Hack 2023",
  "role": "radioUser"
}.<signtature>
Initial JWT Decoded

Decoding this JWT shows the algorithm used to sign it: RS256. RS256 is an asymmetric algorithm that uses a public key for verification and a private key for signing. This algorithm allows for the public key to be known and verified by all, but JWT cannot be forged due to the private key being required for signing.

The body tells us our initial role: radioUser

If we look around the shack we may be able to find clues to elevate our privileges.


Clickable Areas

Clickable Areas

Different areas around the shack are clickable and allow use to read notes or journal entries. I will highlight the areas that are important to click:

Captain's Comms: Clickable Areas

The speaker is simple, it just mutes or unmutes the audio from The Captain's Comms.

The SDR waterfall display allows you to focus on and decode (depending on your permission level) different frequencies being picked up by the SDR antenna. The transmitter allows you to broadcast your own message over the radio (must have permission).

If you attempt a task that you do not have permission to do you will be presented with an error message.

The next step is to read all of the available information. Click all of the areas and read the notes presented to you. Starting with the manual vol 1 and vol 2 and the appendix.

2. Manuals - Manual Vol 1

2. Manuals - Manual Vol 2

2. Manuals - Manual Appendix A

4. ChatNPT ToDo List

5. Captain's ToDo List

6. Just Watch This - Owner's Card

According to the Just Watch This - Owner's Card, the radio monitor token file (rMonitor.tok) location is revealed to be:

https://captainscomms.com/jwtDefault/rMonitor.tok

If you attempt to download the token without an Authorization Token set, you will get an error. You must set your radioUser JWT as a Bearer Token Authorization header and the file will be returned successfully. I used BURP http proxy to send the request using the BURP Repeater:

rMoninotr.tok

The body of the rMonitor.tok JWT decoded shows that the role associate with this token is "radioMonitor".

  </>
JWT
{
  "iss": "HHC 2023 Captain's Comms",
  "iat": 1699485795.3403327,
  "exp": 1809937395.3403327,
  "aud": "Holiday Hack 2023",
  "role": "radioMonitor"
}
radioMonitor JWT Body Decoded

We can use this radioMonitor token to view the SDR waterfall diagram. To change roles, you can copy the radioMonitor JWT go change the cookies in your browser. For instance, in Chrome, press F12 to show Developer Tools. Then click Application > Storage > Cookies > https://captainscomms.com. Now double click the cookie "justWatchThisRole" and paste the new JWT token in the Value field for it. Now when you click the SDR screen it should show you the waterfall diagram.

SDR Waterfall

Now that we can view the SDR waterfall, I tried to click the peaks in the diagram, but got an error on each saying there is nothing to decode. Then I recalled in the "Just Watch This Appendix A - Decoder Index", it says "With the SDR window open, simply click on a signal peak while using the radioDecoder ROLE token in order to hear and decode a signal." We have to have the radioDecoder role to decode any of the data from the SDR.

I found the radioDecoder token by changing the filename of the radioMonitor token to reflect word Decoder. Here is the URL:

https://captainscomms.com/jwtDefault/rDecoder.tok

Remember to update the Bearer token to reflect the radioMonitor role to get the radioDecoder JWT.

radioDecoder JWT

  </>
JWT
{
  "iss": "HHC 2023 Captain's Comms",
  "iat": 1699485795.3403327,
  "exp": 1809937395.3403327,
  "aud": "Holiday Hack 2023",
  "role": "radioDecoder"
}
radioDecoder JWT Body Decoded

Now set the "justWatchThisRole" cookie in your browswer to the radioDecoder JWT just as you did with radioMonitor. Now when you click the SDR window, you can click the peaks to view the decoded signals.

There are three peaks to decode. From left to right, its a morse code message, a "numbers station" message, and a radio Fax.

Morse Code Message

The morse code message is from the pirates. It says "SILLY CAPTAIN! WE FOUND HIS FANCY RADIO PRIVATE KEY IN A FOLDER CALLED TH3CAPSPR1V4T3F0LD3R". If we can find the private key we can forge any JWT we want! Keep that in mind.

Numbers Station Message

The numbers station prints out things that looks like dates and times... Dec 24th at 16:00?

Radio Fax Message

The radio fax prints out a frequency. This could be the frequency we need to send the decieving message to the pirates changing their "go" time. We will need to assume the role of "GeeseIslandsSuperChiefCommunicationsOfficer" according to the objective description. The Captain's Journal found after completing Elf Hunt on Pixel Island also mentions the role "GeeseIslandsSuperChiefCommunicationsOfficer".

We can change our role to "GeeseIslandsSuperChiefCommunicationsOfficer" if we can locate the private key. Since the pirates said they found the private key in a folder called "TH3CAPSPR1V4T3F0LD3R". We also know from the ChatNPT ToDo list that the public key was placed in the "keys" directory and the public key is named "capsPubKey.key"

Private Key Hint

I started exploring different URL's to look for the private key. I made sure that my Bearer Authorization token reflected the roleDecoder role. I guessed the file name of the key would be "capsPrivKey.key" based on the public key name. I also guessed the path based on the hints. We know the Just Watch This radio system was installed to the jwtDefault directory, and that the Captain created the "keys" directory to hold the public key, and the pirates found the directory "TH3CAPSPR1V4T3F0LD3R". Putting all these together lead me to the URL:

https://captainscomms.com/jwtDefault/keys/TH3CAPSPR1V4T3F0LD3R/capsPrivKey.key

Private Key Found!

It worked! I saved the private key to a file. I already knew how to generate a JWT using python so I wrote a script to do it.

  </>
Python
import jwt

payload = {
    "iss": "HHC 2023 Captain's Comms",
    "iat": 1699485795.3403327,
    "exp": 1809937395.3403327,
    "aud": "Holiday Hack 2023",
    "role": "GeeseIslandsSuperChiefCommunicationsOfficer"
}

private_key_bytes = b""
public_key_bytes = b""

with open("capsPrivKey.key", "rb") as f:
    private_key_bytes = f.read()
    
with open("capsPubKey.key", "rb") as f:
    public_key_bytes = f.read()
    
encoded = jwt.encode(payload, private_key_bytes, algorithm="RS256")
print(encoded)
jwt_forge.py

That code includes reading the public key in case anyone wants to verify the JWT.

  </>
JWT
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJISEMgMjAyMyBDYXB0YWluJ3MgQ29tbXMiLCJpYXQiOjE2OTk0ODU3OTUuMzQwMzMyNywiZXhwIjoxODA5OTM3Mzk1LjM0MDMzMjcsImF1ZCI6IkhvbGlkYXkgSGFjayAyMDIzIiwicm9sZSI6IkdlZXNlSXNsYW5kc1N1cGVyQ2hpZWZDb21tdW5pY2F0aW9uc09mZmljZXIifQ.N-8MdT6yPFge7zERpm4VdLdVLMyYcY_Wza1TADoGKK5_85Y5ua59z2Ke0TTyQPa14Z7_Su5CpHZMoxThIEHUWqMzZ8MceUmNGzzIsML7iFQElSsLmBMytHcm9-qzL0Bqb5MeqoHZYTxN0vYG7WaGihYDTB7OxkoO_r4uPSQC8swFJjfazecCqIvl4T5i08p5Ur180GxgEaB-o4fpg_OgReD91ThJXPt7wZd9xMoQjSuPqTPiYrP5o-aaQMcNhSkMix_RX1UGrU-2sBlL01FxI7SjxPYu4eQbACvuK6G2wyuvaQIclGB2Qh3P7rAOTpksZSex9RjtKOiLMCafTyfFng
GeeseIslandsSuperChiefCommunicationsOfficer JWT

The output is a forged GeeseIslandsSuperChiefCommunicationsOfficer token. Update your cookies as before to reflect the new role.

Click the Transmitter and enter the following values from the decoded signals. Remember that we are trying to alter the Go-Time four hours earlier. So 1600 hours becomes 1200 hours.

Frequency Go-Date Go-Time
10426 1224 1200

Transmitter

Click the green button and your challenge will be complete!

Success