Skip to content

Christmas Island⚓︎

Upon logging into the Holiday Hack Challenge 2023, we find ourselves on a ship in the vast expanse of the ocean! Navigating toward Christmas Island is our next mission, achievable by utilizing the arrow keys on the keyboard or the WASD keys. Positioned in the lower-left corner of the map, the island awaits our arrival. Let the maritime adventure begin!

map

There are three different ports available:

Port of Orientation⚓︎

While exploring Christmas Island, we discover the Port of Orientation. Upon reaching it, a "Dock Now" option is presented to us.

docknow

When we make land, we obtain a new objective on arrival.

Holiday Hack Orientation (Christmas Island)

Talk to Jingle Ringford on Christmas Island and get your bearings at Geese Islands

Holiday Hack Orientation⚓︎

Holiday Hack Orientation (Christmas Island)

Talk to Jingle Ringford on Christmas Island and get your bearings at Geese Islands

The dock featured Jingle Ringford to greet us!

dock

After speaking with Jingle Ringford, I received a fishing pole so I can fish on my boat!

fishingpole

When clicking on my star and going to "Items", we can see it stored there!

fishingpole

Full Island (Zoomed Out)

zoom30

Following further conversation with Jingle Ringford, I received instructions to click on the Cranberry Pi Terminal. This action grants access to the orientation terminal challenge. In the SANS Holiday Hack, interactive terminals are provided for users to click on, initiating challenges directly in the browser.

accessterminal

Upon initiating the challenge, a tmux terminal is launched.

terminalcompletion

Typing answer and pressing ENTER earned us our first achievement!

Achievement

Congratulations! You have completed the Holiday Hack Orientation challenge!

Jingle Ringford

Head back to your boat or click on the anchor icon on the left of the screen to set sail for Frosty's Beach where Santa's waiting for you. I've updated your boat's compass to guide the way. As you sail to each island, talk to the goose of that island to receive a colorful lei festooning the masts on your ship.

Port of Frosty's Beach⚓︎

While exploring Christmas Island, we discover the Port of Frosty's Beach. Upon reaching it, a "Dock Now" option is presented to us.

docknow

When we make land, we obtain more objectives on arrival.

Snowball Fight (Christmas Island)

Visit Christmas Island and talk to Morcel Nougat about this great new game. Team up with another player and show Morcel how to win against Santa!

Linux 101 (Christmas Island)

Visit Ginger Breddie in Santa's Shack on Christmas Island to help him with some basic Linux tasks. It's in the southwest corner of Frosty's Beach.

When we arrive at the dock, we arrive to meet Santa for the first time and the Goose of Christmas Island!

santa

When speaking with Santa, he wants us to have a snowball fight and provides us with our first hint!

Synthesis is the True Ending

The AI revolution has begun. Some of the most prominent and useful tools born from the advent of powerful AI include ChatGPT, PlayHT, Midjourney, Dall-E 3, Bing AI, and Bard, and Grok.

Throughout this years challenge, I used ChatGPT to enhance my code, find vulnerabilities, and even help with report writing! Some of the prompts used are documented.

Moving to the left of the dock, we see the vendor area with sponsors of Google, Microsoft, SANS, Amazon, SWAG store. There is also poster of HackSpaceCon and President's Cup!

sponsors

Full Island (Zoomed Out)

zoom30

Snowball Fight⚓︎

Snowball Fight (Christmas Island)

Visit Christmas Island and talk to Morcel Nougat about this great new game. Team up with another player and show Morcel how to win against Santa!

If we go to the left of Santa, we find Morcel Nougat close to a challenge.

snowball

When speaking with Morcel Nougat, we obtain the following hints:

Consoling iFrames

Have an iframe in your document? Be sure to select the right context before meddling with JavaScript.

Snowball Super Hero

Its easiest to grab a friend play with and beat Santa but tinkering with client-side variables can grant you all kinds of snowball fight super powers. You could even take on Santa and the elves solo!

After spawning the challenge we are presented with the following tutorial:

snowballstart

Analyzing JavaScript⚓︎

To leverage the hints provided, we can use browser developer tools (F12) to interact with an iframe:

  1. Right-click the iframe and choose Inspect, or press CTRL + Shift + i (in Chrome).
  2. Go to the Console tab.
  3. Use the downward arrow to access the JavaScript console for the iframe.
  4. Modify JavaScript variables, allowing adjustments to various aspects of the iframe, including its current URL and URL parameters (window.location.href).

We can locate the main game code in the developer tools, retrieved from the URL: https://hhc23-snowball.holidayhackchallenge.com/room/.

developertools

By examining the JavaScript code, we can pinpoint several valuable variables that can be modified to maximize the benefits in our game.

lines 264-276
var snowballLiveTime = 2500
var snowballDmg = 2
var snowballSpeed = 500
var playersHitBoxSize = [30,30,40,60]
var elfHitBoxSize = [32,32,48,48]
var santaHitBoxSize = [60,60,70,70]
var player_healthbar_offset = {x:0,y:-90}
var myPlayerTint = 0xb3b3ff
var otherPlayerTint = 0xff9980
var santaObject
var santaThrowDelay = 500
var playersVelocity = 200
var gameOverText

We also discover that there is a single-player mode which can be modified by overriding a local storage variable named singlePlayer.

