> For the complete documentation index, see [llms.txt](https://kabinet.gitbook.io/ctf-writeup/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://kabinet.gitbook.io/ctf-writeup/2022/stack-the-flag/secret-of-meow-olympurr.md).

# Secret of Meow Olympurr

## Secret of Meow Olympurr

Category: Cloud Difficulty: Medium Tags: AWS, Azure

## Challenge Description

<figure><img src="/files/kOfwrDvu1Yj6EjnPdwz3" alt=""><figcaption></figcaption></figure>

From the challenge description, I identified a few key information

1. There are misconfiguration in the cloud configuration
2. It is a multi-cloud configuration, with two environment
3. To get the flag, I will need to invoke a function

I am also given the URL to a AWS CloudFront

[d2p9lw76n0gfo0.cloudfront.net](http://d2p9lw76n0gfo0.cloudfront.net/)

## Enumeration

<figure><img src="/files/oI6iq58GktqYZFhLDBvh" alt=""><figcaption></figcaption></figure>

Visiting the URL shows a website with alot of cute cats, and it also reminds me of `CloudyNekos` from TISC 2022

Viewing the source code of the website does not reveal any useful information, however when visiting the error page, it shows some interesting information.

<figure><img src="/files/QuXki82MQNuCyOdXf8ZG" alt=""><figcaption></figcaption></figure>

## Error page

The image src is [`http://18.141.147.115:8080/https://meowolympurr.z23.web.core.windows.net/images/ohno.jpg`](http://18.141.147.115:8080/https://meowolympurr.z23.web.core.windows.net/images/ohno.jpg) which made me suspect that it is a possible SSRF vector, and I went down a really long rabbit hole of enumerating and trying to exploit the RFO.

## Attempting to exploit SSRF (Rabbit Hole)

I first identified the API that is running at [`http://18.141.147.115:8080`](http://18.141.147.115:8080/https://meowolympurr.z23.web.core.windows.net/images/ohno.jpg) is [Cors\_anywhere](https://github.com/Rob--W/cors-anywhere/)

I am also able to visit [`http://18.141.147.115:8080/http://169.254.169.254/latest/meta-data`](http://18.141.147.115:8080/http://169.254.169.254/latest/meta-data) and extract the credentials at [`http://18.141.147.115:8080/http://169.254.169.254/latest/meta-data/identity-credentials/ec2/security-credentials/ec2-instance`](http://18.141.147.115:8080/http://169.254.169.254/latest/meta-data/identity-credentials/ec2/security-credentials/ec2-instance)

However, after spending hours enumerating with the credentials, I was unable to proceed anywhere. I revisited this [`http://18.141.147.115:8080/https://meowolympurr.z23.web.core.windows.net/images/ohno.jpg`](http://18.141.147.115:8080/https://meowolympurr.z23.web.core.windows.net/images/ohno.jpg) url, and I realized that I missed out on the glaringly obvious Azure URL Syntax.

I double check my suspicion by visiting [Microsoft](https://learn.microsoft.com/en-us/azure/storage/common/storage-account-overview) documentation and identified that it is an `Azure DNS zone endpoints`.

<figure><img src="/files/ELxFI6esoxS3Jz60DkHV" alt=""><figcaption></figcaption></figure>

Visiting [`https://meowolympurr.z23.web.core.windows.net/`](https://meowolympurr.z23.web.core.windows.net/) shows the exact page as the AWS CloudFront end point, with an extra endpoint pointing to Azure Function App (which we will revisit in later steps), however things get interesting again when visiting the error page.

<figure><img src="/files/rBsRatHItwg57IDYO7Eb" alt=""><figcaption></figcaption></figure>

When visiting `view-source:https://meowolympurr.z23.web.core.windows.net/asd` it shows a SAS Key for Azure Storage Account, and I connected to the storage account with [Microsoft Azure Storage Explorer](https://azure.microsoft.com/en-us/products/storage/storage-explorer/).

> 💡 SAS (Shared Access Signature) key is a string of characters that allows access to a specific Azure storage account resource. SAS keys are typically used to grant access to resources in a storage account to users or applications that do not have direct access to the storage account key. The SAS key provides a secure and flexible way to grant access to storage account resources without giving users or applications access to the storage account key.

```
https://meowolympurr.blob.core.windows.net?sv=2017-07-29&ss=b&srt=sco&sp=rl&se=2022-12-12T00:00:00Z&st=2022-09-01T00:00:00Z&spr=https&sig=UE2%2FTMTAzDnyJEABpX4OYFBs1b1uAWjwEEAtjeQtwxg%3D
```

## Connecting to Azure Storage Account

I used the GUI application [Microsoft Azure Storage Explorer](https://learn.microsoft.com/en-us/azure/vs-azure-tools-storage-manage-with-storage-explorer)

<figure><img src="/files/zx4XfA0UGrNzJX8Bh1wH" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/tJBkmQGwT7ziIcr8Lv38" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/lGw9jadaskViD20VD0tJ" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/nF09sW3JUC4SMABWdkeR" alt=""><figcaption></figcaption></figure>

Upon connecting to the storage account with the SAS, it shows that there are 3 blobs containers.

Looking at the `dev` container shows a `readme.md` file which shows hints to continue the challenge.

```markdown
# Meow Olympurr 
One stop service for all fun activites in Meow Olympurr! 
    
All resources are hosted on a single tenant: 83e595f4-f086-4f2f-9de8-d698b6012093

Meows are not cy-purr security trained, but we are willing to learn! 
    
# To do 
1. Consolidate the asset list 
2. Seek advice from Jaga and team when they arrive! 
3. Integrate services 
4. Remove credentials used for debugging access to function app

# Function app - https://olympurr-app.azurewebsites.net/api/meowvellous
SAS token to access the scm-releases container: ?sv=2018-11-09&sr=c&st=2022-09-01T00%3A00%3A00Z&se=2022-12-12T00%3A00%3A00Z&sp=rl&spr=https&sig=jENgCFTrC1mYM1ZNo%2F8pq1Hg9BO1VLbXlk%2FpABrK4Eo%3D

## Credentials for debugging
The following service principal has the same privileges as the function app
Application ID: ee92075f-4ddc-4522-a12c-2bc0ab874c85
Client Secret: kmk8Q~mGYD9jNfgm~rcIOMRgiC9ekKtNEw5GPaS7
```

The `readme.md` gave a few key information.

1. Tenant ID
2. Application ID
3. Client Secret
4. Function Application Endpoint
5. SAS token for the `scm-releases` container

Using the `application id` and `client secret` I am able to login with the `service principal`, which has the same privileges as the function app. I will be using az powershell, as I am more familiar with it.

> 💡 An Azure service principal is a security identity that is used by applications or services to access resources in Azure. It is similar to a user identity, but is specific to applications or services, and can be used to grant permissions to access Azure resources

**Connecting with the Azure using powershell**

```powershell
powershell -ep bypass

$TenantId = '83e595f4-f086-4f2f-9de8-d698b6012093'
$Credential = Get-Credential
Connect-AzAccount -ServicePrincipal -TenantId $TenantId -Credential $Credential
```

For the `Get-Credential` cmdlets, put the `application id` as username, and `client secret` as password

<figure><img src="/files/8T7D8w3AnSnpM8tHBDrk" alt=""><figcaption></figcaption></figure>

Since the `readme.md` above gave a `SAS key` I will first try and enumerate storage account with the `Get-AzStorageAccount` cmdlet.

<figure><img src="/files/Rp7J7kxRZiWkLPEdNzyB" alt=""><figcaption></figcaption></figure>

As suspected, there is another storage account called `meowvellousappstorage` and I am able to connect to the `scm-releases` container with the SAS in the readme.

```powershell
https://meowvellousappstorage.blob.core.windows.net/scm-releases?sv=2018-11-09&sr=c&st=2022-09-01T00%3A00%3A00Z&se=2022-12-12T00%3A00%3A00Z&sp=rl&spr=https&sig=jENgCFTrC1mYM1ZNo%2F8pq1Hg9BO1VLbXlk%2FpABrK4Eo%3D
```

In the `scm-releases` container, it shows a zip file `scm-latest-olympurr-app.zip` which is the source code of the Azure Function enumerated previously.

```python
import boto3
import requests
import json

import azure.functions as func
from azure.identity import ManagedIdentityCredential
from azure.keyvault.secrets import SecretClient

functionName = "event-webservice"
keyName = "AKIA5G4XMRW7TLT6XD7R"

def logURL(url):
    identity = ManagedIdentityCredential()
    secretClient = SecretClient(vault_url="https://olympurr-aws.vault.azure.net/", credential=identity)
    secret = secretClient.get_secret(keyName).value
    session = boto3.Session(
        aws_access_key_id=keyName,
        aws_secret_access_key=secret
    )
    
    lambda_client = session.client("lambda", region_name="ap-southeast-1")

    details = {"url" : url}
    lambda_client.invoke(
        FunctionName=functionName,
        InvocationType="RequestResponse",
        Payload=bytes(json.dumps(details), "utf-8")
    )
    return secret

def main(req: func.HttpRequest) -> func.HttpResponse:
    url = req.params.get('url')

    if not url:
        try:
            req_body = req.get_json()
        except ValueError:
            pass
        else:
            name = req_body.get('url')

    if url:
        # Log the URL in AWS 
        secret = logURL(url)
        try:
            response = requests.get(url)
            return func.HttpResponse(response.text)
        except Exception as e:
            return func.HttpResponse(str(e))
    
    return func.HttpResponse(
            """Found an interesting event you would like to organise in Meow Olympurr?
Pass the URL as a query string. You will see the submitted information if it is successful. 
e.g. https://olympurr-app.azurewebsites.net/api/meowvellous?url=<INSERT>
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⣿⣿⡷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⣿⡿⠋⠈⠻⣮⣳⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⣴⣾⡿⠋⠀⠀⠀⠀⠙⣿⣿⣤⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣤⣶⣿⡿⠟⠛⠉⠀⠀⠀⠀⠀⠀⠀⠈⠛⠛⠿⠿⣿⣷⣶⣤⣄⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣴⣾⡿⠟⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠛⠻⠿⣿⣶⣦⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⣀⣠⣤⣤⣀⡀⠀⠀⣀⣴⣿⡿⠛⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⠿⣿⣷⣦⣄⡀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣤⣄⠀⠀
⢀⣤⣾⡿⠟⠛⠛⢿⣿⣶⣾⣿⠟⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⠿⣿⣷⣦⣀⣀⣤⣶⣿⡿⠿⢿⣿⡀⠀
⣿⣿⠏⠀⢰⡆⠀⠀⠉⢿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠻⢿⡿⠟⠋⠁⠀⠀⢸⣿⠇⠀
⣿⡟⠀⣀⠈⣀⡀⠒⠃⠀⠙⣿⡆⠀⠀⠀⠀⠀⠀⠀⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⠇⠀
⣿⡇⠀⠛⢠⡋⢙⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⣿⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⠀⠀
⣿⣧⠀⠀⠀⠓⠛⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⠛⠋⠀⠀⢸⣧⣤⣤⣶⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣿⡿⠀⠀
⣿⣿⣤⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠉⠻⣷⣶⣶⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿⠁⠀⠀
⠈⠛⠻⠿⢿⣿⣷⣶⣦⣤⣄⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣴⣿⣷⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⡏⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠉⠙⠛⠻⠿⢿⣿⣷⣶⣦⣤⣄⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠿⠛⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⢿⣿⡄⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠙⠛⠻⠿⢿⣿⣷⣶⣦⣤⣄⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢿⣿⡄⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠛⠛⠿⠿⣿⣷⣶⣶⣤⣤⣀⡀⠀⠀⠀⢀⣴⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢿⡿⣄
   Send us the details!            ⠀⠀⠉⠉⠛⠛⠿⠿⣿⣷⣶⡿⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⣿⣹
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣀⠀⠀⠀⠀⠀⠀⢸⣧
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢻⣿⣆⠀⠀⠀⠀⠀⠀⢀⣀⣠⣤⣶⣾⣿⣿⣿⣿⣤⣄⣀⡀⠀⠀⠀⣿
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⢿⣻⣷⣶⣾⣿⣿⡿⢯⣛⣛⡋⠁⠀⠀⠉⠙⠛⠛⠿⣿⣿⡷⣶⣿
            """,
            status_code=200
    )
```

Extracting the source code with unsquashfs identify a few information.

1. An AWS key with the key name of `AKIA5G4XMRW7TLT6XD7R`
2. An Lamba Function with the function name `event-webservice`
3. In the function `logURL` it shows the lambda function getting a `managed identity` and connecting to `Azure Key Vault` to retrieve a secret key.

> 💡 Azure managed identity is a feature of Azure Active Directory that allows an Azure resource, such as a virtual machine, to be authenticated and authorized to access other Azure resources.

Since we knew that the `service principal` we are connected has the same permission as the managed identity, I am able to directly call the `Get-AzKeyVaultSecret` cmdlet to retrieve the AWS secret.

> 💡 Azure Key Vault is a cloud-based service for securely storing and managing cryptographic keys and secrets.

```powershell
Get-AzKeyVaultSecret -VaultName "olympurr-aws" -Name "AKIA5G4XMRW7TLT6XD7R"
```

<figure><img src="/files/oznKEXkS99tIHCrReQxC" alt=""><figcaption></figcaption></figure>

## Pivot back to AWS

Using AWS cli, I am able to login with the set of access key and secret access key

Using the tool [pacu](https://github.com/RhinoSecurityLabs/pacu), I am able to enumerate my user permission.

```bash
docker run -it -v ~/.aws:/root/.aws rhinosecuritylabs/pacu:latest
import_keys --all
exec iam__bruteforce_permissions
```

<figure><img src="/files/122GFn77yzGeupsiYeWc" alt=""><figcaption></figcaption></figure>

I am able to identified the allow permissions.

```json
"Allow": [
      "ec2:DescribeLogGroups",
      "s3:DescribeLogGroups",
      "logs:DescribeLogGroups",
      "ec2:DescribeLogStreams",
      "s3:DescribeLogStreams",
      "logs:DescribeLogStreams",
      "ec2:GetQueryResults",
      "s3:GetQueryResults",
      "logs:GetQueryResults"
    ]
```

Since we have the `logs:DescribeLogGroups` permission set, lets try running that first

```json
aws logs describe-log-groups
```

There are quite a few log groups, however two of them caught my eyes.

The `/aws/lambda/event-webservice` was the function name identified in the source code from `scm-releases` and

`/aws/lambda/internal-secret-of-MeowOlympurr-webservice` seems to reveal the secrets (flag).

<figure><img src="/files/axTpJrZhKDH7KemL0mYH" alt=""><figcaption></figcaption></figure>

Recall from the `function application` source code that the IAM user is able to invoke a lambda function, despite it not being reflected in the permission enumerated from pacu.

```python
lambda_client.invoke(
        FunctionName=functionName,
        InvocationType="RequestResponse",
        Payload=bytes(json.dumps(details), "utf-8")
    )
```

I attempted to invoke the `internal-secret-of-MeowOlympurr-webservice` and I am given the flag.

```bash
aws lambda invoke  --function-name internal-secret-of-MeowOlympurr-webservice outfile
```

<figure><img src="/files/NReGGDgmK91j6oFuoQND" alt=""><figcaption></figcaption></figure>

## Conclusion

Flag: `STF22{LIveInTh3Me0wmen7_:3}`

The challenge is a nice step above `Cloudy Nekos` from TISC. It covers misconfiguration in a multi-cloud environment, testing participants capability in enumerating services in both AWS and Azure.

> ps the cats were really cute
