🎯 CVE-2026-31431 深度技术分析:漏洞根因 · PoC/EXP · 检测指纹

🎯 CVE 全聚合深度分析

CVE-2026-31431 深度技术分析

📊 聚合 8 来源🧪 含 PoC🕵️ 含指纹
NVD-LatestGitHub-AdvisoryPoC-in-GitHubExploit-DB-RSSOrca Security

摘要:CVE-2026-31431 是 Linux 内核 crypto/algif_aead 子系统中的一个高危漏洞,CVSS 评分为 7.8。该漏洞源于 AEAD 接口错误地启用了“就地(in-place)”操作路径,允许攻击者借助 AF_ALG 套接字与 splice() 机制,以无特权容器内的工作负载身份,覆盖任意文件的页缓存(page-cache)。在 Talos Linux 环境中,该漏洞可被进一步利用为完整节点提权链:无需任何 Kubernetes 高级权限即可在主机上执行任意 root 代码、读取包含节点机密的宿主机文件系统。本报告对该漏洞的技术根因、实际危害与修复缓解策略进行深度分析。

📌 漏洞概述

CVE-2026-31431 由 NVD 收录,评分为 CVSS 7.8(HIGH),属于 Linux 内核 crypto 子系统中 algif_aead 模块的“Copy Fail”漏洞。该漏洞影响配置了 AF_ALG 密码学接口(通常随 CONFIG_CRYPTO_USER_API 启用)的内核。漏洞类型可归类为“访问控制不当(CWE-284)”或“对只读页面的写入(相当于任意地址写)”。

根据官方修复描述,问题源于一个名为 72548b093ee3 的提交引入了在 algif_aead 中“就地”操作的逻辑,而该逻辑并未正确处理源页面与目标页面来自不同映射的语义。Linux 内核官方修复决定“回退到非就地(out-of-place)操作”,并仅保留关联数据(AD)的复制操作,同时移除所有就地优化带来的额外复杂度。这一修复说明就地操作的存在是导致安全漏洞的核心原因。

该漏洞影响所有启用了 AF_ALG 且包含问题提交的内核版本,尤其是 Talos Linux(Siderolabs )中的受影响内核。GitHub Advisory GHSA-m38g-vww2-mvgx 确认了其危害性:攻击者只需能够在工作节点上调度一个 Pod,即可在宿主机上实现任意代码执行。截至本报告发布时,CISA KEV 尚未收录该漏洞,表明尚未观察到国家级利用,但公开的 PoC 与详细分析已经出现。

🔬 漏洞根因分析

要理解该漏洞,需要深入分析 algif_aeadsplice() 的交互过程。AF_ALG 是 Linux 内核提供的密码学用户态接口,允许用户程序通过套接字执行对称加密、AEAD 解密等操作。正常的 AEAD 操作中,用户程序通过 sendmsg() 传入密文和关联数据(AAD),AAD 在套接字缓存中保存,而密文默认从用户空间缓冲区复制到内核临时缓冲区;随后密码学引擎在临时缓冲区上执行解密,再将结果复制回用户空间。这一传统的“非就地”流程虽然性能略低,但安全上没有问题。

为优化性能,内核提交 72548b093ee3 引入了就地操作支持。其基本假设是:当用户传入的密文缓冲区与接收结果缓冲区在物理上指向同一页面时,可以省略一次内存拷贝,让密码学引擎直接对该页面进行原地改写。然而 algif_aead 的接口设计中,源(密文)和目的(明文)在绝大多数情况下来自不同的用户映射,就地操作并无明显收益。但更致命的是,该优化与 splice() 机制结合时产生了严重的安全问题。

利用方式如下:攻击者使用 splice() 将一个只读文件(如 /usr/sbin/nft/etc/passwd)的页缓存页面直接作为 AF_ALG 套接字的输入,而不是通过 copy_from_user 复制。此时内核获得的是该文件页缓存页面的物理页引用。由于此前启用了就地操作,密码学引擎会将输出页面指针设置为与输入页面相同。也就是说,解密操作将直接对该页缓存页面进行写入。

AEAD 解密的典型流程是:先对密文进行解密生成明文,再基于解密后的明文与 AAD 计算认证标签,并与输入的标签比对。如果标签不匹配,则解密操作返回错误(-EBADMSG)。但在很多 AEAD 实现中,明文在认证失败之前就已经被生成并写入输出缓冲区。即便最终认证失败、请求被拒绝,那一次“失败”的解密结果也已经残留在输出页面中。正常接口下,用户得到的输出缓冲区是可写内存,所以残留结果无关紧要;但当输出缓冲区指向只读文件的页缓存页面时,攻击者就利用了这个副作用,将一个 4 字节窗口的“密文”解密为可控的伪随机数据,并写入目标文件的页缓存。

结合公开 PoC 的细节:每次攻击读取目标二进制中的 4 字节,将其作为 AEAD 密文输入的一部分,通过精心构造的密钥和 AAD,使得解密输出的 4 字节被替换为攻击者想要写入的 payload 片段。由于输入来自页缓存,输出同样写到该页缓存,这实际上构成了一种“任意文件页缓存写”原语。经过 4×N 次迭代(N 为目标文件长度),攻击者可以将整个目标文件的页缓存映像替换为恶意 payload(如一个 setuid shell 启动器)。当宿主机上的特权进程执行该文件时,内核会从页缓存加载已篡改的内容,而磁盘上的 inode 依然是原始 setuid root 文件,因此进程将获得 root 权限,执行 payload。