lines 117-128
var singlePlayer = "false"
  function checkAndUpdateSinglePlayer() {
    const localStorageValue = localStorage.getItem('singlePlayer');
    if (localStorageValue === 'true' || localStorageValue === 'false') {
      singlePlayer = String(localStorageValue === 'true');
    }
    const urlParams = new URLSearchParams(window.location.search);
    const urlValue = urlParams.get('singlePlayer');
    if (urlValue === 'true' || urlValue === 'false') {
      singlePlayer = String(urlValue === 'true');
    }
  }
lines 475-476
// jared ... I mean Elf the dwarf joins the fight when in single player mode
if (singlePlayer === 'true') {

Server-Side JavaScript Manipulation⚓︎

We can customize the JavaScript server response by manually intervening through Burp Suite. Intercepting the server response grants the capability to edit the JavaScript content before it is delivered to the browser. This is accomplished by:

This is achieved by doing the following:

  • Uncheck Intercept requests based on the following rules: in the Proxy settings in Burp
  • Check Intercept responses based on the following rules: in the Proxy settings in Burp
  • Uncheck all options in the WebSocket interception rules in the Proxy settings in Burp
  • Specific the URL regex match condition under Response interception rules in the Proxy settings in Burp
regex
https\:\/\/hhc23\-snowball\.holidayhackchallenge\.com\/room\/.*

burpintercept

Manually modify data in the server response using Burp Interceptor.

"singlePlayer":"true"  // Single-player mode, Line 158
var elfThrowDelay = 10000;  // Elf throw speed, Line 244
var snowballDmg = 99999;  // Snowball damage overall, Line 265
var snowballSpeed = 1000;  // Snowball speed overall, Line 266
var santaThrowDelay = 10000;  // Santa throw speed, Line 274
var playersVelocity = 1000;  // Movement speed, Line 275

Server-Side JavaScript Manipulation with mitmproxy⚓︎

We can also automate this by using mitmdump with a Python addon to automate the replacement:

mitm_snowballhero.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""This script is used to intercept and manipulate HTTP server messages using mitmdump.
Usage: reset; sudo mitmdump -s mitm_snowballhero.py --listen-port 9000 --set flow_detail=0
Reference: https://mitmproxy.org/
Holiday Hack 2023 - Snowball Super Hero
"""

# Imports
from mitmproxy import http
from mitmproxy import ctx
import re

PRINT_ALL = False


def replace_str(flow, match_str, replace_val):
    """
    Replace the value of a variable in a JavaScript response.

    Args:
        flow (mitmproxy.http.HTTPFlow): The flow object.
        match_str (str): The string to find.
        replace_val: The replacement value.

    Returns:
        mitmproxy.http.HTTPFlow: The modified flow object.
    """

    # Regex Escape match
    match_str_regex = re.escape(match_str)

    # Comment line of code
    if isinstance(replace_val, str) and replace_val.startswith("//"):
        match_res = re.search(f"({match_str_regex}.*)", flow.response.text)
        if match_res:
            old_line = match_res.group(0)
            new_line = f"//{old_line}"
            flow.response.text = flow.response.text.replace(old_line, new_line)
            ctx.log.info(f"Replacement: '{old_line}' => '{new_line}'")
            return flow

    # Setting variable value
    match_res = re.search(f"(var\s*{match_str_regex}\s*=\s*.*)", flow.response.text)
    if match_res:
        old_line = match_res.group(0)
        if isinstance(replace_val, str):
            new_line = f'var {match_str} = "{replace_val}";'
        else:
            new_line = f"var {match_str} = {replace_val};"
        flow.response.text = flow.response.text.replace(old_line, new_line)
        ctx.log.info(f"Replacement: '{old_line}' => '{new_line}'")
        return flow

    # Refactor line of code
    if isinstance(match_str, str) and isinstance(replace_val, str):
        oldTxt = flow.response.text
        flow.response.text = oldTxt.replace(match_str, replace_val)
        if oldTxt != flow.response.text:
            ctx.log.info(f"Replacement: '{match_str}' => '{replace_val}'")
            return flow

    ctx.log.error(f"No match found for {match_str}")
    return flow


def response(flow: http.HTTPFlow):
    assert flow.response
    PRINT_ALL and ctx.log.info(f"Received response for url:{flow.request.url} and path:{flow.request.path}")
    if (
        flow.request.url.startswith("https://hhc23-snowball.holidayhackchallenge.com/room/")
        and "Content-Type" in flow.response.headers
        and "text/html" in flow.response.headers["Content-Type"].lower()
        and "Multiplayer Snowball Hero" in flow.response.text
    ):
        ctx.log.info(f"Attempting interception for url:{flow.request.url} and path:{flow.request.path}")
        flow = replace_str(flow, '"singlePlayer":"false"', '"singlePlayer":"true"')  # Single-player mode, Line 158
        flow = replace_str(flow, "elfThrowDelay", 10000)  # Elf throw speed, Line 244
        flow = replace_str(flow, "snowballDmg", 99999)  # Snowball damage overall, Line 265
        flow = replace_str(flow, "snowballSpeed", 1000)  # Snowball speed overall, Line 266
        flow = replace_str(flow, "santaThrowDelay", 10000)  # Santa throw speed, Line 274
        flow = replace_str(flow, "playersVelocity", 1000)  # Movement speed, Line 275

To enable SSL trust, add the mitmdump certificate to your browser by visiting http://mitm.it/. We also then need to setup FoxyProxy and point it to the mitmdump on port 9000. We can also point our browser directly to this proxy or combine it with Burp and set the upstream server to port 9000 for the specific host:

upstream

We can see it replaces the server-response successfully. Note, this opens TCP Port 9000 on execution.

mitm_snowballhero.py
reset; sudo mitmdump -s mitm_snowballhero.py --listen-port 9000 --set flow_detail=0
[16:05:15.643] Loading script mitm_snowballhero.py
[16:05:15.648] HTTP(S) proxy listening at *:9000.
[16:05:48.922][192.168.0.10:56032] client connect
[16:05:48.953][192.168.0.10:56032] server connect hhc23-snowball.holidayhackchallenge.com:443 (34.128.147.194:443)
[16:05:55.077] Replacement: '"singlePlayer":"false"' => '"singlePlayer":"true"'
[16:05:55.077] Replacement: 'var elfThrowDelay = 2000' => 'var elfThrowDelay = 10000;'
[16:05:55.078] Replacement: 'var snowballDmg = 2' => 'var snowballDmg = 99999;'
[16:05:55.078] Replacement: 'var snowballSpeed = 500' => 'var snowballSpeed = 1000;'
[16:05:55.078] Replacement: 'var santaThrowDelay = 500' => 'var santaThrowDelay = 10000;'
[16:05:55.079] Replacement: 'var playersVelocity = 200' => 'var playersVelocity = 1000;'

Single-Player Victory⚓︎

In the single-player mode, a companion named 'Elf the Dwarf' joins us for the battle that assists drastically against the elves and Santa!

singleplayer1

After defeating Santa we obtain Victory!

defeat

Morcel Nougat congratulates us and we obtain an achievement!

victory

Achievement

Congratulations! You have completed the Snowball Fight challenge!

Linux 101⚓︎

Linux 101 (Christmas Island)

Visit Ginger Breddie in Santa's Shack on Christmas Island to help him with some basic Linux tasks. It's in the southwest corner of Frosty's Beach.

I went over to Santa's Surf Shack to the far south-west of the island from the Snowball Fight challenge.

surfshack

I found Ginger Breddie inside and close to a challenge.

inside

When we startup the challenge, it spins up a tmux terminal: The North Pole 🎁 Present Maker: All the presents on this system have been stolen by trolls. Capture trolls by following instructions here and 🎁's will appear in the green bar below. Run the command "hintme" to receive a hint.

terminalstart

Type "yes" to begin:

yes

Perform a directory listing of your home directory to find a troll and retrieve a present!

elf@610a770f8ee0:~$ ls -la
total 68
drwxr-xr-x 1 elf  elf   4096 Dec  2 22:19 .
drwxr-xr-x 1 root root  4096 Dec  2 22:19 ..
-rw-r--r-- 1 elf  elf     28 Dec  2 22:19 .bash_history
-rw-r--r-- 1 elf  elf    220 Feb 25  2020 .bash_logout
-rw-r--r-- 1 elf  elf   3105 Nov 20 18:04 .bashrc
-rw-r--r-- 1 elf  elf    807 Feb 25  2020 .profile
-rw-r--r-- 1 elf  elf    168 Nov 20 18:04 HELP
-rw-r--r-- 1 elf  elf     24 Dec  2 22:19 troll_19315479765589239
drwxr-xr-x 1 elf  elf  24576 Dec  2 22:19 workshop

Now find the troll inside the troll.

elf@610a770f8ee0:~$ cat troll_19315479765589239
troll_24187022596776786

Great, now remove the troll in your home directory.

elf@610a770f8ee0:~$ rm troll_19315479765589239

Print the present working directory using a command.

elf@610a770f8ee0:~$ pwd
/home/elf

Good job but it looks like another troll hid itself in your home directory. Find the hidden troll!

elf@610a770f8ee0:~$ ls -la
total 64
drwxr-xr-x 1 elf  elf   4096 Dec 15 03:45 .
drwxr-xr-x 1 root root  4096 Dec  2 22:19 ..
-rw-r--r-- 1 elf  elf     28 Dec  2 22:19 .bash_history
-rw-r--r-- 1 elf  elf    220 Feb 25  2020 .bash_logout
-rw-r--r-- 1 elf  elf   3105 Nov 20 18:04 .bashrc
-rw-r--r-- 1 elf  elf    807 Feb 25  2020 .profile
-rw-r--r-- 1 elf  elf      0 Dec 15 03:45 .troll_5074624024543078
-rw-r--r-- 1 elf  elf    168 Nov 20 18:04 HELP
drwxr-xr-x 1 elf  elf  24576 Dec  2 22:19 workshop

Excellent, now find the troll in your command history.

elf@b0f5e926c755:~$ history | grep troll
    1  echo troll_9394554126440791
    4  cat troll_19315479765589239
    6  rm troll_19315479765589239
    10  history | grep troll

Find the troll in your environment variables.

elf@610a770f8ee0:~$ env | egrep -i troll
SESSNAME=Troll Wrangler
z_TROLL=troll_20249649541603754

Next, head into the workshop.

elf@610a770f8ee0:~$ cd workshop/
elf@610a770f8ee0:~/workshop$

A troll is hiding in one of the workshop toolboxes. Use "grep" while ignoring case to find which toolbox the troll is in.

elf@610a770f8ee0:~/workshop$ egrep -iR troll
toolbox_191.txt:tRoLl.4056180441832623

A troll is blocking the present_engine from starting. Run the present_engine binary to retrieve this troll.

elf@ca1a4211be41:~/workshop$ ./present_engine
bash: ./present_engine: Permission denied
elf@ca1a4211be41:~/workshop$ chmod +x present_engine
elf@ca1a4211be41:~/workshop$ ./present_engine
troll.898906189498077

Trolls have blown the fuses in /home/elf/workshop/electrical. cd into electrical and rename blown_fuse0 to fuse0.

elf@ca1a4211be41:~/workshop$ cd electrical/
elf@ca1a4211be41:~/workshop/electrical$ mv blown_fuse0 fuse0

Now, make a symbolic link (symlink) named fuse1 that points to fuse0

elf@ca1a4211be41:~/workshop/electrical$ ln -fs fuse0 fuse1
elf@e504d279024f:~/workshop/electrical$ ls -la
total 20
drwxr-xr-x 1 elf elf 4096 Dec 15 04:05 .
drwxr-xr-x 1 elf elf 4096 Dec  2 22:19 ..
-rw-r--r-- 1 elf elf  200 Dec  2 22:19 fuse0
lrwxrwxrwx 1 elf elf    5 Dec 15 04:05 fuse1 -> fuse0

Make a copy of fuse1 named fuse2.

elf@ca1a4211be41:~/workshop/electrical$ cp fuse1 fuse2
elf@e504d279024f:~/workshop/electrical$ ls -la
total 24
drwxr-xr-x 1 elf elf 4096 Dec 15 04:05 .
drwxr-xr-x 1 elf elf 4096 Dec  2 22:19 ..
-rw-r--r-- 1 elf elf  200 Dec  2 22:19 fuse0
lrwxrwxrwx 1 elf elf    5 Dec 15 04:05 fuse1 -> fuse0
-rw-r--r-- 1 elf elf  200 Dec 15 04:05 fuse2

We need to make sure trolls don't come back. Add the characters "TROLL_REPELLENT" into the file fuse2.

elf@ca1a4211be41:~/workshop/electrical$ echo 'TROLL_REPELLENT' >> fuse2

Find the troll somewhere in /opt/troll_den.

elf@ca1a4211be41:~/workshop/electrical$ cd /opt/troll_den/

elf@e504d279024f:~/workshop/electrical$ find /opt/troll_den -iname 'troll*'
/opt/troll_den
/opt/troll_den/apps/showcase/src/main/resources/tRoLl.6253159819943018

Find the file somewhere in /opt/troll_den that is owned by the user troll.

elf@e504d279024f:~/workshop/electrical$ find /opt/troll_den/ -user troll
/opt/troll_den/apps/showcase/src/main/resources/template/ajaxErrorContainers/tr0LL_9528909612014411

Find the file created by trolls that is greater than 108 kilobytes and less than 110 kilobytes located somewhere in /opt/troll_den.

elf@e504d279024f:~/workshop/electrical$ find /opt/troll_den/ -size +108k -size -110k
/opt/troll_den/plugins/portlet-mocks/src/test/java/org/apache/t_r_o_l_l_2579728047101724

List running processes to find another troll.

elf@e504d279024f:~/workshop/electrical$ ps aux
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
init           1  0.0  0.0  20112 16508 pts/0    Ss+  04:03   0:00 /usr/bin/python3 /usr/local/bin/tmuxp load ./mysession.yaml
elf        18326  0.2  0.0  31520 26752 pts/2    S+   04:34   0:00 /usr/bin/python3 /14516_troll

The 14516_troll process is listening on a TCP port. Use a command to have the only listening port display to the screen.

elf@e504d279024f:~/workshop/electrical$ netstat -panut | grep 18326
tcp        0      0 0.0.0.0:54321           0.0.0.0:*               LISTEN      18326/python3

The service listening on port 54321 is an HTTP server. Interact with this server to retrieve the last troll.

elf@e504d279024f:~/workshop/electrical$ curl http://localhost:54321
troll.73180338045875

Your final task is to stop the 14516_troll process to collect the remaining presents.

troll.73180338045875elf@e504d279024f:~/workshop/electrical$ kill -9 18326

Type "exit" to close...

exit
Achievement

Congratulations! You have completed the Linux 101 challenge!

Port of Rudolph's Rest⚓︎

While exploring Christmas Island, we discover the Port of Rudolph's Rest. Upon reaching it, a "Dock Now" option is presented to us.

docknow

When we make land, we obtain more objectives on arrival.

Reportinator (Christmas Island)

Noel Boetie used ChatNPT to write a pentest report. Go to Christmas Island and help him clean it up.

Azure 101 (Christmas Island)

Help Sparkle Redberry with some Azure command line skills. Find the elf and the terminal on Christmas Island.

The dock featured the Goose of Christmas Island and Noal Boatie to greet us!

dock

Full Island (Zoomed Out)

zoom30

Reportinator⚓︎

Reportinator (Christmas Island)

Noel Boetie used ChatNPT to write a pentest report. Go to Christmas Island and help him clean it up.

If we go to the middle of the island, we find Noal Boatie close to a challenge.

challenge

When speaking with Noal Boatie, we obtain the following hint:

Reportinator

I know AI sometimes can get specifics wrong unless the prompts are well written. Maybe chatNPT made some mistakes here.

When we startup the challenge, it spins up a Penetration Test Report:

pentestreport

I created a Python script for brute-forcing to unravel this challenge quickly:

reportinator_brute.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""This script attempts to bruteforce the correct reportinator result.
Holiday Hack 2023 - Reportinator
"""

# Imports
from utilities import *
import requests
from itertools import product
from random import shuffle

#########################################
# Main
if __name__ == "__main__":
    url = "https://hhc23-reportinator-dot-holidayhack2023.ue.r.appspot.com:443/check"
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0",
        "Accept": "*/*",
        "Accept-Language": "en-US,en;q=0.5",
        "Accept-Encoding": "gzip, deflate, br",
        "Content-Type": "application/x-www-form-urlencoded",
    }
    cookies = {"ReportinatorCookieYum": "eyJ1c2VyaWQiOiI5YWY0MTIyYS0yNjE1LTQ4MzMtOTY2MS03YzM0MDkxMjRjOTYifQ.ZYUMHw._nqesOfGb1SYX6bSf7K7xxKLl-4"}

    # Generate all combinations and loop
    combinations = list(product([1, 0], repeat=9))
    shuffle(combinations)
    for combo in combinations:
        data = {
            "input-1": combo[0],
            "input-2": combo[1],
            "input-3": combo[2],
            "input-4": combo[3],
            "input-5": combo[4],
            "input-6": combo[5],
            "input-7": combo[6],
            "input-8": combo[7],
            "input-9": combo[8],
        }
        print(f"Attempt: {data}")

        response = requests.post(url, headers=headers, cookies=cookies, data=data)

        if response.status_code != 400 and "Failure" not in response.text:
            print(f"Good Response: {data}, Status: {response.status_code}, Text: {response.text}")
            exit()

    print("DONE!")
