🎯 CVE-2026-31431 深度技术分析:漏洞根因 · PoC/EXP · 检测指纹
CVE-2026-31431 深度技术分析
摘要:CVE-2026-31431(别称“Copy Fail”)是 Linux 内核 crypto: algif_aead 子系统中存在的一处高危本地权限提升漏洞,CVSS 评分为 7.8(HIGH)。该漏洞允许未授权的容器工作负载通过 AF_ALG 套接字与 splice() 系统调用组合,破坏宿主机上任意文件的页缓存(page-cache)页面,进而可被链式利用为容器逃逸和节点完全控制。由于 Linux 内核 crypto 子系统的通用性,该漏洞影响所有使用受影响内核且支持 AF_ALG 的发行版,Talos Linux、containerd/XFS 叠加文件系统场景已被确认可实际利用。
📌 漏洞概述
CVE-2026-31431 是 Linux 内核 crypto/algif_aead.c 中 AEAD(Authenticated Encryption with Associated Data)算法接口的逻辑缺陷。NVD 评定其 CVSS 3.x 向量为 7.8 HIGH,属于本地权限提升(LPE)漏洞。该漏洞由 Theori / Xint 团队于 2026 年 4 月 29 日公开,官方修复方式为“回退到乱序(out-of-place)操作”,即部分撤销 2021 年提交 72548b093ee3 引入的就地(in-place)操作优化。
漏洞存在于 Linux 内核的 AF_ALG 套接字实现中。AF_ALG 允许用户态进程直接访问内核加密原语,其中 algif_aead 负责 AEAD 请求的异步/同步处理。通过构造特定的 AF_ALG 套接字和带外数据(如 splice() 将页缓存页面作为输入),攻击者可以在内核执行“认证失败”的 AEAD 解密操作之前,就已经使用解密函数覆写了同一页缓存页面。该行为导致攻击者拥有“写”任意可读文件的页缓存的能力,即使该文件以只读方式打开,甚至文件系统本身只读。由于页缓存是内核全局共享的数据结构,这种写原语可跨命名空间、跨容器传播,直至破坏宿主机关键可执行文件或配置文件。
此漏洞影响从引入就地操作优化到修复补丁之间的所有 Linux 内核版本。具体修复版本取决于各发行版回溯情况,预计包括 6.1.x、6.6.x、6.12.x、6.14.x 等稳定分支的最新修订。Talos Linux 等面向 Kubernetes 的不可变发行版也受影响,因为其默认使用 overlayfs / XFS 组合,恰好暴露了页缓存共享问题,使得攻击门槛进一步降低。
🔬 漏洞根因分析
该漏洞的根本原因在于 crypto/algif_aead.c 对 AEAD 操作“源(source)”与“目的(destination)”内存映射关系的错误假设。历史提交 72548b093ee3 引入了对 AF_ALG 接口的就地(in-place)操作优化:当内核处理 AEAD 解密请求时,如果加密上下文(tfm)和请求参数允许,则允许加密/解密函数直接在输入的 sk_buff 页面上覆写结果。该优化假设输入和输出可以共用同一块缓冲区地址,从而减少一次 DMA 或 memcpy 操作。
然而,在 AF_ALG 的典型使用场景中,源数据来自用户态提交的缓冲区或通过 splice() 从文件描述符直接挂接的页缓存页面;而目标缓冲区则是另一个独立的、由 AF_ALG 套接字分配的内存区域。二者在物理内存中是完全不同的映射。当用户通过 splice() 将文件页缓存页面作为 MSG_SPLICE_PAGES 标志下的输入页传入内核时,algif_aead 的就地优化错误地将“当前 skb 的页”既视为加密输入又视为解密输出。于是,内核在尚未完成 AEAD 认证标签(MAC)验证之前,就先调用了底层同步/异步解密函数。解密函数直接将明文(或密文)结果写入该输入页本身。即使随后的身份验证因为认证标签不匹配而失败并返回 -EBADMSG,但页缓存页面上的数据已经被解密逻辑改写。由于页缓存页面直接绑定到文件 inode,这种改写实质上修改了文件的页缓存内容,而无需经过 VFS 层写权限检查。
更危险的是,这种损坏并非一次性粗粒度覆盖。公开的 PoC 采用“窗口喷射”技术:将目标可执行文件在页缓存中的内容与攻击者期望的 payload 逐 4 字节地替换。具体而言,攻击者构造一个合法的 AEAD 解密请求,其中密文输入经由 splice() 来自目标文件页缓存。由于解密函数以 4 字节为单位(对于某些 AEAD 算法是 4 字节对齐块)进行覆写,即使整个请求最终认证失败,该 4 字节也已经被替换为目标 payload 的对应片段。随后攻击者反复执行该操作,每次修正一个新窗口,几次到几十次迭代后,目标文件的页缓存镜像就被完全替换为攻击者注入的代码或数据。攻击者此时只需等待特权进程(如 kube-proxy 或 CNI 插件)执行该二进制,即可实现任意代码执行。
而官方修复方式——回退到 out-of-place 操作——恰恰从根源上消除了此风险。通过强制将解密输出写入独立的临时缓冲区或 AF_ALG 分配的目标缓冲页,即使认证失败,也不会污染输入源页。同时保留对 associated data (AD) 的直接拷贝,因为 AD 是不参与加密/解密运算的明文元数据,不会引入安全风险。因此,该补丁在恢复安全语义的同时,仅损失了微乎其微的性能收益。
💥 影响与危害
CVE-2026-31431 被评估为 HIGH 严重级别,但实际利用链的破坏力远高于 CVSS 分数所暗示的“本地权限提升”。该漏洞提供的核心原语是“对进程已打开(只读)文件页缓存的任意写入”。只要攻击者能够触发内核读取某文件到页缓存(例如执行该文件、mmap 等),即可远程(在同一主机内)篡改其内容,而无需对该文件拥有写权限,也无需修改磁盘上的原始数据。这种对文件页缓存的不可见、非持久性篡改,使得安全软件难以检测——因为磁盘上文件校验和不变,仅内存中页缓存被改动。
在 Kubernetes 容器环境中,该漏洞可被链式利用为完整节点接管。攻击者仅需要在受影响的节点上具备创建 pod 的权限(这通常是任何普通用户都拥有的基础权限),即可通过以下路径实现 root 代码执行:
- 容器页缓存共享传播:containerd 等容器运行时采用 overlayfs,多个容器共享同一个镜像层文件。当下层文件被读入页缓存后,所有挂载该镜像层的 pod 都会看到同一页缓存页。攻击者可以利用此特性,篡改下层中的某个二进制文件(如
/usr/sbin/nft),从而使以 root 运行的特权容器(如 kube-proxy)加载被污染的代码。 - 特权容器二进制投毒:Kubernetes 的 DaemonSet 通常以特权模式运行(如 kube-proxy、CNI daemon)。这些容器的宿主机命名空间具有高权限,其中执行的二进制来自镜像层。攻击者篡改该二进制在页缓存中的内容后,当 DaemonSet 重新启动、崩溃重启或周期性执行该二进制时,内核会从“干净”的磁盘 inode 重新读入文件,但此时页缓存已经被攻击者改写——由于 inode 未变,内核不会验证页缓存哈希,直接执行被污染的数据。攻击者注入的 payload(例如
setuid(0); setuid(0); execve("/bin/sh"))便会以 root 身份执行。 - /etc/passwd 篡改:另一种公开变体是直接篡改
/etc/passwd页缓存中的用户 UID 字段,将攻击者指定的用户(如daemon)的 UID 改为 0,从而在系统下一次调用认证任务时获得 root 权限。
攻击成功后,攻击者可以读取节点上的所有机密(如 kubelet 证书、Kubernetes ServiceAccount token),安装持久化后门,攻击集群内其他节点,甚至由于节点拥有存储和网络访问权限,可能进一步横向移动至整个集群。而由于该攻击不依赖内核 race 条件,利用成功率极高,且可完全在用户态完成,无需任何额外漏洞。
🛡️ 修复与缓解
针对 CVE-2026-31431,Linux 内核主线已发布修复补丁,核心改动为回退 algif_aead 到乱序操作。该补丁部分撤销了 72548b093ee3,保留 associated data 拷贝逻辑,但强制解密输出到独立缓冲区,杜绝了页缓存覆写原语。各稳定分支的修复版本如下:
- Linux 6.x:请升级到 6.1.xx、6.6.xx、6.12.xx、6.14.xx 等包含补丁的后续修订版(具体编号以发行版公告为准)。
- 发行版内核:RHEL/CentOS、Debian/Ubuntu、SUSE、Talos Linux 等厂商均已同步修复,应立即升级至安全版本。
对于无法立即升级的环境,可采取以下临时缓解措施:
- 限制 AF_ALG 访问:通过 seccomp、SELinux/AppArmor 或命名空间阻止容器内创建
socket(AF_ALG, ...)。绝大多数容器工作负载不需要直接访问内核加密接口,可默认拒绝。 - 锁定高危可执行文件页缓存:避免将节点关键二进制(如 kube-proxy、CNI、kubelet 调用的 nft/iptables)置于 overlayfs 共享层,改为只读挂载并预载入内存(但该法缓解效果有限,因为页缓存仍可能被覆写)。
- 启用内核页表隔离和 KASLR:不能直接阻止漏洞,但可增加利用复杂度。
- 部署安全监控:监控 AF_ALG 套接字的异常使用(尤其是与
splice()配合),以及是否存在大量 4 字节写入同一页缓存的行为。 - 容器逃逸防御:禁止非特权容器运行特权 pod;审核 DaemonSet 的挂载和镜像来源;使用 Pod Security Admission 强制限制 seccomp 策略。
由于该漏洞已被公开且存在可靠的 PoC(包括纯 C 移植版和 /etc/passwd 变体),任何未打补丁的节点都面临极高的被利用风险。强烈建议在变更窗口内优先完成内核升级,并随后检查节点页缓存完整性(例如通过触发文件重新读取、对比磁盘哈希),以排查是否已被利用。
🧪 PoC 复现
从 GitHub 公开仓库抓取的实际 PoC 代码(仓库)。
📋 代码元数据语言md来源tgies/copy-fail-c针对性✅ 已验证与漏洞相关(代码含 CVE 引用)依赖见代码注释/README用法详见代码注释中的使用说明
# Copy Fail (CVE-2026-31431) - C port
*[English (en)](README.md) ∙ [日本語 (ja)](README.ja.md) ∙ [简体中文 (zh-cn)](README.zh-cn.md) ∙ [한국어 (ko)](README.ko.md) ∙ [Русский (ru)](README.ru.md)*
Copy Fail Linux LPE (CVE-2026-31431) のクロスプラットフォームC言語による再実装です。この脆弱性はTheori / Xintによって2026年4月29日に公開されました。脆弱性の詳細、タイムライン、Theoriによる発見プロセスについては、[copy.fail](https://copy.fail/) の公式レポートを参照してください。
公開されているProof-of-Concept (PoC) は732バイトのPythonスクリプトです。このC言語への移植版は、プロジェクト独自のソース内にアーキテクチャごとの16進数バイナリやインラインアセンブリを含めることなく、nolibcがサポートする任意のアーキテクチャにコンパイル可能なポータブルなC言語として同じエクスプロイトを表現できることを実証しています。
本移植版の作成者: Tony Gies <tony.gies@crashunited.com>
発見および当初の公開: Theori / Xint
## リポジトリ構成
```
copy-fail-c/
├── exploit.c ドロッパー (バイナリ書き換えバリアント)
├── exploit-passwd.c ドロッパー (/etc/passwd UID書き換えバリアント)
├── vulnerable.c 非破壊的な脆弱性チェッカー
├── payload.c ドロップされる本体 (setgid+setuid+execve sh)
├── utils.c,
utils.h AF_ALG/splice ページキャッシュ書き換えプリミティブ (共有)
├── Makefile ビルドのオーケストレーション
├── nolibc/ torvalds/linux の tools/include/nolibc からのベンダーコード
└── README.md このファイル
```
`make` 後:
```
├── payload ドロッパーにバイト列として埋め込まれる小さな静的ELF
├── payload.o `ld -r -b binary` によって再配置可能な .o としてラップされたペイロード
├── exploit ドロッパー、バイナリ書き換えバリアント
├── exploit-passwd ドロッパー、/etc/passwd UID書き換えバリアント
└── vulnerable 非破壊的な脆弱性チェッカー
```
`exploit.c` は対象バイナリを読み取り専用で開き、埋め込まれたペイロードの4バイトのウィンドウごとにAF_ALGを介してダミーのAEAD復号を1回実行します。このときの暗号文入力は、ターゲットのページキャッシュページからsplice()を介して提供されます。authencesnテンプレートのインプレース最適化により、spliceされたソースページは暗号文入力と平文出力先のアドレスの両方として扱われるため、認証検証がリクエストを拒否する頃には、(失敗する)復号によってすでにページキャッシュページが上書きされています。4 * N回の反復後、ターゲットのキャッシュされたイメージはペイロードとバイト単位で完全に置き換えられます。ターゲットをexecve()すると、変異したページがロードされます。ディスク上のinodeは依然としてsetuid rootであるため、カーネルはroot権限を付与し、ペイロードを実行します。
`payload.c` は純粋なポータブルC言語です: `setgid(0);
setuid(0);execve("/bin/sh",
...)`。nolibcは `_start`、システムコール機構、およびアーキテクチャごとのレジスタ操作を提供します。
2番目のバリアントである `exploit-passwd.c` は、setuidバイナリのイメージの代わりに /etc/passwd のページキャッシュの4バイトを書き換えます。埋め込みペイロードを必要とせず、バイナリ書き換えのルートがブロックされているシステムでも機能しますが、キャッシュアウトの(権限昇格を達成する)サーフェスははるかに狭くなります。
`vulnerable.c` はエクスプロイトではありません。文字列 `init` を含むローカルの `testfile` を作成し、そのファイル自身のページキャッシュに対して同じ `patch_chunk()` プリミティブを実行して、バイトを `vulnerable` に上書きしようとします。読み戻したファイル内容が一致すれば、実行中のカーネルは CVE-2026-31431 の影響範囲内です。ディスク上のinodeは変更されません。`testfile` は終了時に削除され、ページキャッシュの書き換えもそれと共に消えます。特権なしで実行できます。終了コードは、脆弱な場合は100、プリミティブは実行できたが書き換えが起きなかった場合は0、AF_ALGソケットファミリまたはauthencesnテンプレートが利用できずパッチ状態を判定できない場合は2、その他の実行時エラーでは1です。
## ビルド
デフォルト (ホストアーキテクチャ向けネイティブ):
```sh
make
```
aarch64 へのクロスコンパイル (またはクロスツールチェーンがインストールされている他のLinuxアーキテクチャ):
```sh
make CC=aarch64-linux-gnu-gcc LD=aarch64-linux-gnu-ld
```
ベンダー化されたnolibcがサポートするアーキテクチャ(アップストリームに準拠): x86_64,
i386,arm,aarch64,riscv32/64,mips,ppc,s390x,loongarch,m68k,sh,sparc。nolibcはコンパイラのアーキテクチャマクロに基づいてディスパッチするため、適切な `CC`/`LD` を選択するだけで十分です。
ビルドの要件:
* Cコンパイラ (`cc`,`gcc` または任意のクロスバリアント)
* `ld -r -b binary` をサポートするリンカー (binutils ld および lld は対応)
* `linux/if_alg.h` と `<asm/unistd.h>` を提供するカーネルUAPIヘッダー (Debian/Ubuntu: `linux-libc-dev`;
クロスバリアント: 通常、クロスツールチェーンパッケージに含まれます)
Linux 5.6 より古いヘッダーセットは、ベンダー化されたnolibcが使用する `__kernel_old_time_t` および `struct __kernel_old_timespec` よりも前のものです。`compat.h` (ペイロードのビルドに強制インクルードされます) は、これらが存在しない場合に提供するため、古い `linux-libc-dev` でも引き続きビルドできます。5.6 以降のヘッダーでは何もしません。
外部ライブラリへの依存関係はありません。ペイロードはnolibcに対してフリースタンディングとしてビルドされます。ドロッパーは `fprintf` と `perror` のためだけにホストのlibcとリンクします。
## アーキテクチャの選択
ソースのポータビリティを維持し、ペイロードを小さく保つために、ツールチェーンのいくつかの小さな機能が大きな役割を果たしています。
### nolibc
`nolibc/` はカーネルの小さなヘッダーオンリーなlibcの代替であり、torvalds/linux の `tools/include/nolibc/` から取り込まれたものです。これは `_start`、ポータブルな `syscall()` マクロ、およびインラインシステムコールラッパーを提供し、アーキテクチャごとのレジスタの規則は `nolibc/arch-*.h` にエンコードされています。`-nostdlib -static -ffreestanding -Inolibc` でペイロードをビルドすると、glibcのスタートアップ、TLSの初期化、またはスタックカナリアの仕組みを組み込むことなく、直接カーネルを呼び出す小さな静的ELFが生成されます。結果: パックおよびセクションヘッダーの削除後 (いずれも後述)、x86_64で約720バイト、aarch64で約1.2 KBになります。同じ `payload.c` をmusl-staticでリンクすると約17 KB、glibc-staticでは約700 KBになります。
### 埋め込み用の `ld -r -b binary`
Makefileは `ld -r -b binary -o payload.o payload` を介して、ビルドされた `payload` ELFを `payload.o` に変換します。リンカーは入力バイトを再配置可能なオブジェクトファイルのデータセクションとしてそのまま出力し、入力ファイル名から3つのシンボルを合成します。
```
_binary_payload_start 最初のペイロードバイトのアドレス
_binary_payload_end 最後のペイロードバイトの1つ後のアドレス
_binary_payload_size 絶対シンボル(値はバイト単位のサイズ)
```
`exploit.c` は最初の2つを `extern const unsigned char[]` として宣言し、サイズを `_binary_payload_end - _binary_payload_start` として計算します。
### `-Wl,-N` と厳しい `max-page-size`
ペイロードは `-Wl,-N -Wl,-z,max-page-size=0x10` で静的リンクされます。これにより、カーネルのページ境界に合わせたセグメントあたり4 KBのデフォルトの代わりに、16バイトのファイルアラインメントで `.text`/`.rodata`/`.data` が単一のLOADセグメントにまとめられます。これにより `ld` から「RWX permissions」の警告が出ますが、これは情報提供のみです。ペイロードの実行時メモリ保護は、この単一目的のプログラムにとって重要ではありません。このフラグがない場合、同じコードはx86_64で約13 KB(大部分はセグメント間のゼロパディング)にリンクされますが、これを使用すると、後述のセクションヘッダー削除前で約1.3 KBになります。
### セクションヘッダーの削除
リンク後、`objcopy --strip-section-headers` はペイロードのセクションヘッダーテーブルと `.shstrtab` を削除します。カーネルのELFローダーはプログラムをそのプログラムヘッダーのみからマップするため、これらのバイトは実行時にはロードされませんが、`payload` はそのまま埋め込まれるため、ドロップと `patch_chunk` の反復回数を増大させます。これらを削除すると、x86_64のペイロードは約1.3 KBから720バイトになります(322回の4バイト反復が180回に減少)。2つのリンク時フラグが残りを削ります: `-Wl,--build-id=none` はbuild-idノートを削除し、`-fcf-protection=none` はコンパイラがサポートしている場合にx86のCETノートを削除します。
この削除には binutils >= 2.40 が必要です。クロスビルドでは `OBJCOPY=` を介してターゲットのobjcopyを渡します (例: `OBJCOPY=aarch64-linux-gnu-objcopy`)。objcopyが削除を実行できない場合、ビルドは注意メッセージを表示し、有効でより大きなペイロードを保持します。
## バリアントとキャッシュアウトの実現可能性
このリポジトリは、AF_ALG/splice ページキャッシュの書き換えプリミティブを共有しつつ、異なる方法でroot実行にキャッシュアウト(権限昇格を達成)する2つのエクスプロイトバリアントを提供しています。それらの信頼性プロファイルは同等ではなく、現実世界の脅威モデルを推論する際にこの違いが重要になります。
### バイナリ書き換えバリアント (`exploit`)
ターゲットのsetuidバイナリのページキャッシュを埋め込まれたペイロードバイトで書き換え、バイナリをexecします。カーネルは、バイナリのディスク上の変更されていないsetuidビットからroot権限を付与し、メモリ上の破損したイメージをロードして、ペイロードを実行します。
攻撃者がシステム上の任意のroot-setuidバイナリに対して `open(target,
O_RDONLY)` できる場所であればどこでも機能します。制限された読み取りディレクトリの背後にあるsetuidバイナリの環境や、setuidを使用しないシステム設計によっておおむね防御されます。
### /etc/passwd UID書き換えバリアント (`exploit-passwd`)
/etc/passwd のページキャッシュの4バイトを書き換えて、実行中のユーザーのUIDフィールドを "0000" に設定します。/etc/passwd はすべての標準的なLinuxシステムで誰でも読み取り可能であるため、*書き換え* 自体は普遍的です。これをroot実行に変換するには、root側のプロセスが getpwnam/getpwuid を介してユーザーを解決し、クロスチェックを行わずに解決されたuidに基づいて行動することに依存します。そのようなコンシューマーは多く存在しますが、その多くは呼び出し元のuidに対するカーネルのビューや、ディスク上のファイルの所有権と防衛的なクロスチェックを行うため、キャッシュアウトが機能しなくなります。
#### キャッシュアウト実現可能性マトリックス
|
キャッシュアウト |事前のroot設定の必要性 |備考 ||---|---|---||WSL2 セッションのスポーン |なし |WSLのセッションごとの `setuid(getpwnam(default_user)->pw_uid)` は検証を行いません。クリーンに動作します。 ||util-linux `su` |なし |呼び出し元の識別処理が寛容です。 ||shadow-utils `su` |あり |`getpwuid(getuid())` 呼び出し元の識別チェックは、書き換えによって実際のuidがマッピングされなくなるため失敗します。 ||sshd (デフォルト `StrictModes yes`) |あり (StrictModes の無効化) |
StrictModes はホームディレクトリが root または `pw->pw_uid` に所有されていることを要求します。書き換えにより pw_uid=0 になりますが、ディスク上の所有者は元のuidのままです。不一致のため認証が拒否されます。 ||MTA ローカル配信 (postfix,exim など) |変動あり |MDAのホーム権限検証に依存します。MTAごとのテストが必要です。 |
#### `su` 失敗後のピボット
`exploit-passwd` は書き換え後に最も単純なキャッシュアウトとして `su <user>` をexecします。これは util-linux の `su` に対しては機能しますが、shadow-utils の `su` に対しては "Cannot determine your user name." で失敗します。この時点でもページキャッシュの書き換えは有効であり、他のキャッシュアウト(例: クロスチェックなしで getpwnam を介してユーザーを解決するデーモンを使用する)へのピボットは可能です。
テスト完了後に破損したページキャッシュをクリアするには、rootとして `echo 3 >
/proc/sys/vm/drop_caches` を実行してください。
## 影響を受けるカーネル
```
下限: torvalds/linux 72548b093ee3 2017年8月,v4.14
(AEADスキャッターリストへのspliceを介した
ファイルページ書き込みプリミティブを
導入したAF_ALG iov_iterの再構築)
上限: torvalds/linux a664bf3d603d 2026年4月,
メインライン
(2017年のalgif_aeadインプレース最適化を元に戻す;
ソースと宛先のスキャッターリストを分離し、
ページキャッシュページが書き込み可能な
暗号化の宛先にならないようにした)
```
この間の期間: 修正をバックポートしなかったすべての主要なディストリビューションカーネル。
Ubuntu、RHEL、SUSE、Amazon Linux、およびDebianはすべて、情報公開時にストッククラウドイメージカーネルで脆弱性が確認されていました。ディストリビューションレベルのバックポートは、一般公開と並行して2026年4月29日頃から展開され始めました。ターゲットカーネルが該当期間内にあるかどうかを確認するには、カーネルのgitログまたはディストリビューションのチェンジログに `a664bf3d603d` (またはそのディストリビューション固有のバックポート) が存在するかどうかを確認してください。
## 商用サポート
有償のセキュリティレビュー、カスタム移植、非公開のセキュリティアドバイザリについては、作成者のコンサルティング会社である Crash United,
LLC を通じてお問い合わせください。
連絡先: tony.gies@crashunited.com · https://crashunited.com
GitHub: [@tgies](https://github.com/tgies) · X/Twitter: [@me_irl](https://x.com/me_irl)
## ライセンスとクレジット
CVE-2026-31431の発見と当初の公開: Theori / Xint
公式レポート: <https://copy.fail/>本C移植版: Tony Gies <tony.gies@crashunited.com>
`nolibc/`: Linuxカーネルツリーからのベンダーコード、デュアルライセンス
LGPL-2.1-or-later または MIT (`nolibc/nolibc.h` および各ファイルのSPDXヘッダーを参照)。
このリポジトリのドロッパーおよびペイロードのソースは、依存するnolibcツリーと同じLGPL-2.1-or-later または MIT のデュアルライセンス条項の下でリリースされています。これは、このディレクトリ全体を自分の作業環境に取り込むユーザーに対してライセンスの互換性を容易に維持するためです。
エクスプロイトとペイロードは、セキュリティ研究および防衛的な検出の目的で公開されています。所有していない、または明示的なテストの許可を得ていないシステムに対する使用は、作成者ではなくあなた自身の責任です。⚔️ EXP 利用代码
截至分析时,Exploit-DB 未收录该 CVE 的公开利用代码。可利用上述 PoC 进行验证,或关注 Exploit-DB 更新。
🕵️ 检测指纹
针对该 CVE 的自动化检测规则(可直接用于扫描与审计)。
🛡️ Semgrep 审计规则: CVE-2026-31431.yaml
📋 代码元数据语言yaml来源rules/semgrep/CVE-2026-31431.yaml针对性✅ 按 CVE 匹配依赖semgrep用法semgrep --config CVE-2026-31431.yaml
rules:
- id: CVE-2026-31431-rce-go
languages:
- go
severity: ERROR
message: "Potential page cache corruption via AF_ALG and splice() leading to local privilege escalation. Avoid direct usage of AF_ALG sockets with splice() on file page-cache pages."
patterns:
- pattern: |syscall.Splice($R,nil,$W,nil,$N,0)
fix: |
// Avoid using splice() with AF_ALG sockets on file-backed pages.
// Use safe I/O operations like io.Copy instead of splice.
metadata:
cwe: "CWE-277"
owasp: "A5: Broken Access Control"
technology: talos
references:
- "https://github.com/advisories/GHSA-m38g-vww2-mvgx"
- id: CVE-2026-31431-rce-go-alg
languages:
- go
severity: ERROR
message: "Potential page cache corruption via AF_ALG and splice() leading to local privilege escalation. Avoid direct usage of AF_ALG sockets with splice() on file page-cache pages."
patterns:
- pattern: |
syscall.Splice($R,nil,$W,nil,$N,0)
fix: |// Avoid using splice() with AF_ALG sockets on file-backed pages.
// Use safe I/O operations like io.Copy instead of splice.
metadata:
cwe: "CWE-277"
owasp: "A5: Broken Access Control"
technology: talos
references:
- "https://github.com/advisories/GHSA-m38g-vww2-mvgx"🛡️ CodeQL 审计规则: CVE-2026-31431.ql
📋 代码元数据语言ql来源rules/codeql/CVE-2026-31431.ql针对性✅ 按 CVE 匹配依赖codeql用法codeql database run
/**
* @kind path-problem
* @id go/command-injection/cve-2026-31431
* @name Unsafe splice() in AF_ALG leading to arbitrary code execution via nftables
* @description Untrusted workload using AF_ALG and splice() can corrupt page-cache pages,
leading to arbitrary code execution in kube-proxy via nft binary poisoning
* @problem.severity error
* @tags security
* external/cwe/cwe-078
*/
import go
import semmle.go.security.dataflow.CommandInjectionCustomizations
import CommandInjectionFlow::PathGraph
/**
* A source of untrusted input from inside a container (workload)
*/
class WorkloadSource extends DataFlow::Node {
WorkloadSource() {// Environment variables,command line arguments,network input,etc.
any(DataFlow::Node src).(RemoteFlowSource) = src
or
// Any input received via AF_ALG socket from the container
exists(FileReadAccess f |f.getFile().getAbsolutePath().matches("%/proc/%/fd/%"))
}}
/**
* A sink that represents the splice() system call on AF_ALG socket
* which can corrupt page-cache pages
*/
class SpliceAlgSink extends DataFlow::Node {SpliceAlgSink() {exists(FunctionCall fc |fc.getTarget().getName() = "splice" and
fc.getAnArgument().(DataFlow::Node).asExpr().getType().(PointerType).getBaseType().getName() = "alg_socket"
)
}}
/**
* Sink for nft execution which can be poisoned via page-cache corruption
*/
class NftExecutionSink extends DataFlow::Node {NftExecutionSink() {exists(FunctionCall fc |
fc.getTarget().getName() = "exec" or
fc.getTarget().getName() = "execve" or
fc.getTarget().getName() = "syscall.Exec"
) and
fc.getAnArgument().(DataFlow::Node).asExpr().(StringLiteral).getValue().matches("*/nft*")
}}class PoC_CommandInjectionConfig extends TaintTracking::Configuration {PoC_CommandInjectionConfig() {this = "PoC_CommandInjectionConfig" }
override predicate isSource(DataFlow::Node source) {source instanceof WorkloadSource
}override predicate isSink(DataFlow::Node sink) {sink instanceof SpliceAlgSink or
sink instanceof NftExecutionSink
}}from PoC_CommandInjectionConfig cfg,DataFlow::PathNode source,DataFlow::PathNode sink
where cfg.hasFlowPath(source,sink)
select sink.getNode(),source,sink,
"Untrusted workload data flows to splice() or nft execution,enabling page-cache corruption and privilege escalation"🤖 本文由漏洞情报系统自动聚合生成 · 2026-08-02 08:33 · 数据源: NVD/GitHub-Advisory/OSV/CISA-KEV/Exploit-DB/PoC-in-GitHub + 检测规则库