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!
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.
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!
After speaking with Jingle Ringford, I received a fishing pole so I can fish on my boat!
When clicking on my star and going to "Items", we can see it stored there!
Full Island (Zoomed Out)
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.
Upon initiating the challenge, a tmux terminal is launched.
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.
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!
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!
Full Island (Zoomed Out)
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.
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:
Analyzing JavaScript⚓︎
To leverage the hints provided, we can use browser developer tools (F12) to interact with an iframe
:
- Right-click the
iframe
and chooseInspect
, or pressCTRL
+Shift
+i
(in Chrome). - Go to the
Console
tab. - Use the downward arrow to access the JavaScript console for the
iframe
. - 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/
.
By examining the JavaScript code, we can pinpoint several valuable variables that can be modified to maximize the benefits in our game.
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
.
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');
}
}
// 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 theProxy
settings in Burp - Check
Intercept responses based on the following rules:
in theProxy
settings in Burp - Uncheck all options in the
WebSocket interception rules
in theProxy
settings in Burp - Specific the URL regex match condition under
Response interception rules
in theProxy
settings in Burp
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:
#!/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:
We can see it replaces the server-response successfully. Note, this opens TCP Port 9000 on execution.
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!
After defeating Santa we obtain Victory!
Morcel Nougat congratulates us and we obtain an achievement!
Achievement
Congratulations! You have completed the Snowball Fight challenge!
Linux 101⚓︎
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.
I found Ginger Breddie inside and close to a challenge.
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.
Type "yes" to begin:
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.
Great, now remove the troll in your home directory.
Print the present working directory using a command.
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.
Next, head into the workshop.
A troll is hiding in one of the workshop toolboxes. Use "grep" while ignoring case to find which toolbox the troll is in.
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.
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.
Your final task is to stop the 14516_troll process to collect the remaining presents.
Type "exit" to close...
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.
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!
Full Island (Zoomed Out)
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.
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:
I created a Python script for brute-forcing to unravel this challenge quickly:
#!/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!")
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 fromBy 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 anHTTP SEND
where there is not such thing asSEND
. 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, theHTTP 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⚓︎
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!
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
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
)
{
"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!
[
{
"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!
[
{
"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!
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.
[
{
"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.
Pepper Minstix
After you complete all the challenges, come back here for a surprise!
See Conclusion on the big surprise!