output
COMPLETED!
{'input-1': 0, 'input-2': 0, 'input-3': 1, 'input-4': 0, 'input-5': 0, 'input-6': 1, 'input-7': 0, 'input-8': 0, 'input-9': 1}

Findings #3, #6, and #9 are the invalid exaggerated findings in the report:

  • The report on #3 Remote Code Execution via Java Deserialization of Stored Database Objects lacks clarity on the successful attainment of Remote Code Execution and uses an impossibly high TCP port of 88555 from By intercepting HTTP request traffic on 88555/TCP. The actual maximum is 65535. Typically, achieving this involves blind exploitation with multiple gadget chains (e.g., CommonsCollections1-7) and ping-back commands, which was not demonstrated in the report.
  • The report on #6 Stored Cross-Site Scripting Vulnerabilities was invalid as it inaccurately attributes it to the encoding of input/output and sending of an HTTP SEND where there is not such thing as SEND. The actual issue resides in the parsing of unsafe input.
  • The report on #9 Internal IP Address Disclosure was invalid because the Location header is functioning as intended, reflecting the website's location. Knowing an IP address in this context does not qualify as a vulnerability. In addition, the HTTP 7.4.33 request does not make any sense.

Once submitting our review, we get a completion:

Report Validation Complete

Great work! You've successfully navigated through the intricate maze of data, distinguishing the authentic findings from the AI hallucinations. Your diligence in validating the penetration test report is commendable.

