Skip to content
KitploitKITPLOIT
工具博客
Log in
提交
工具博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

订阅源联系隐私© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
POC-CVE-2026-65971 — CVE-2026-65971 的概念验证与技术分析——通过 power-components/livewire-powergrid(< 6.10.4)中的 sortDirection Livewire 属性实现的 SQL 注入 | Kitploit
工具/GitHubGitHub/biitts/poc-cve-2026-65971
漏洞分析漏洞利用Web应用程序漏洞利用渗透测试论文与研究学习与教育
GitHubbiitts/poc-cve-2026-65971

POC-CVE-2026-65971

CVE-2026-65971 的概念验证与技术分析——通过 power-components/livewire-powergrid(< 6.10.4)中的 sortDirection Livewire 属性实现的 SQL 注入

查看仓库
1102个月前尚未审核

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

CVE-2026-65971 — 通过 sortDirection 在 Livewire PowerGrid 中实现 SQL 注入

针对 CVE-2026-65971 / GHSA-7fgc-3h6c-698r 的概念验证及完整技术文档, 这是 power-components/livewire-powergrid 中的一个 SQL 注入漏洞, 可通过公开的 Livewire 属性 sortDirection 触发。

CVECVE-2026-65971
GHSAGHSA-7fgc-3h6c-698r
软件包power-components/livewire-powergrid (Composer / Packagist)
受影响版本>= 6.0.0, < 6.10.4
已修复版本6.10.4
弱点CWE-89 — 未正确中和 SQL 命令中使用的特殊元素
严重性7.6 高危 — CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:L
报告者Caio Fabrício (@BiiTts)
披露方式协调披露,通过 GitHub 私有安全公告
├── poc/exploit_powergrid_sqli.py working exploit — confirm + blind extraction
├── lab/ build the vulnerable app to reproduce it yourself
├── evidence/EVIDENCE.txt raw lab notes from confirmation
├── patch/security-fix-v6.10.4.diff the security-relevant portion of the official fix
└── detection/ Sigma rules + Nuclei template for defenders
---

## 🧠 概述

PowerGrid 是一个用于 Laravel + Livewire 的 datatable 组件(约 2k 星,广泛用于
Laravel 管理面板)。其排序状态存在于两个 **公共 Livewire 属性** 中:```php
public string $sortField = 'id';
public string $sortDirection = 'asc';

在 Livewire 中,公共属性是组件 wire 格式的一部分——任何能够访问该组件的客户端都可以通过 POST /livewire/update 设置它。这是设计使然;安全边界在于服务器如何处理该值。

PowerGrid 的 naturalSort() 特性会构建一个原始的 ORDER BY 表达式,其中包含字面占位符 {sortDirection};在将字符串交给 orderByRaw() 之前,管道会用 原始、未经验证的属性值 替换该占位符。因此,排序方向关键字会原样落入 SQL 中。

Laravel 自带的 orderBy() 会拒绝任何不是 asc/desc 的值,正是这种验证保证了普通排序路径的安全。问题在于,存在另一条未经验证的路径可到达同一个子句——攻击者可以完全绕过验证路径而触及它(参见 绕过方式)。

结果:ORDER BY 子句中出现任意 SQL,可被利用为盲布尔/时间型 oracle,读取数据库用户所能读取的任何数据。


🔥 影响

任何能够访问使用了 naturalSort 的 PowerGrid 表格的人,都可以借助时间型/布尔 oracle 读取 数据库中的任意数据——其他表、密码哈希、会话令牌、API 密钥、跨租户记录。

  • 保密性:高。 数据库用户可以 SELECT 的任何内容均可完整读取。
  • 完整性:低。 默认 PDO MySQL 配置会阻止堆叠查询,因此 ; UPDATE ... 不会执行。写入影响仅限于子查询能够触发的内容。
  • 可用性:低。 相同的原语为攻击者提供了 SLEEP() 和重型子查询——可轻易滥用来占用数据库线程。
  • 典型部署位置是加剧风险的因素。 PowerGrid 表格通常位于管理后台和多租户管理系统——恰恰是敏感数据的所在之处。低权限租户用户一旦访问到这样的表格,就能窃取整个数据库。

所需权限为 PR:L,因为数据表格通常位于应用身份验证之后。如果受影响的表格渲染在 未认证 的页面上,请按 PR:N 重新计算 → 8.2 高。


🧩 根本原因 —— 完整的污染链

三个文件,三个阶段。所有引用均针对易受攻击的标签 v6.10.3。

阶段 1 —— 源头:攻击者可控的公共属性

`src/Concerns/Sorting.php````php public string $sortField = 'id'; // line 11 public string $sortDirection = 'asc'; // line 13

这两个属性都没有白名单、验证规则或规范化设置器。`sortDirection` 只会被赋值或翻转:```php
public function reverseSort(): string    // line 37
{
    return $this->sortDirection === 'asc' ? 'desc' : 'asc';
}

updatedSortDirection()(第 103 行)确实存在——它是进行校验的自然位置——但在 v6.10.3 中,它仅处理懒加载的簿记工作,从未检查该值。

由于 Livewire 直接从请求中水合公共属性,因此此时 sortDirection 完全由攻击者控制,可作为任意字符串。

第 2 阶段 — 原始子句:naturalSort() 植入占位符

src/Providers/Macros.php,第 102–116 行 — naturalSort 列宏:```php Column::macro('naturalSort', function (bool $when = false, ?string $tableName = null): Column { $this->enableSort();

if ($when) {
    $this->rawQueries[] = [
        'method'   => 'orderByRaw',                          // <-- raw sink
        'sql'      => Sql::sortStringAsNumber($this->dataField),
        'bindings' => [],
    ];
}

return $this;

});

