1. مقدمه و خلاصه ای از مشخصات CVE
آسیب پذیری CVE-2024-24576 معروف به BatBadBut که شما نمیتوانید فرمانها را در ویندوز بهصورت امن اجرا کنید.
اصطلاح BatBadBut در واقع نامی طنزآمیز و ترکیبی است که از سه واژه گرفته شده:
- Bat اشاره به فایلهای batch در ویندوز (.bat file)
- Badیعنی ناامن یا مشکلدار
- Butیعنی “اما”
بنابراین، BatBadBut به صورت غیررسمی و کنایهآمیز به این معنی است که Batchها (فایلهای bat.) بد هستند، اما هنوز مجبوریم از آنها استفاده کنیم.
1-1 شرح مسئله بر اساس سایت nist
Rust زبانی برنامهنویسی است. گروه پاسخ امنیتی Rust اطلاع پیدا کرد که کتابخانه استاندارد Rust در نسخههای پیش از 1.77.2 هنگام اجرای فایلهای batch در ویندوز (پسوندهای bat و cmd) با استفاده از Command، آرگومانها را بهدرستی escape نمیکرد. اگر مهاجمی بتواند آرگومانهایی که به پروسس spawn شده داده میشود را کنترل کند، میتواند با دور زدن مکانیزم escape اجرای دلخواه دستورات شِل را انجام دهد. شدت این آسیبپذیری برای کسانی که فایلهای batch را در ویندوز با آرگومانهای غیرقابلاعتماد فراخوانی میکنند بحرانی است. سایر پلتفرمها یا شیوههای استفاده تحتتأثیر قرار نگرفتهاند.
در مستندات API،Command::arg و Command::args ذکر شده که آرگومانها «همانطور که هستند» به پروسس فرستاده میشوند و توسط شِل ارزیابی نمیشوند. این بهمعنی ایمن بودن ارسال ورودیهای غیرقابلاعتماد بهعنوان آرگومان فرض شده است. در ویندوز پیادهسازی این تضمین پیچیدهتر است، چون API ویندوز تنها یک رشته واحد شامل همه آرگومانها فراهم میکند و خود پروسس موظف است آن را تقسیم (split) کند. بیشتر برنامهها از runtime استاندارد C برای argv استفاده میکنند که در عمل تقسیم آرگومان را تا حد زیادی همسان میسازد. اما یک استثنا cmd.exe است (که برای اجرای batchها استفاده میشود) که منطق تقسیم آرگومان خودش را دارد. این موضوع کتابخانه استاندارد را مجبور میکند تا escaping سفارشی برای آرگومانهای ارسالی به batchها پیاده کند.
متأسفانه گزارش شد که منطق escaping ما به اندازه کافی کامل نبوده و میشد آرگومانهای مخربی ارسال کرد که منجر به اجرای دلخواه شِل شوند. بهخاطر پیچیدگی cmd.exe، نتوانستیم راه حلی پیدا کنیم که در همه حالتها آرگومانها را بهدرستی escape کند. برای حفظ تضمینهای API، مقاومت کد escaping را افزایش دادیم و API Command را طوری تغییر دادیم که وقتی نتواند یک آرگومان را بهصورت امن escape کند، خطای InvalidInput بازگرداند. این خطا هنگام spawn کردن پروسس منتشر خواهد شد. اصلاح در Rust 1.77.2 گنجانده شده است.
نکته: منطق جدید escaping برای batchها محافظهکارانهتر است و ممکن است برخی آرگومانهای معتبر را هم رد کند. کسانی که خودشان escaping را پیاده میکنند یا فقط با ورودیهای اعتمادشده روی ویندوز کار میکنند میتوانند از متد CommandExt::raw_arg برای دور زدن منطق escaping کتابخانه استاندارد استفاده کنند.
1-2 شمارش نقاط ضعف (Weakness Enumeration)
1-3 خلاصه کوتاه (TL;DR)
BatBadBut یک آسیب پذیری است که به مهاجم اجازه می دهد تا در برنامه های ویندوزی که به طور غیرمستقیم از تابع `CreateProcess` استفاده می کنند، در شرایط مشخص، تزریق دستور (command injection) انجام دهد.
تابع `CreateProcess()` هنگام اجرای فایل های batch (مثل `bat.` و `cmd.`) به طور ضمنی `cmd.exe` را اجرا می کند، حتی اگر برنامه خودش این فایل ها را صریحا در خط فرمان مشخص نکرده باشد. مشکل این است که `cmd.exe` قواعد پیچیده ای برای پارس کردن آرگومان ها دارد و runtime های زبان های برنامه نویسی به درستی آرگومان ها را escape نمی کنند. به خاطر همین، اگر کسی بتواند بخشی از آرگومان های خط فرمان که به فایل batch داده می شود را کنترل کند، می توان دستورات دلخواه را تزریق و اجرا کرد.
برای مثال، قطعه کد ساده ای در Node.js ممکن است روی ماشین سرور برنامه `calc.exe` را باز کند.
const { spawn } = require('child_process');
const child = spawn('./test.bat', ['"&calc.exe']);
این اتفاق فقط زمانی رخ میدهد که یک فایل batch بهطور صریح در خطفرمانی که به ()CreateProcess پاس داده میشود مشخص شده باشد، و وقتی که یک فایل .exe مشخص شده باشد رخ نمیدهد. با این حال، چون ویندوز بهصورت پیشفرض فایلهای bat. و cmd. را در متغیر محیطی PATHEXT قرار میدهد، بعضی runtimeها ممکن است فایلهای batch را برخلاف قصد توسعهدهنده اجرا کنند اگر فایلی با همان نام فرمانی که توسعهدهنده قصد اجرای آن را داشته وجود داشته باشد. بنابراین حتی قطعهکدی که در ادامه میآید ممکن است به اجرای دلخواه دستورها منجر شود، در حالی که بهطور صریح bat. یا cmd. را شامل نمیشود:
cmd := exec.Command("test", "")
cmd.Run()
استفاده از این رفتارها زمانی ممکن است که شرایط زیر برقرار باشند:
- برنامه روی ویندوز دستوری را اجرا کند.
- برنامه پسوند فایل فرمان را مشخص نکرده باشد، یا پسوند مشخصشده bat. یا cmd. باشد.
- فرمانی که اجرا میشود شامل ورودی کنترلیشده توسط کاربر (user-controlled input) به عنوان بخشی از آرگومانهای فرمان باشد.
- محیط اجرای زبان برنامهنویسی (runtime) بهدرستی آرگومانهای فرمان را برای cmd.exe escape نکند.¹
با بهرهبرداری از این رفتارها، ممکن است اجرای دلخواه دستورها (arbitrary command execution) ممکن شود.
من یک فلوچارت برای تعیین اینکه آیا برنامههای شما تحت تاثیر این آسیبپذیری قرار دارند ساختهام اگر مطمئن نیستید به پیوست A مراجعه کنید، و برای وضعیت زبانهای برنامهنویسی متأثر به پیوست B مراجعه نمایید.
1-4 امتیاز CVSS
اول از همه باید ذکر کنم که نباید امتیاز CVSS آسیبپذیریهای یک کتابخانه را مستقیماً به برنامه خودتان اعمال کنید.
راهنمای CVSS نسخه ۳٫۱ بیان میکند که امتیاز CVSS یک کتابخانه باید بر اساس بدترین حالت ممکن (worst-case scenario) محاسبه شود، و به همین دلیل است که آسیبپذیریهای اخیر زبانهای برنامهنویسی امتیاز بالایی گرفتهاند، حتی اگر شرایط خاصی برای بهرهبرداری لازم باشد.
به جای اعمال مستقیم امتیاز، باید امتیاز را بر اساس پیادهسازی خاص خودتان دوباره محاسبه کنید:
راهنمای CVSS برای کتابخانهها و نرمافزارهای مشابه
2. نحوه اجرای آسیب پذیری در محیط اجرا و شرح فایلهای ارایه شده
2-1 نحوه اجرای آسیب پذیری به این شکل زیر است:
- نصب نسخه آسیب پذیر Rust یعنی نسخههای پیش از 1.77.2
- کامپایل برنامه POC با دستور cargo run
- اجرای برنامه با دستور cargo run و یا اجرای مستقیم با فایل اجرایی .exe خروجی در ایتجا exe
- در مرحله بعد برنامه منتظر دریافت ورودی از کاربر می ماند.
- وارد کردن ورودی که escaping رعایت نشده است ارسال می کنیم در اینجا همانطور که در شکل زیر مشخص شده است. مانند
anything” & your command!
- سپس بعد از ادامه اجرای برنامه مشاهده می کنید علاوه بر اجرای اسکریپت ما که رشته دریافتی را توسط اسکریپت نمایش داده است در خط آخر دستور whoami اجرا شده و خروجی آن نمایش داده شده است، که می توان هر دستور دیگری را جایگزین کرد.
2-2 شرح فایلهای ارائه شده
در پوشه POC پوشه دیگری با نام CVE-2024-24576-PoC وجود دارد که شامل سورس آسیب پذیر قابل اجرا و دیباگ در visual studio code است. فایل های مهم به شرح زیر است:
- پوشه مخفی vscode. که شامل تنظیمات اجرا و دیباگ با vscode است.
- فایل toml که برای کامپایل کردن توسط rust نیاز داریم
- فایل اصلی سورس درون پوشه src با نام rs است.
- فایل bat هم اسکریپت نمونه ای است که صرفا رشته ورودی توسط کاربر یا همان پارامتر اول را چاپ می کند.
3. تحلیل آسیب پذیری و شرح سورس آن: ارائه از مقالات موجود یا تحلیل تحلیلگر
3-1 تحلیل آسیب پذیری – جزئیات فنی
نویسنده بیان می کند: “هرچند من طرفدار نامگذاری آسیبپذیریهایی که اثر گسترده اینترنتی ندارند نیستم، اما طرفدار بازی با کلمات هم هستم، بنابراین تصمیم گرفتم این آسیبپذیری BatBadBut نامیده شود چرا که مربوط به فایلهای batch است و بد است ولی بدترین نیست”.
در این بخش جنبه فنی BatBadBut و علت امکانپذیری تزریق دستور را توضیح میدهیم.
توجه کنید که بعضی قطعهکدها روی آخرین نسخه runtimeها کار نمیکنند، چون برخی تامینکنندگان قبلاً مشکل را پچ کردهاند.
3-2 ریشه مشکل
ریشه BatBadBut در رفتار نادیده گرفتهشده تابع CreateProcess روی ویندوز است. هنگام اجرای فایلهای batch با CreateProcess، ویندوز بهصورت ضمنی cmd.exe را اجرا میکند چون ویندوز بدون cmd.exe نمیتواند فایلهای batch را اجرا کند.
برای مثال، قطعهکدی که فایل batch به نام test.bat را اجرا میکند، در واقع C:\Windows\System32\cmd.exe /c .\test.bat را spawn میکند تا test.bat را اجرا کند.
wchar_t arguments[] = L".\\test.bat";
STARTUPINFO si{};
PROCESS_INFORMATION pi{};
CreateProcessW(nullptr, arguments, nullptr, nullptr, false, 0, nullptr, nullptr, &si, &pi);
گرچه این به خودی خود مشکل نیست، مسئله وقتی ایجاد میشود که زبان برنامهنویسی تابع CreateProcess را بستهبندی (wrap) کرده و مکانیزم escape برای آرگومانهای فرمان اضافه میکند.
3-3 بستهبندی یا زیربرنامه (Wrapping) تابع CreateProcess
بیشتر زبانهای برنامهنویسی یک تابع برای اجرای فرمان ارائه میدهند و تابع CreateProcess را بسته بندی (wrap) میکنند تا یک رابط کاربری دوستانهتر فراهم کنند.
برای مثال، ماژول child_process در Node.js تابع CreateProcess را بستهبندی کرده و راهی برای اجرای فرمان با آرگومانها فراهم میکند، بهصورت مشابه نمونه زیر:
const { spawn } = require('child_process');
const child = spawn('echo', ['hello', 'world']);
در قطعهکد بالا مشاهده میکنید که تابع spawn، دستور (command) و آرگومانها را بهصورت جداگانه دریافت میکند. سپس، در مرحلهی بعد، آرگومانها را بهصورت درونی (internally) «escape» میکند تا بتواند آنها را به تابع سیستمی CreateProcess ارسال کند. این رفتار در فایل src/win/process.c بین خطوط ۴۴۴ تا ۵۱۸ پیادهسازی شده است.
بیشتر توسعهدهندگان انتظار دارند که تابع spawn، آرگومانهای دستور را بهدرستی escape کند، و این انتظار در بیشتر موارد درست است.
با این حال، همانطور که پیشتر اشاره شد، تابع CreateProcess هنگام اجرای فایلهای دستهای (batch files) بهصورت ضمنی (implicitly) فرایند cmd.exe را ایجاد میکند.
متأسفانه، cmd.exe از قوانین escape متفاوتی نسبت به سازوکار معمول پیروی میکند، و همین موضوع میتواند منجر به رفتارهای پیشبینینشده (usual escaping mechanism) شود.
3-4 قانون تجزیه (Parsing rule) cmd.exe
در اغلب پوستههای سیستمهای شبهيونیک (Unix-like)، قوانینِ فرار (escaping) مشابه یا یکساناند: از بکاسلش (\) بهعنوانِ کاراکترِ فرار استفاده میشود. بنابراین اگر بخواهید یک علامت نقلقول دوگانه (“) را داخل یک رشته محصور در دو علامت نقلقول فرار دهید، میتوانید مانند نمونه زیر از بکاسلش استفاده کنید:
echo "Hello \"World\""
استفاده از بکاسلش بهعنوان کاراکتر فرار بهنظر یک استاندارد فعلی (de facto) است و فرمتهایی مثل JSON و YAML نیز از آن استفاده میکنند. با این حال، وقتی دستور زیر را در Command Prompt اجرا کنید، برنامهی calc.exe اجرا خواهد شد:
echo "\"&calc.exe"
علت این است که Command Prompt از بکاسلش بهعنوان کاراکتر فرار استفاده نمیکند و در عوض از caret (^) استفاده میکند.
برمیگردیم به مثال child_process؛ این ماژول علامتهای نقلقول دوگانه (“) را در آرگومانهای دستور با بکاسلش (\) فرار میدهد. با توجه به قواعد فراردهی cmd.exe که پیشتر ذکر شد، این فراردهی هنگام اجرای فایل دستهای کافی نیست، بنابراین قطعهکد زیر، حتی با اینکه آرگومان بهدرستی جدا شده است و گزینهی shell غیر فعال است، باز هم calc.exe را اجرا میکند:
const { spawn } = require('child_process');
const child = spawn('./test.bat', ['"&calc.exe']);
به دلیل این رفتار، یک آرگومان خط فرمان مخرب میتواند منجر به اجرای دستورات ناخواسته (command injection) شود و این، مشکل اصلی BatBadBut است.
4. تحلیل کد بهره بردار و شرح سورس آن: ارایه از مقالات موجود یا تحلیل تحلیلگر
4-1 Shell یا batch file نمونه با نام test.bat
این اسکریپت فقط آرگومان اول را نمایش می دهد.
4-2 سورس PoC آسیب پذیر
سورس زیر رشته ای از کاربر توسط در خط 12 دریافت می کند و سپس در خط 22 آنرا به همراه shell اجرا می کند که این خط آسیب پذیر است. سپس پس از اجرا خروجی را در متغیر output قرار میدهد و در خط 28 آنرا در کنسول چاپ میکند.
4-3 نحوه سوء استفاده از آسیب پذیری
بدلیل عدم انجام escaping با اجرای برنامه و ورودی دادن به برنامه مانند مثال زیر که سبب اجرای ماشین حساب می شود.
“aaaaaa& calc.exe”
برنامه ما شامل اسکریپت ساده است که آرگومان دریافتی را چاپ میکند اما بدلیل انجام نشدن escaping بخش دوم رشته به عنوان دستور دیگر تفسیر میشود و آنرا اجرا می کند.
4-4 موانع موجود در اجرای کد بهره بردار و شرح نحوه بایپس آنها:
این آسیب پذیری محدودیت محیط اجرا ندارد روی همه ویندوز ها اجرا میشود، صرفا باید نسخه آسیب پذیر rust یعنی نسخههای پیش از 1.77.2 را نصب و برنامه را با آن کامپایل کنید.
5. تحلیل فضای حافظه در نقاط بحرانی:
5-1 تحلیل فضای حافظه قبل از رخداد آسیب پذیری:
این آسیب پذیری دارای این بخش نیست، چرا که آسیب پذیری در نحوه تفسیر دستور در سیستم عامل وجود دارد. و در نسخه اصلاحیه توسعه دهنده Rust در تابع wrapper خود تفسیر رشته ورودی و جلوگیری از escaping را اضافه کرده است.
5-2 تحلیل فضای حافظه در نقطه آسیب پذیر:
قبل از اجرای CreateProcess همانطور که در تصویر زیر مشاهده میکنید، ما یک breakpoint روی روال Native به نام NtCreateUserProcess که آخرین متد قبل از ورود به کرنل است—قرار دادهایم. البته امکان تعیین نقطه توقف روی توابع سطح بالاتر، مانند CreateProcess در kernel32.dll نیز وجود دارد. با این حال، روند اجرای برنامه در نهایت به NtCreateUserProcess در مد کاربر ختم میشود.
با بررسی پارامترهای ارسالی در بخش Memory View و Command ابزار WinDbg مشاهده میکنیم که اگرچه رشته زیر ابتدا در برنامه ما ارسال شده است، اما پس از عبور از Rust wrapper و فراخوانی تابع سیستمی NtCreateUserProcess، به شکلی که در ادامه نمایش داده شده، تغییر یافته است.
aaa” &whoami
رشته زیر به عنوان آرگومان اجرایی به تابع فوق ارسال شده است.
"cmd.exe /d /c ""c:\windows\system32\test.bat" "aaa\" &whoami"""
همچنین با ابزار process monitor هم بررسی می کنیم که در تصویر زیر خروجی آن را مشاهده میکنید:
حتی میتوان این آسیب پذیری را به صورت دستی بدون نیاز به هیچ ابزاری در cmd اجرا کرد تا مشاهده کنید که ویندوز هیچ تفسیری روی این ورودی انجام نمی دهد.
5-4 علت وقوع آسیب پذیری و ارایه نوع دادهای که منجر به رخداد آسیب پذیری می شود:
همانطور که پیش تر هم ذکر شد علت وقوع این آسیب پذیری عدم escaping در ویندوز برای اجرای فرامین اجرایی با cmd است. که کافیست رشته ای مشابه ” & به برنامه ارسال گردد و مواردی دیگر که در ضمیمه ها قید شده است.
5-5 تولید کدی که منجر به رخداد آسیب پذیری می گردد
کد فوق در پوشه POC موجود است که در سند سورس آن نیز مورد بررسی قرار گرفت.
6. تحلیل پچ ارائه شده:
در پوشه patched فایلی با نام rust-1.77.2-x86_64-pc-windows-msvc.msi وجود دارد که پس از نصب آن برنامه آسیب پذیری که با آن کامپایل شود در مقابل این آسیب پذیری ایمن خواهد بود. برای زبان Rust باید نسخه های بعد از rust-1.77.2 را نصب کنید. در ادامه این مورد را در ابتدا روی نسخه وصله نشده آزمایش میکنیم و سپس روی نسخه وصله شده انجام خواهیم داد که می توانید خروجی آنها را مشاهده کنید.
6-1 اجرای آسیب پذیری قبل وصله (با نصب نسخه قبل از rust-1.77.2)
6-2 اجرای آسیب پذیری بعد از نصب وصله امنیتی و کامپایل با آن
همانطور که در تصویر مشاهده می کنید فرمان دوم اجرا نشده است.
7. توضیح روند این آسیب پذیری به طور خلاصه
- اگر نسخه Rust قبل از ورژن rust-1.77.2 باشد.
- اگر شرط های ضمیمه A برقرار باشد.
- با ورودی دادن ورودی هایی دور زدن escaping
- a. بدلیل انجام نشدن escaping درست در توابع ویندوز و wrapper زبان های آسیب پذیر
- ارسال رشته با تفسیر اشتباه
- اجرای دستور توسط createprocess
- اجر شدن چند دستور توسط cmd.exe با آرگومان هایی که درست escaping نشده است منجر به اجرای اسکریپت مخرب خواهد شد.
8. کاهش خطر یا کاهش سطح ریسک Mitigation
8-1 فراردهی کوتیشن (نقل قول) دوبل (دو گانه)؟
مسئله اینجا این است که رشتهای که با کوتیشن دوبل محصور شده توسط کوتیشن داخل همان رشته شکسته میشود.
پس به نظر میرسد فراردهی (escape) کوتیشن دوبل (“) با caret (^) برای جلوگیری از تزریق فرمان کافی باشد.
اما در واقع، این برای جلوگیری از تزریق فرمان کافی نیست.
به طور غافلگیر کننده، خط فرمان (command prompt) متغیرها (مثل %PATH%) را قبل از هر پردازش دیگری پارس و توسعه میدهد.
این یعنی فرمان زیر calc.exe را اجرا خواهد کرد، حتی اگر &calc.exe داخل رشته محصور در کوتیشن دوبل باشد:
SET VAR=^"
echo "%VAR%&calc.exe"
گرچه متغیرهای محیطی پیشفرض ویندوز شامل علامت کوتیشن دوبل (“) در مقدارشان نیستند، یک متغیر ویژه به نام CMDCMDLINE وجود دارد که رشته خط فرمانی را که برای شروع جلسه جاری command prompt استفاده شده نگهداری میکند.
با فرض اینکه فرمان زیر در PowerShell اجرا شود:
"C:\WINDOWS\system32\cmd.exe" /c "echo %CMDCMDLINE%"
خروجی زیر چاپ خواهد شد:
cmd.exe /c "echo %CMDCMDLINE%"
و با استفاده از استخراج زیررشته از متغیر در خط فرمان (command prompt)، امکان استخراج علامت کوتیشن دوبل (“) از این متغیر وجود دارد. بنابراین، فرمان زیر هنگام اجرا در PowerShell برنامه calc.exe را اجرا میکند:
cmd.exe /c 'echo "%CMDCMDLINE:~-1%&calc.exe"'
به علت این رفتار، فراردهی کوتیشن دوبل با caret برای جلوگیری از تزریق فرمان هنگام اجرای فایل بچ کافی نیست و نیاز به فراردهی بیشتر دارد. در بخش بعدی در این باره توضیح میدهم.
8-2 به عنوان توسعه دهنده
از آنجا که همه زبانها این مشکل را برطرف نکردهاند، هنگام اجرای فرمانها روی ویندوز باید دقت کنید. اگر شما توسعهدهندهای هستید که روی ویندوز فرمان اجرا میکنید اما نمیخواهید فایل بچ اجرا شود، همیشه باید پسوند فایل فرمان را مشخص کنید. برای مثال، اگر کاربر فایل test.bat را در مسیری قرار دهد که در متغیر PATH گنجانده شده، قطعه کد زیر ممکن است به جای test.exe، test.bat را اجرا کند:
cmd := exec.Command("test", "arg1", "arg2")
برای جلوگیری از این مشکل، همیشه باید پسوند فایل فرمان را به صورت زیر مشخص کنید:
cmd := exec.Command("test.exe", "arg1", "arg2")
اگر میخواهید فایلهای بچ را اجرا کنید و runtime شما آرگومانهای فرمان را برای فایل بچ به درستی فراردهی نمیکند، باید ورودیهای تحت کنترل کاربر را قبل از استفاده به عنوان آرگومان فرمان فراردهی کنید.
چون فضاها (spaces) را بیرون از رشته محصور در کوتیشن دوبل نمیتوان به درستی فراردهی کرد، باید از کوتیشن دوبل برای پیچیدن آرگومانها استفاده کنید.
اما داخل رشته محصور در کوتیشن دوبل، علامت درصد (%) را نمیتوان به درستی فراردهی کرد.
برای حل این وضعیت، فراردهی زیر و تا حدی دستکاری لازم است:
- فراردهی خودکار با بکاسلش () که توسط runtime اعمال میشود را غیرفعال کنید.
- برای هر آرگومان مراحل زیر را اعمال کنید:
- علامت درصد (%) را با %%cd:~,% جایگزین کنید.
- بکاسلشی که جلوی کوتیشن دوبل (“) قرار دارد را با دو بکاسلش (\\) جایگزین کنید.
- کوتیشن دوبل (“) را با دو کوتیشن دوبل (“”) جایگزین کنید.
- کاراکترهای خط جدید (\n) را حذف کنید.
- آرگومان را در کوتیشن دوبل (“) محصور کنید.
با جایگزینی % با %%cd:~, %، %cd:~, % (توضیح: نگهدارنده توضیحی که در متن مرجع بوده) به یک رشته خالی توسعه پیدا میکند و خط فرمان قادر به توسعه متغیر واقعی نخواهد بود، در نتیجه علامت درصد به عنوان یک کاراکتر عادی در نظر گرفته میشود.
توجه داشته باشید که اگر delayed expansion از طریق مقدار رجیستری DelayedExpansion فعال شده باشد، باید آن را با فراخوانی صریح cmd.exe با گزینه /V:OFF غیرفعال کنید. همچنین توجه کنید که فراردهی علامت درصد نیازمند فعال بودن command extensions است؛ اگر این مورد از طریق مقدار رجیستری EnableExtensions غیرفعال شده باشد، باید آن را با گزینه /E:ON فعال کنید.
8-3 به عنوان کاربر
برای جلوگیری از اجرای غیرمنتظره فایلهای بچ، باید فایلهای بچ را به مسیری منتقل کنید که در متغیر محیطی PATH گنجانده نشده باشد. در این صورت، فایلهای بچ تنها زمانی اجرا میشوند که مسیر کامل آنها مشخص شود و بنابراین اجرای غیرمنتظره فایلهای بچ جلوگیری میشود.
8-4 به عنوان نگهدارنده runtime
اگر شما نگهدارنده runtime یک زبان برنامهنویسی هستید، توصیه میکنم مکانیزم فراردهی اضافی برای فایلهای بچ پیادهسازی کنید. حتی اگر نمیخواهید این مشکل را در لایه runtime برطرف کنید، حداقل باید این مشکل را مستندسازی کرده و هشدار مناسبی به کاربران ارائه دهید، زیرا این مشکل چندان شناخته شده نیست.
9. نتیجهگیری
در این مقاله، جزئیات فنی BatBadBut، یک آسیبپذیری که به مهاجم اجازه میدهد در شرایط خاص روی ویندوز تزریق فرمان انجام دهد، توضیح داده شد.
همانطور که چندین بار در مقاله اشاره کردم، این مشکل اکثر برنامهها را تحت تاثیر قرار نمیدهد، اما در صورتی که شما تحت تاثیر قرار گرفتهاید، باید آرگومانهای فرمان را به صورت دستی به درستی فراردهی کنید.
امیدوارم این مقاله به شما کمک کند تا جدیت این مشکل را درک کرده و خطرات آن را به صورت امن و مؤثر کاهش دهید.
10. ضمیمه
10-1 ضمیمه A: نمودار جریان برای تعیین اینکه آیا برنامههای شما تحت تأثیر قرار گرفتهاند یا خیر
10-2 ضمیمه B: وضعیت زبانهای برنامهنویسی تحت تأثیر
وضعیت | پروژه |
Documentation update | Erlang |
Documentation update | Go |
Haskell | |
Won’t fix | Java |
Node.js | |
PHP | |
Documentation update | Python |
Documentation update | Ruby |
Rust |
لطفا به ضميمه B براي وضعيت زبانهاي برنامه نويسي تحت تاثير مراجعه کنيد.
- از آنجا که عمدتا از Node.js استفاده ميکنم، در اينجا از آن به عنوان مثال استفاده کرده ام. با اين حال، اين مشکل اختصاصي به Node.js نيست و ساير زبانهاي برنامه نويسي را نيز تحت تاثير قرار ميدهد.
- در واقع، بسياري از زبانهاي برنامه نويسي تضمين ميکنند که آرگومانهاي فرمان به صورت صحيح فراردهی ميشوند و/يا از shell استفاده نميکنند.
- توجه کنيد که جايگزين کردن بکاسلش با caret باعث فراردهی صحيح کوتیشن دوبل نميشود و نياز به فراردهی اضافي دارد.
- وقتي گزينه shell غيرفعال است، ماژول child_process به طور مستقيم فرمان را اجرا ميکند و cmd.exe را spawn نميکند. با اين حال، ويندوز هنگام اجراي فايلهاي بچ به صورت ضمني cmd.exe را اجرا ميکند، بنابراين هنگام اجراي فايلهاي بچ گزينه shell به طور خاموش ناديده گرفته ميشود.
- البته خود علامت caret نيز بايد فراردهی شود.
- وقتي .\\test.bat arg1^ arg2 اجرا ميشود، arg1 و arg2 به عنوان آرگومانهاي جدا شناسايي خواهند شد.
- .\\test.bat “100^%” به صورت 100^% شناسايي خواهد شد نه 100%.
- اگرچه تستها نشان ميدهند که اين فراردهی از تزريق فرمان جلوگيري ميکند، من هنوز مطمئن نيستم که اين بهترين روش باشد؛ اگر روش بهتري ميدانيد لطفا مرا مطلع کنيد.
11. مراجع
CVE-2024-24576
Pocs
https://github.com/frostb1ten/CVE-2024-24576-PoC
https://github.com/brains93/CVE-2024-24576-PoC-Python
ref:
https://nvd.nist.gov/vuln/detail/cve-2024-24576
https://kb.cert.org/vuls/id/123335
https://learn.microsoft.com/en-us/archive/blogs/twistylittlepassagesallalike/everyone-quotes-command-line-arguments-the-wrong-way
https://flatt.tech/research/posts/batbadbut-you-cant-securely-execute-commands-on-windows/
https://github.com/rust-lang/rust/security/advisories/GHSA-q455-m56c-85mh
https://blog.rust-lang.org/2024/04/09/Rust-1.77.2/
https://blog.rust-lang.org/2024/04/09/cve-2024-24576/
https://github.com/rust-lang/rust/releases/tag/1.77.2
https://rust-lang.org/tools/install/
https://learn.microsoft.com/en-us/archive/blogs/twistylittlepassagesallalike/everyone-quotes-command-line-arguments-the-wrong-way
https://flatt.tech/research/posts/batbadbut-you-cant-securely-execute-commands-on-windows/
https://github.com/php/php-src/security/advisories/GHSA-pc52-254m-w9w7
https://github.com/rust-lang/rust/security/advisories/GHSA-q455-m56c-85mh
https://github.com/yt-dlp/yt-dlp/security/advisories/GHSA-hjq6-52gw-2g7p
https://nodejs.org/en/blog/vulnerability/april-2024-security-releases-2
https://github.com/haskell/security-advisories/blob/main/advisories/hackage/process/HSEC-2024-0003.md
https://osv.dev/vulnerability/HSEC-2024-0003