
Analisi di riproduzione per CVE-2026-31431, exp adattato in C.
.
├── container
│ ├── container.md # 容器逃逸的思路
│ ├── expenv # 容器环境
│ │ ├── bin
│ │ │ ├── gscontainer
│ │ │ └── share
│ │ ├── Dockerfile
│ │ ├── run.sh
│ │ └── src
│ │ ├── gscontainer.c
│ │ └── share.c
│ ├── images
│ │ ├── container.png
│ │ ├── getshell.png
│ │ ├── host.png
│ │ ├── payload.png
│ │ └── share.png
│ ├── recode.bin # 单阶段的 shellcode
│ └── stager
│ ├── shell.elf # 内嵌在exp当中的分阶段 shellcode
│ ├── stager1.bin
│ ├── stager2.bin
│ ├── stager3.bin
│ └── stager4.bin
├── doc
│ ├── cve-2026-31431.md # xint.io 分析总结
│ └── shellcode.md # 介绍什么是 shellcode
├── exp.py # curl http://copy.fail/exp -o exp.py
├── README.md
├── success
│ ├── code.py # exp.py 提取的 shellcode
│ └── exploit.c # C 语言精简的 exp,当中有原生的 msf 提权的 shellcode,需要自己免杀
└── test
├── exptest.c # 清除注释
└── test.c # 正确且带注释,便于理解
Tre commit singolarmente innocui, combinati, hanno prodotto la vulnerabilità:
splice(file → pipe → AF_ALG)
↓
af_alg_sendmsg: pagine cache di pagina del file → TX SGL (copia zero)
↓
_aead_recvmsg: ottimizzazione in-place
├─ memcpy_sglist: copia AAD+ciphertext nel RX SGL
├─ sg_chain: la pagina del tag (ancora puntata alla cache di pagina del file) viene concatenata nel RX SGL
└─ req->src = req->dst (= scatterlist contenente le pagine cache di pagina del file)
↓
crypto_authenc_esn_decrypt: riordinamento ESN
└─ scatterwalk_map_and_copy(tmp+1, dst, assoclen+cryptlen, 4, 1)
↓ attraversa il dst scatterlist fino alla posizione del tag
↓ kmap_local_page() mappa la pagina cache di pagina del file
↓ memcpy: scrive seqno_lo nella pagina cache di pagina del file
↓
Verifica HMAC fallita → restituisce -EBADMSG
↓
La pagina cache di pagina del file è stata modificata, il kernel non ha marcato la pagina come sporca, il file su disco rimane invariato
L'articolo afferma che "quasi tutte le distribuzioni Linux" dal 2017 sono colpite. La cache di pagina è condivisa tra i contenitori, quindi questa vulnerabilità è sia un vettore di escalation locale (LPE) che di fuga dal contenitore.
Il commit di correzione nel kernel principale a664bf3d603d riporta le operazioni AEAD di AF_ALG alla modalità out-of-place (src e dst separati):
Before: aead_request_set_crypt(..., rsgl_src,
areq->first_rsgl.sgl.sgt.sgl, ...)
^ src == dst ^
After: aead_request_set_crypt(..., tsgl_src,
areq->first_rsgl.sgl.sgt.sgl, ...)
^ src ≠ dst ^ (TX SGL for src, RX SGL for dst)
Messaggio del commit: "Non c'è alcun vantaggio nell'operare in-place in algif_aead poiché la sorgente e la destinazione provengono da mapping diversi."
Misure di mitigazione di emergenza:
echo "install algif_aead /bin/false" > /etc/modprobe.d/disable-algif-aead.conf
rmmod algif_aead
Oppure tramite una politica seccomp che blocchi la creazione di socket AF_ALG (socket(AF_ALG, ...)).
| Tempo | Commit | Impatto |
|---|
| 2011 | a5079d084f8b | authencesn è stato aggiunto, utilizzando la dst scatterlist come spazio temporaneo per il riordinamento ESN. Innocuo a questo punto — poiché la vecchia interfaccia AEAD manteneva AAD separato, e l'unico chiamante era lo xfrm del kernel. |
| 2015 | 104880a6b470 | authencesn è stato convertito alla nuova interfaccia AEAD, introducendo il comportamento di "scrivere oltre il limite di output" a assoclen+cryptlen per seqno_lo. Ancora non sfruttabile — poiché AF_ALG usava la modalità out-of-place, req->src e req->dst erano separati, e le pagine della cache di pagina erano solo nella sorgente di sola lettura. |
| 2017 | 72548b093ee3 | Ottimizzazione in-place di AF_ALG. Copia AAD+ciphertext dal TX SGL al buffer RX, ma concatena la pagina del tag tramite sg_chain. Imposta req->src = req->dst. Ora le pagine della cache di pagina introdotte da splice si trovano anche nel dst scatterlist scrivibile. La vulnerabilità si forma. |
| Distribuzione | Versione del kernel | Colpito |
|---|
| Ubuntu 24.04 LTS | 6.17.0-1007-aws | Sì |
| Amazon Linux 2023 | 6.18.8-9.213.amzn2023 | Sì |
| RHEL 10.1 | 6.12.0-124.45.1.el10_1 | Sì |
| SUSE 16 | 6.12.0-160000.9-default | Sì |
| Caratteristica | Verifica del codice sorgente | Descrizione |
|---|
| authencesn scrive seqno_lo alla fine | authencesn.c:134 | Scrive seqno_lo (32 bit inferiori) a assoclen+cryptlen. Descrizione utente corretta. |
| Convenzione di riordinamento ESN | Confermato dal blog (xint.io) | AAD bytes 0-3 = seqno_hi, bytes 4-7 = seqno_lo. tmp[1] (=bytes 4-7=seqno_lo) viene scritto alla fine. |
| Il percorso di decrittazione non ripristina i byte sovrascritti | authencesn.c:270-273 vs 215-217 | decrypt_tail ripristina ESN all'offset 0-7 ma non ripristina mai i byte originali a assoclen+cryptlen. Il percorso di crittografia (genicv_tail) invece ripristina prima di scrivere ICV. |
| Crittografia/decrittografia in-place di AF_ALG | algif_aead.c:189-252 | rsgl_src punta allo stesso RX SGL di areq->first_rsgl.sgl.sgt.sgl. |
| Concatenamento del tag in AF_ALG | algif_aead.c:238-244 | In decrittazione, il tag è referenziato tramite sg_chain anziché copiato — nello scenario splice, la pagina del tag punta ancora alla cache di pagina del file. Causa principale della vulnerabilità di sicurezza. |
| Trasferimento a copia zero con splice | fs/splice.c:876, af_alg.c:1049, lib/scatterlist.c:1167 | Riferisce direttamente la pagina della pipe, copia zero. |
| CVE-2026-31431 | Tre catene di commit | authencesn(2011/2015) + in-place(2017) + splice a copia zero = primitiva di scrittura controllabile nella cache di pagina. |