Your contributions to ensuring the accuracy and integrity of our cybersecurity efforts are invaluable. The shadows of uncertainty have been dispelled, leaving clarity and truth in their wake. The findings you have authenticated will play a crucial role in fortifying our digital defenses.

We appreciate your expertise and keen analytical skills in this crucial task. You are a true asset to the team. Keep up the excellent work!

Achievement

"Congratulations! You have completed the Reportinator challenge!"

Azure 101⚓︎

Azure 101 (Christmas Island)

Help Sparkle Redberry with some Azure command line skills. Find the elf and the terminal on Christmas Island.

If we go to the far left of the island, we also find Sparkle Redberry close to a challenge and started it up!

challenge

When speaking with Sparkle Redberry, we obtain the following hint:

Azure CLI Reference

The Azure CLI tools come with a builtin help system, but Microsoft also provides this handy cheatsheet.

When we startup the challenge, it spins up a tmux terminal: You may not know this but the Azure cli help messages are very easy to access. First, try typing: $ az help | less

azstartup

elf@3b93c88b5a50:~$ az help | less
Group
    az

Subgroups:
    account                     : Manage Azure subscription information.
    acr                         : Manage private registries with Azure Container Registries.
    ad                          : Manage Azure Active Directory Graph entities needed for Role Based Access Control.
    advisor                     : Manage Azure Advisor.
    aks                         : Manage Azure Kubernetes Services.
    ams               [Preview] : Manage Azure Media Services resources.
    apim              [Preview] : Manage Azure API Management services.
    appconfig         [Preview] : Manage App Configurations.
    appservice                  : Manage App Service plans.
    backup            [Preview] : Manage Azure Backups.
    batch                       : Manage Azure Batch.
    billing                     : Manage Azure Billing.
    bot                         : Manage Microsoft Azure Bot Service.
    cache             [Preview] : Commands to manage CLI objects cached using the `--defer` argument.
    cdn                         : Manage Azure Content Delivery Networks (CDNs).
    cloud                       : Manage registered Azure clouds.
    cognitiveservices           : Manage Azure Cognitive Services accounts.
    consumption       [Preview] : Manage consumption of Azure resources.
    container                   : Manage Azure Container Instances.
    cosmosdb                    : Manage Azure Cosmos DB database accounts.
    deployment                  : Manage Azure Resource Manager deployments at subscription scope.
    deploymentmanager [Preview] : Create and manage rollouts for your service.
    disk                        : Manage Azure Managed Disks.
    disk-encryption-set         : Disk Encryption Set resource.
    dla               [Preview] : Manage Data Lake Analytics accounts, jobs, and catalogs.
    dls               [Preview] : Manage Data Lake Store accounts and filesystems.
    dms                         : Manage Azure Data Migration Service (DMS) instances.
    eventgrid                   : Manage Azure Event Grid topics, event subscriptions, domains and domain topics.
    eventhubs                   : Manage Azure Event Hubs namespaces, eventhubs, consumergroups and geo recovery configurations - Alias.
    extension                   : Manage and update CLI extensions.
    feature                     : Manage resource provider features.
    functionapp                 : Manage function apps. To install the Azure Functions Core tools
    see https://github.com/Azure/azure-functions-core-tools.
    group                       : Manage resource groups and template deployments.
    hdinsight                   : Manage HDInsight resources.
    identity                    : Managed Service Identities.
    image                       : Manage custom virtual machine images.
    iot                         : Manage Internet of Things (IoT) assets.
    iotcentral                  : Manage IoT Central assets.
    keyvault                    : Manage KeyVault keys, secrets, and certificates.
    kusto                       : Manage Azure Kusto resources.
    lab               [Preview] : Manage Azure DevTest Labs.
    lock                        : Manage Azure locks.
    managedapp                  : Manage template solutions provided and maintained by Independent Software Vendors (ISVs).
    managedservices             : Manage the registration assignments and definitions in Azure.
    maps                        : Manage Azure Maps.
    mariadb                     : Manage Azure Database for MariaDB servers.
    monitor                     : Manage the Azure Monitor Service.
    mysql                       : Manage Azure Database for MySQL servers.
    netappfiles       [Preview] : Manage Azure NetApp Files (ANF) Resources.
    network                     : Manage Azure Network resources.
    openshift                   : Manage Azure Red Hat OpenShift Services.
    policy                      : Manage resource policies.
    postgres                    : Manage Azure Database for PostgreSQL servers.
    ppg                         : Manage Proximity Placement Groups.
    provider                    : Manage resource providers.
    redis                       : Manage dedicated Redis caches for your Azure applications.
    relay                       : Manage Azure Relay Service namespaces, WCF relays, hybrid connections, and rules.
    reservations      [Preview] : Manage Azure Reservations.
    resource                    : Manage Azure resources.
    role                        : Manage user roles for access control with Azure Active Directory and service principals.
    search            [Preview] : Manage Azure Search services, admin keys and query keys.
    security          [Preview] : Manage your security posture with Azure Security Center.
    servicebus                  : Manage Azure Service Bus namespaces, queues, topics, subscriptions, rules and geo-disaster recovery configuration alias.
    sf                [Preview] : Manage and administer Azure Service Fabric clusters.
    sig                         : Manage shared image gallery.
    signalr                     : Manage Azure SignalR Service.
    snapshot                    : Manage point-in-time copies of managed disks, native blobs, or other snapshots.
    sql                         : Manage Azure SQL Databases and Data Warehouses.
    storage                     : Manage Azure Cloud Storage resources.
    tag                         : Manage resource tags.
    vm                          : Manage Linux or Windows virtual machines.
    vmss                        : Manage groupings of virtual machines in an Azure Virtual Machine Scale Set (VMSS).
    webapp                      : Manage web apps.

