ð¥ CVE-2026-31431 深床ç¬ç«ç ç©¶ïŒæºç 审计 · äºæ¬¡åç° Â· å©ç𿹿¡
CVE-2026-31431 深床ç¬ç«ç ç©¶ïŒæºç 审计 · äºæ¬¡åç° Â· å©ç𿹿¡
ð æºç ç¬ç«å®¡è®¡
对 https://github.com/theori-io/copy-fail-CVE-2026-31431 æºç è¿è¡ç¬ç«å®¡è®¡ïŒçœ®ä¿¡åºŠ 0%ïŒã
ð§¬ æ ¹å ç¬ç«çè§£
ïŒå®¡è®¡è§£æå€±èŽ¥ïŒ
ð€ïž æŒæŽè§ŠåéŸè·¯
𧪠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 21:31