
تحليل استنساخ CVE-2026-31431، وexp مُكيَّف بلغة 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 # 正确且带注释,便于理解
ثلاثة إيداعات غير ضارة كلٌّ على حدة، أنتجت عند دمجها ثغرة:
splice(文件 → pipe → AF_ALG)
↓
af_alg_sendmsg: 文件页缓存页 → TX SGL (零拷贝)
↓
_aead_recvmsg: in-place 优化
├─ memcpy_sglist: AAD+密文拷贝到 RX SGL
├─ sg_chain: tag 页(仍指向文件页缓存)链入 RX SGL
└─ req->src = req->dst (= 含文件页缓存页的 scatterlist)
↓
crypto_authenc_esn_decrypt: ESN 重排列
└─ scatterwalk_map_and_copy(tmp+1, dst, assoclen+cryptlen, 4, 1)
↓ 在 dst scatterlist 中遍历到 tag 位置
↓ kmap_local_page() 映射文件页缓存页
↓ memcpy: 将 seqno_lo 写入文件页缓存页
↓
HMAC 验证失败 → 返回 -EBADMSG
↓
文件页缓存页已被修改,内核未标记脏页,磁盘文件不变
تدّعي الورقة البحثية أن "جميع توزيعات Linux تقريبًا" متأثرة منذ عام 2017. وتُشارك page cache عبر الحاويات، لذا فإن هذه الثغرة تُعد ناقلًا لرفع الامتيازات محليًا (LPE) وناقلًا للهروب من الحاويات في آنٍ واحد.
إيداع الإصلاح في النواة الرئيسية a664bf3d603d يعيد عمليات AEAD في AF_ALG إلى وضع out-of-place (فصل src و dst):
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)
رسالة الإيداع: "There is no benefit in operating in-place in algif_aead since the source and destination come from different mappings."
إجراءات التخفيف الطارئة:
echo "install algif_aead /bin/false" > /etc/modprobe.d/disable-algif-aead.conf
rmmod algif_aead
أو منع إنشاء مقابس AF_ALG عبر سياسة seccomp (socket(AF_ALG, ...)).
| الوقت | الإيداع | التأثير |
|---|
| 2011 | a5079d084f8b | تمت إضافة authencesn، باستخدام dst scatterlist كمساحة مؤقتة لإعادة ترتيب ESN. كان غير ضار في ذلك الوقت — لأن واجهة AEAD القديمة أبقت AAD منفصلة، وكان المستدعي الوحيد هو xfrm في النواة. |
| 2015 | 104880a6b470 | تم تحويل authencesn إلى واجهة AEAD الجديدة، مما أدخل سلوك "تجاوز حد الإخراج" بكتابة seqno_lo عند assoclen+cryptlen. لا يزال غير قابل للاستغلال — لأن AF_ALG يستخدم وضع out-of-place، بحيث يكون req->src و req->dst منفصلين، وصفحات page cache موجودة فقط في src للقراءة فقط. |
| 2017 | 72548b093ee3 | تحسين in-place في AF_ALG. نسخ AAD والنص المشفر من TX SGL إلى RX buffer، مع ربط صفحة tag عبر sg_chain. تعيين req->src = req->dst. الآن، أصبحت صفحات page cache المُدخلة عبر splice موجودة أيضًا في dst scatterlist القابل للكتابة. تشكّلت الثغرة. |
| التوزيعة | إصدار النواة | متأثر |
|---|
| Ubuntu 24.04 LTS | 6.17.0-1007-aws | نعم |
| Amazon Linux 2023 | 6.18.8-9.213.amzn2023 | نعم |
| RHEL 10.1 | 6.12.0-124.45.1.el10_1 | نعم |
| SUSE 16 | 6.12.0-160000.9-default | نعم |
| الخاصية | التحقق من الكود المصدري | الوصف |
|---|
| authencesn يكتب seqno_lo إلى النهاية | authencesn.c:134 | ما يُكتب عند assoclen+cryptlen هو seqno_lo (الـ 32 بت المنخفضة). وصف المستخدم صحيح. |
| اصطلاح إعادة ترتيب ESN | تأكيد المدونة (xint.io) | البايتات 0-3 من AAD = seqno_hi، والبايتات 4-7 = seqno_lo. يُكتب tmp[1] (= البايتات 4-7 = seqno_lo) إلى النهاية. |
| مسار فك التشفير لا يستعيد البايتات المستبدلة | authencesn.c:270-273 vs 215-217 | يستعيد decrypt_tail ESN عند الإزاحة 0-7 لكنه لا يستعيد أبدًا البايتات الأصلية عند assoclen+cryptlen. أما مسار التشفير (genicv_tail) فيستعيدها قبل كتابة ICV. |
| التشفير وفك التشفير في المكان في AF_ALG | algif_aead.c:189-252 | يشير rsgl_src و areq->first_rsgl.sgl.sgt.sgl إلى نفس RX SGL. |
| ربط صفحة tag في AF_ALG | algif_aead.c:238-244 | أثناء فك التشفير، تتم الإشارة إلى tag عبر sg_chain بدلاً من نسخه — وفي سيناريو splice تظل صفحة tag تشير إلى صفحة page cache للملف. السبب الجذري للثغرة الأمنية. |
| نقل splice بدون نسخ (Zero-copy) | fs/splice.c:876, af_alg.c:1049, lib/scatterlist.c:1167 | يشير مباشرة إلى صفحة الأنبوب (pipe page)، بدون نسخ. |
| CVE-2026-31431 | سلسلة من ثلاثة إيداعات | authencesn (2011/2015) + in-place (2017) + splice بدون نسخ = بدائية كتابة قابلة للتحكم في page cache. |