Commands:
    configure                   : Manage Azure CLI configuration. This command is interactive.
    feedback                    : Send feedback to the Azure CLI Team!
    find                        : I'm an AI robot, my advice is based on our Azure documentation as well as the usage patterns of Azure CLI and Azure ARM users. Using me improves Azure products and documentation.
    interactive       [Preview] : Start interactive mode. Installs the Interactive extension if not installed already.
    login                       : Log in to Azure.
    logout                      : Log out to remove access to Azure subscriptions.
    rest                        : Invoke a custom request.
    version           [Preview] : Show the versions of Azure CLI modules and extensions in JSON format by default or format configured by --output.

Please let us know how we are doing: https://aka.ms/clihats

Next, you've already been configured with credentials. Use az and your account to show your current details and make sure to pipe to less ( | less )

elf@3b93c88b5a50:~$ az account show | less
{
  "environmentName": "AzureCloud",
  "id": "2b0942f3-9bca-484b-a508-abdae2db5e64",
  "isDefault": true,
  "name": "northpole-sub",
  "state": "Enabled",
  "tenantId": "90a38eda-4006-4dd5-924c-6ca55cacc14d",
  "user": {
    "name": "northpole@northpole.invalid",
    "type": "user"
  }
}

Excellent! Now get a list of resource groups in Azure. For more information: https://learn.microsoft.com/en-us/cli/azure/group?view=azure-cli-latest