`Sql::sortStringAsNumber()` 解析为 `getSortSqlByDriver()` 在 `src/DataSource/Support/Sql.php`
(第 60–100 行)中构建的按驱动(per-driver)表达式。每个驱动变体
都以相同的字面占位符结尾:```php
$default = "$sortField+0 {sortDirection}";                                                          // line 76
'8.0.4'  => "CAST(NULLIF(REGEXP_REPLACE($sortField, '[[:alpha:]]+', ''), '') AS SIGNED INTEGER) {sortDirection}",  // MySQL, line 81
'0'      => "CAST($sortField AS INTEGER) {sortDirection}",                                          // SQLite, line 84
'0'      => "CAST(NULLIF(REGEXP_REPLACE($sortField, '\D', '', 'g'), '') AS INTEGER) {sortDirection}", // PgSQL, line 87
'0'      => "CAST(SUBSTRING(...) AS INT) {sortDirection}",                                          // SQL Server, line 90

该漏洞是与驱动无关的 — 每个分支都会插值 {sortDirection}。

阶段 3 — 汇点:占位符通过原始属性值进行解析

`src/DataSource/Processors/Database/Pipelines/ColumnRawQueries.php````php private function resolvePlaceholders(?string $sql): ?string // line 56 { if (is_null($sql)) { return null; }

return preg_replace_callback('/\{(\w+)\}/', function ($matches) {
    $property = trim($matches[1]);

    return data_get($this->component, $property, '');   // line 65 — raw property, no escaping
}, $sql);

}

以及执行,第 52 行:```php
$query->{$method}($resolvedSql, $resolvedBindings);   // $method === 'orderByRaw'

data_get($this->component, 'sortDirection') 返回攻击者的字符串,preg_replace_callback 将其拼接到 SQL 文本中,而 orderByRaw() —— 按契约规定不会转义其 参数 —— 将其传递给数据库。

请注意下面一行中残酷的讽刺:resolveBindings()(第 69 行)存在,而且 naturalSort 声明了 'bindings' => []。安全参数化的机制近在眼前。它不能 用于方向关键字 —— ORDER BY x ? 不是有效的 SQL,方向永远不能是绑定 参数 —— 这正是方向关键字必须被列入允许列表的原因。

The chain in one line```

POST /livewire/update ──▶ public string $sortDirection (Sorting.php:13, no validation) ──▶ data_get($component, 'sortDirection') (ColumnRawQueries.php:65) ──▶ "CAST(...) {sortDirection}" → "CAST(...) asc, (SELECT SLEEP(3))" ──▶ orderByRaw($sql) (ColumnRawQueries.php:52) ──▶ MySQL/MariaDB/PgSQL/SQLite/MSSQL

---

## 🔓 绕过方式 —— 为什么 Laravel 的验证救不了你

这是将“原始字符串插值”变成真正可利用漏洞的部分,也是该问题能在一个成熟、广泛使用的包中长期存在的原因。

PowerGrid 通过一条**管道(pipeline)**处理查询。管道中有两个阶段涉及排序方向:

**`Sorting` 管道** — `src/DataSource/Processors/Database/Pipelines/Sorting.php`:```php
public function handle(mixed $query, Closure $next): mixed
{
    // ...
    if (filled($this->component->sortField)) {          // line 21  <-- THE GUARD
        if ($this->component->multiSort) {
            $this->applyMultipleSort($query);
        } else {
            $this->applySingleSort($query, $this->component->sortField, $this->component->sortDirection);
        }
    }

    return $next($query);
}

private function applySingleSort(..., string $sortField, string $direction): void
{
    // ...
    $query->orderBy($this->component->resolveSortField($sortField), $direction);   // line 42
}

orderBy() 是 Laravel 的 校验型 API。给它 asc/desc 以外的任何值,它 都会抛出异常:``` InvalidArgumentException: Order direction must be "asc" or "desc".

所以在正常路径下——用户点击列标题,`sortField=name`,`sortDirection=<payload>`——框架会阻止注入。快速审计到此为止,并得出结论“已由 Laravel 缓解”。

**`ColumnRawQueries` 管道**——上面所示的第二阶段——**没有这样的防护**。看一下它的 `handle()`(第 21–27 行):它遍历所有列,并且对每一个携带 `rawQueries` 的列都*无条件地*应用它们。它从不检查 `sortField`。它从不检查 `Sorting` 管道的结果。

这种不对称性就是漏洞所在:

| `sortField` | `Sorting` 管道 | `ColumnRawQueries` 管道 | 结果 |
|---|---|---|---|
| `"name"`(已填充) | 运行 → `orderBy()` **验证** → 对负载抛出异常 | 运行 → 注入 | ❌ 被异常阻止 |
| `""`(空) | `filled('')` 为 `false` → **完全跳过** | 运行 → 注入 | ✅ **注入成功** |

将 **`sortField` 设置为空字符串** 会使验证阶段跳过自身,而原始阶段仍然会在其中包含攻击者的 `{sortDirection}` 的情况下发出 `naturalSort` `ORDER BY`。Laravel 的验证永远不会被调用,因为包含它的代码路径永远不会执行。

**因此,完整的攻击涉及两个字段,而不是一个:** `sortDirection` 携带负载,而 `sortField=""` 是解锁大门的钥匙。

---

## 🎯 精确字段

所有操作都通过 Livewire 的标准更新端点进行。没有特殊请求头,没有自定义路由,没有管理员功能。

**端点:** `POST /livewire/update`
下载工具