سلام به همگی. اخیرا یک آسیب پذیری بسیار مهم (CVE-2026-31431) در لینوکس گزارش شده که عملا اگر شما هر سرور لینوکسی ای که داشته باشید باید kernel تون رو آپدیت کنید. حالا این آسیب پذیری چی هست؟

اگر به طور خلاصه بگم شما با هر یوزری که تو لینوکس لاگین کردید میتونید تبدیل به یوزر root بشید :) . جالبه که این مورد امنیتی از سال 2017 بوده تو کرنل و خدا میدونه چنیدن نفر از این راه سوء استفاده کردن و issue نکردنش. ولی الان بعد از گذشت نزدیک به 9 سال این آسیب پذیری پیدا شده و تو بسیاری از Distro ها حل شده. فقط نیازه که شما ورژن کرنلتون رو آپدیت کنید تا همه چی گل و بلبل بشه.
خب بیایین در مورد آسیب پذیری به صورت فنی صحبت کنیم.
تو کرنل لینوکس ما یک قابلیت خفن داریم به اسم AF_ALG. این قابلیت به برنامه های User Space اجازه میده بدون اینکه تو دردسر بیفتن تو دل سخت افزار عملیات رمزنگاری رو انجام بدن. مثلا فرض کنید میخواید یک فایل بزرگ رو با AES رمزنگاری کنید. به جای اینکه خودتون توی برنامه تون الگوریتم رو پیاده کنید، میاید از این ساکت مخصوص استفاده میکنید که داده رو بفرسته به کرنل و کرنل عملیات رمزنگاری رو انجام بده.
سال 2017 یه بهینه سازی خفن توی این بخش پیاده کردن. قبل از اینکه بگیم چی بود باید در مورد scatterlist حرف بزنیم . این یه فیچر خیلی باحله تو لینوکس. فرض کنید یه کتاب 100 صفحه ای میخوایید واسه اکبر آقا بفرستید. ولی چون حجم کتاب بالاست شما 33 صفحه اولو میذارید تو انباری و 33 تای بعدی تو آشپزخونه و 34 تای بعدی تو اتاق خواب و میایین از چیزی به عنوان scatterlist استفاده میکنید تا بدونید هر تیکه از کتاب کجاست. لینوکس هم دقیقا فایل های بزرگ رو وقتی میخواد تو مموری بذاره از این فیچر خودش استفاده میکنه. خب مهندس ها اومدن گفتن: چرا دوتا scatterlist مجزا برای ورودی و خروجی داشته باشیم؟ بذارین req->src رو برابر با req->dst قرار بدیم تا حافظه کمتری مصرف بشه و سرعت بره بالا. به نظر منطقی میاد نه؟ولی همه چی دقیقا از اینجا شروع میشه
یه مثال با جزئیات بیشتر بزنیم. فرض کنید شما یه فایل دارید برای ذخیره رمزهاتون. مثلاً داخلش نوشتید:
Gmail-Password: Akbar agha
و میخواید این فایل رو رمزنگاری کنید.
قبل از 2017 لینوکس فایل اصلی رو از دیسک میاورد داخل RAM و بعد از رمزنگاری، خروجی رو داخل یه بخش دیگه از حافظه مینوشت. در نهایت همون بخش جدید حافظه روی دیسک نوشته میشد و جای فایل اولیه رو میگرفت. یعنی source و destination جدا بودن. حالا اگر موقع رمزنگاری ۴ بایت بیشتر هم نوشته میشد، معمولاً وارد فایل اصلی نمیشد چون خروجی داخل یه buffer جدا قرار داشت. اگر داده ای خارج از محدوده مورد انتظار نوشته میشد معمولا وارد buffer جداگانه خروجی میشد و مستقیما page cache فایل اصلی رو overwrite نمیکرد.
ولی بعد از 2017 لینوکس برای performance بهتر از in-place encryption استفاده کرد. یعنی فایل رو از دیسک میاره داخل page cache یا RAM و عملیات رمزنگاری مستقیم روی همون بخش حافظه انجام میشه. در نتیجه خروجی روی همون memory اولیه overwrite میشه. مشکل CVE-2026-31431 این بود که اون ۴ بایت اضافه هم میتونست روی همون page cache نوشته بشه و باعث overwrite شدن page cache فایل های حساس مثل su بشه، بدون اینکه فایل واقعی روی دیسک تغییر کند. یعنی طرف میاد با سوء استفاده از crypto API میتونه page cache فایل دیگهای رو overwrite کنه و اون سرویس رو (su) اجراش میکنه بلافاصله از روی رم و کلی validator check رو عملا دور بزنه :)))))))))
مشکل دقیقا کجای کار خودش رو نشون داد؟
الان دیگه ورودی و خروجی تو رمزنگاری یکی شده. اما یه الگوریتم خاص هست به اسم authencesn(hmac(sha256),cbc(aes)). این الگوریتم برای کارهایی که نیاز به Extended Sequence Number دارن، وسط کار مجبوره 4 بایت رو به عنوان فضای موقت در آفست assoclen + cryptlen بنویسه. یعنی یه "خراش و دستگاری کوچولو" میکنه تو حافظه.
حالا فرض کنید کاربر از طریق splice() یک فایل رو به این ساکت رمزنگاری میده. به خاطر همون بهینهسازی 2017، tag page های فایل که توی page cache قرار دارن، با sg_chain() به خروجی scatterlist متصل میشن. یعنی خروجی رمزنگاری مستقیما رفته توی کش فایل اصلی توی حافظه. وقتی اون الگوریتم خاص میاد 4 بایت رو مینویسه، داره مینویسه رو حافظه کش شده فایل کاربر — بدون اینکه هیچ مجوز نوشتن روی اون فایل رو داشته باشه.
چطور از این ۴ بایت میرسیم به root؟
اینجا دقیقاً بخش جذاب ماجراست . ۴ بایت شاید کم به نظر برسد، ولی وقتی طرف کاردان باشه و بدونه دقیقا کجا و چه چیزی را overwrite کنه تغییر بده، همون ۴ بایت هم کافیه واسش
مثلاً میتونه:
page cache یک باینری setuid مثل /usr/bin/su یا sudo را تغییر دهد،
یک شرط امنیتی یا branch حساس را patch کند،
یا بخشی از control flow برنامه را دستکاری کند تا برنامه با دسترسی root کد دلخواه را اجرا کند.
در CVE-2026-31431 مهاجم فایل واقعی روی دیسک را تغییر نمیده؛ فقط نسخه داخل RAM یا همان page cache را patch میکنه. بعد بلافاصله همان باینری آلوده داخل RAM اجرا میشود و privilege checkها bypass میشوند و attacker به root میرسد.
فقط یک نکته: PoC کامل این آسیبپذیری اتفاقاً عمومی شده و exploit آن منتشر شده است؛ حتی Theori هم PoC رسمی منتشر کرده و چندین vendor و تیم امنیتی مستقل این vulnerability را تأیید کردهاند.
حالا چطور مشکل رو حل کردن تو پچ های حال حاضر ؟ پچی که زدن برگشته همون بهینهسازی رو برداشته؟ نه دقیقا. اومدن گفتن: "خوب تو این الگوریتم خاص که نیاز به scratch space داره، نباید اجازه بدیم خروجی با ورودی share بشه." یعنی رفع آسیب پذیری بدون از دست دادن کلیت بهینهسازی انجام شده. خیلی هوشمندانه است واقعا
تو این لینک گیتهاب میتونید کد پایتون رو مشاهده کنید و خودتون هم تستش کنید.
اگر نکته نظری داشتید خوشحال میشم برام بنویسید
تا نوشته ای دیگه عزت زیاد