We found the following in the linked resource above!

az group list
List resource groups
elf@3b93c88b5a50:~$ az group list | less
[
  {
    "id": "/subscriptions/2b0942f3-9bca-484b-a508-abdae2db5e64/resourceGroups/northpole-rg1",
    "location": "eastus",
    "managedBy": null,
    "name": "northpole-rg1",
    "properties": {
      "provisioningState": "Succeeded"
    },
    "tags": {}
  },
  {
    "id": "/subscriptions/2b0942f3-9bca-484b-a508-abdae2db5e64/resourceGroups/northpole-rg2",
    "location": "westus",
    "managedBy": null,
    "name": "northpole-rg2",
    "properties": {
      "provisioningState": "Succeeded"
    },
    "tags": {}
  }
]

Ok, now use one of the resource groups to get a list of function apps. For more information: https://learn.microsoft.com/en-us/cli/azure/functionapp?view=azure-cli-latest Note: Some of the information returned from this command relates to other cloud assets used by Santa and his elves.

We found the following in the linked resource above!

az functionapp list
List function apps.
elf@058d72e304f5:~$ az functionapp list --resource-group northpole-rg1 | less
[
  {
    "appServicePlanId": "/subscriptions/2b0942f3-9bca-484b-a508-abdae2db5e64/resourceGroups/northpole-rg1/providers/Microsoft.Web/serverfarms/EastUSLinuxDynamicPlan",
    "availabilityState": "Normal",
    "clientAffinityEnabled": false,
    "clientCertEnabled": false,
    "clientCertExclusionPaths": null,
    "clientCertMode": "Required",
    "cloningInfo": null,
    "containerSize": 0,
    "customDomainVerificationId": "201F74B099FA881DB9368A26C8E8B8BB8B9AF75BF450AF717502AC151F59DBEA",
    "dailyMemoryTimeQuota": 0,
    "defaultHostName": "northpole-ssh-certs-fa.azurewebsites.net",
    "enabled": true,
    "enabledHostNames": [
      "northpole-ssh-certs-fa.azurewebsites.net"
    ],
    "extendedLocation": null,
    "hostNameSslStates": [
      {
        "certificateResourceId": null,
        "hostType": "Standard",
        "ipBasedSslResult": null,
        "ipBasedSslState": "NotConfigured",
        "name": "northpole-ssh-certs-fa.azurewebsites.net",
        "sslState": "Disabled",
        "thumbprint": null,
        "toUpdate": null,
        "toUpdateIpBasedSsl": null,
        "virtualIPv6": null,
        "virtualIp": null
      },
      {
        "certificateResourceId": null,
        "hostType": "Repository",
        "ipBasedSslResult": null,
        "ipBasedSslState": "NotConfigured",
        "name": "northpole-ssh-certs-fa.scm.azurewebsites.net",
        "sslState": "Disabled",
        "thumbprint": null,
        "toUpdate": null,
        "toUpdateIpBasedSsl": null,
        "virtualIPv6": null,
        "virtualIp": null
      }
    ],
    "hostNames": [
      "northpole-ssh-certs-fa.azurewebsites.net"
    ],
    "hostNamesDisabled": false,
    "hostingEnvironmentProfile": null,
    "httpsOnly": false,
    "hyperV": false,
    "id": "/subscriptions/2b0942f3-9bca-484b-a508-abdae2db5e64/resourceGroups/northpole-rg1/pro
viders/Microsoft.Web/sites/northpole-ssh-certs-fa",
    "identity": {
      "principalId": "d3be48a8-0702-407c-89af-0319780a2aea",
      "tenantId": "90a38eda-4006-4dd5-924c-6ca55cacc14d",
      "type": "SystemAssigned",
      "userAssignedIdentities": null
    },
    "inProgressOperationId": null,
    "isDefaultContainer": null,
    "isXenon": false,
    "keyVaultReferenceIdentity": "SystemAssigned",
    "kind": "functionapp,linux",
    "lastModifiedTimeUtc": "2023-11-09T14:43:01.183333",
    "location": "East US",
    "maxNumberOfWorkers": null,
    "name": "northpole-ssh-certs-fa",
    "outboundIpAddresses": "",
    "possibleOutboundIpAddresses": "",
    "publicNetworkAccess": null,
    "redundancyMode": "None",
    "repositorySiteName": "northpole-ssh-certs-fa",
    "reserved": true,
    "resourceGroup": "northpole-rg1",
    "scmSiteAlsoStopped": false,
    "siteConfig": {
      "acrUseManagedIdentityCreds": false,
      "acrUserManagedIdentityId": null,
      "alwaysOn": false,
      "antivirusScanEnabled": null,
      "apiDefinition": null,
      "apiManagementConfig": null,
      "appCommandLine": null,
      "appSettings": null,
      "autoHealEnabled": null,
      "autoHealRules": null,
      "autoSwapSlotName": null,
      "azureMonitorLogCategories": null,
      "azureStorageAccounts": null,
      "connectionStrings": null,
      "cors": null,
      "customAppPoolIdentityAdminState": null,
      "customAppPoolIdentityTenantState": null,
      "defaultDocuments": null,
      "detailedErrorLoggingEnabled": null,
      "documentRoot": null,
      "elasticWebAppScaleLimit": null,
      "experiments": null,
      "fileChangeAuditEnabled": null,
      "ftpsState": null,
      "functionAppScaleLimit": 200,
      "functionsRuntimeScaleMonitoringEnabled": null,
      "handlerMappings": null,
      "healthCheckPath": null,
      "http20Enabled": true,
      "http20ProxyFlag": null,
      "httpLoggingEnabled": null,
      "ipSecurityRestrictions": null,
      "ipSecurityRestrictionsDefaultAction": null,
      "javaContainer": null,
      "javaContainerVersion": null,
      "javaVersion": null,
      "keyVaultReferenceIdentity": null,
      "limits": null,
      "linuxFxVersion": "Python|3.11",
      "loadBalancing": null,
      "localMySqlEnabled": null,
      "logsDirectorySizeLimit": null,
      "machineKey": null,
      "managedPipelineMode": null,
      "managedServiceIdentityId": null,
      "metadata": null,
      "minTlsCipherSuite": null,
      "minTlsVersion": null,
      "minimumElasticInstanceCount": 0,
      "netFrameworkVersion": null,
      "nodeVersion": null,
      "numberOfWorkers": 1,
      "phpVersion": null,
      "powerShellVersion": null,
      "preWarmedInstanceCount": null,
      "publicNetworkAccess": null,
      "publishingPassword": null,
      "publishingUsername": null,
      "push": null,
      "pythonVersion": null,
      "remoteDebuggingEnabled": null,
      "remoteDebuggingVersion": null,
      "requestTracingEnabled": null,
      "requestTracingExpirationTime": null,
      "routingRules": null,
      "runtimeADUser": null,
      "runtimeADUserPassword": null,
      "scmIpSecurityRestrictions": null,
      "scmIpSecurityRestrictionsDefaultAction": null,
      "scmIpSecurityRestrictionsUseMain": null,
      "scmMinTlsVersion": null,
      "scmType": null,
      "sitePort": null,
      "sitePrivateLinkHostEnabled": null,
      "storageType": null,
      "supportedTlsCipherSuites": null,
      "tracingOptions": null,
      "use32BitWorkerProcess": null,
      "virtualApplications": null,
      "vnetName": null,
      "vnetPrivatePortsCount": null,
      "vnetRouteAllEnabled": null,
      "webSocketsEnabled": null,
      "websiteTimeZone": null,
      "winAuthAdminState": null,
      "winAuthTenantState": null,
      "windowsConfiguredStacks": null,
      "windowsFxVersion": null,
      "xManagedServiceIdentityId": null
    },
    "slotSwapStatus": null,
    "state": "Running",
    "storageAccountRequired": false,
    "suspendedTill": null,
    "tags": {
      "create-cert-func-url-path": "/api/create-cert?code=candy-cane-twirl",
      "project": "northpole-ssh-certs"
    },
    "targetSwapSlot": null,
    "trafficManagerHostNames": null,
    "type": "Microsoft.Web/sites",
    "usageState": "Normal",
    "virtualNetworkSubnetId": null,
    "vnetContentShareEnabled": false,
    "vnetImagePullEnabled": false,
    "vnetRouteAllEnabled": false
  }
]