从根因上讲,漏洞不是 AEAD 算法的数学缺陷,而是内核在 AF_ALG 接口中错误地允许了“对来自只读映射的页面进行就地写入”。更具体地说,algif_aead 的就地优化没有区分页面是否可写、是否属于用户私有临时缓冲区,而是假定只要 SG 列表中的源和目的相同,就可以安全地原地操作。当源页面来自页缓存时,内核赋予了用户态不可直接获得的物理页写入能力,违反了页缓存只读映射的安全边界。官方补丁移除了就地操作,回归到常规的“先复制到临时缓冲区,再解密,再复制出去”模型,从而彻底消除了对任意页缓存页面的写入能力。

💥 影响与危害

该漏洞最大的影响在于,它允许无特权的容器工作负载绕过内核内存保护,修改宿主机上任意文件的页缓存内容。由于页缓存是磁盘文件在内存中的映像,即使磁盘文件不可写(如只读的 setuid 二进制、系统命令、配置文件),攻击者也能通过页缓存污染来改变程序在下次执行时的行为。

在典型的 Kubernetes 环境中,攻击者只需拥有在 worker 节点上创建 Pod 的能力(任何被允许部署应用的用户都具备),无需任何其他权限。攻击步骤通常包括:

  • 本地页缓存污染:针对宿主机上某个将被特权执行的二进制文件,例如 /usr/sbin/nft(被 kube-proxy 等 DaemonSet 调用)或 CNI(容器网络接口)插件二进制。通过 splice() + AF_ALG 的页面缓存写入原语,将该文件的页缓存映像替换为攻击者构造的 payload。
  • 提权触发:等待特权 Pod(如 kube-proxy)或宿主机组件执行该文件时,由于页缓存已被污染,内核加载的是恶意代码。文件 inode 的属主与权限未变,仍然是 root 拥有且带 setuid 位(如果是 setuid 二进制),所以内核授予了该进程 root 权限。
  • 节点接管:恶意代码以 root 身份运行,攻击者从而获得宿主机全文件系统访问权,可读取节点机密(Kubernetes secret)、挂载主机路径、修改网络规则、部署持久化后门等。

除了攻击宿主机文件,攻击者还可以攻击 /etc/passwd 的页缓存,将某个用户的 UID 改写为 0,然后通过登录或 su 获得 root shell。PoC 提供了两种模式:一是替换可执行文件的内容,二是篡改 /etc/passwd,均能达到本地提权目的。

该漏洞没有已知的 CISA KEV 收录,但由于其利用不需要明显的竞争条件、不需要内核调试接口,且公开的 Python 脚本 PoC 只有 732 字节,实际攻击门槛极低。在 Talos Linux 等容器优化操作系统中,由于默认带有 AF_ALG 且允许非特权容器访问该接口(旧版本中未施加限制),漏洞被成功利用的概率很高。影响等级被评估为“HIGH”,从容器逃逸到节点完全沦陷的完整攻击链已经得到验证。

🛡️ 修复与缓解

内核补丁:Linux 内核开发团队已通过提交“crypto: algif_aead - Revert to operating out-of-place”修复该问题。该补丁主要回退之前引入的就地操作功能,恢复为非就地模式:所有密文输入先复制到独立的临时缓冲区,解密后的明文也写入独立的目标缓冲区,再通过套接字返回给用户。同时保留关联数据(AD)的复制逻辑,但移除了所有就地优化中复杂的 SG 列表共享处理。受影响的内核版本用户应尽快更新至包含以下提交的版本:crypto: algif_aead - Revert to operating out-of-place(补丁哈希尚未在公开资料中列出,具体版本请参考各发行版安全公告)。对于 Talos Linux,Siderolabs 已在 GHSA-m38g-vww2-mvgx 中发布了修复版本和缓解指引,使用 Talos 的用户应立即升级到修复后的版本。

缓解措施:

  • 限制 AF_ALG 套接字访问:在容器运行时或 seccomp 策略中禁用 socket(AF_ALG, ...) 系统调用,阻止非特权容器使用内核密码学接口。可通过 seccomp profile 添加对 socket 的第二个参数(AF_ALG)的拦截。
  • 加强 Kubernetes Pod 安全策略:不允许不受信任的 Pod 在节点上直接运行;对于必须运行的工作负载,使用 restricted Pod Security Standards,并限制其访问宿主敏感路径。
  • 更新容器运行时与操作系统镜像:及时应用 Talos Linux 的安全更新;对于通用发行版,升级内核至包含回退补丁的版本。
  • 监控可疑的 splice()AF_ALG 组合行为:在宿主机上启用审计或 eBPF 监控,检测非特权进程通过 splice()AF_ALG 套接字传输文件页缓存的行为,及时发现利用尝试。
  • 尽量将关键二进制放在不可变文件系统或使用 dm-verity:由于该漏洞针对页缓存,若权限校验层能检测文件内容与磁盘不符(如完整性校验),则可降低实际利用风险,但这属于纵深防御,不能替代内核补丁。

总之,CVE-2026-31431 是一个非常典型的“性能优化引入安全边界漏洞”的案例。它再次提醒内核开发者,任何试图绕过内存拷贝的优化都必须仔细验证源页面的权限和生命周期。对于系统管理员,及时升级内核、收紧 AF_ALG 接口的暴露是当务之急。

🧪 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-06 07:07 · 数据源: NVD/GitHub-Advisory/OSV/CISA-KEV/Exploit-DB/PoC-in-GitHub + 检测规则库

[!] CONTACT_CHANNELS

如需商务合作、技术咨询或漏洞反馈,请通过以下离岸节点联系作者。

> PING_AUTHOR (@A1RedTeam)