Find a way to list the only VM in one of the resource groups you have access to. For more information: https://learn.microsoft.com/en-us/cli/azure/vm?view=azure-cli-latest

We found the following in the linked resource above!

az vm list    List details of Virtual Machines.
elf@058d72e304f5:~$ az vm list --resource-group northpole-rg1 | less
The client 'f17559a4-d8a2-4661-ba0f-c04f8cf2926d' with object id '8deacb33-214d-4d94-9ab4-d27768410f17' does not have authorization to perform action 'Microsoft.Compute/virtualMachines/read' over scope '/subscriptions/2b0942f3-9bca-484b-a508-abdae2db5e64/resourceGroups/northpole-rg1/providers/Microsoft.Compute/virtualMachines' or the scope is invalid. If access was recently granted, please refresh your credentials.
elf@058d72e304f5:~$ az vm list --resource-group northpole-rg2 | less
[
  {
    "id": "/subscriptions/2b0942f3-9bca-484b-a508-abdae2db5e64/resourceGroups/northpole-rg2/providers/Microsoft.Compute/virtualMachines/NP-VM1",
    "location": "eastus",
    "name": "NP-VM1",
    "properties": {
      "hardwareProfile": {
        "vmSize": "Standard_D2s_v3"
      },
      "provisioningState": "Succeeded",
      "storageProfile": {
        "imageReference": {
          "offer": "UbuntuServer",
          "publisher": "Canonical",
          "sku": "16.04-LTS",
          "version": "latest"
        },
        "osDisk": {
          "caching": "ReadWrite",
          "createOption": "FromImage",
          "managedDisk": {
            "storageAccountType": "Standard_LRS"
          },
          "name": "VM1_OsDisk_1"
        }
      },
      "vmId": "e5f16214-18be-4a31-9ebb-2be3a55cfcf7"
    },
    "resourceGroup": "northpole-rg2",
    "tags": {}
  }
]

Find a way to invoke a run-command against the only Virtual Machine (VM) so you can RunShellScript and get a directory listing to reveal a file on the Azure VM. For more information: https://learn.microsoft.com/en-us/cli/azure/vm/run-command?view=azure-cli-latest#az-vm-run-command-invoke

We found the following in the linked resource above!

az vm run-command invoke --resource-group <your-resource-group-name> --name <your-vm-name> --command-id RunShellScript --scripts "ls" --output table
elf@e6b548de5747:~$ az vm run-command invoke --resource-group northpole-rg2 --name NP-VM1 --command-id RunShellScript --scripts 'ls' --output table
{
  "value": [
    {
      "code": "ComponentStatus/StdOut/succeeded",
      "displayStatus": "Provisioning succeeded",
      "level": "Info",
      "message": "bin\netc\nhome\njinglebells\nlib\nlib64\nusr\n",
      "time": 1703776278
    },
    {
      "code": "ComponentStatus/StdErr/succeeded",
      "displayStatus": "Provisioning succeeded",
      "level": "Info",
      "message": "",
      "time": 1703776278
    }
  ]
}
Achievement

"Congratulations! You have completed the Azure 101 challenge!"

When speaking with Sparkle Redberry previously after completing Azure 101 Terminal challenge, we obtain the following hint and objective.

Azure VM Access Token

Azure CLI tools aren't always available, but if you're on an Azure VM you can always use the Azure REST API instead.

Certificate SSHenanigans (Pixel Island)

Go to Pixel Island and review Alabaster Snowball's new SSH certificate configuration and Azure Function App. What type of cookie cache is Alabaster planning to implement?

Resort Lobby - Endgame Location⚓︎

If we head into the castle at the north part of Christmas Island, we enter the Resort Lobby where we are greeted by Pepper Minstix.

resort

Pepper Minstix

After you complete all the challenges, come back here for a surprise!

See Conclusion on the big surprise!