مقدمه
بازکننده بستهبندی phar یا phar deserializer یک متد جدید در شاخه استفاده دوباره کد برای حمله است که به اصطلاح Code reuse attack نامیده میشود. این حمله به روی برنامههایی با زبان PHP که به صورت شی گرا نوشته شدهاند قابل پیادهسازی است. این حمله در گردهمایی ۲۰۱۸ مربوط به گروه Black Hat توسط سم توماس، معرفی عمومی گردید. همانند حمله ROP یا return-oriented programming یا برنامهنویسی بازگشتی بر روی فایلهای باینری کامپایل شده، حمله از طریق phar نیز حاوی اشیاای از PHP است که قابلیت تزریق در آن را دارا میباشد. شکلی دیگر از برنامهنویسی مالکیتگرا یا property-oriented programming در برنامهنویسی شی گرا PHP میباشد.
تازگی این حملات، باعث جلب توجه بسیاری از افراد در جامعه امنیت شده است. این توجه باعث پیدا شدن مشکلات امنیتی بسیار جدید و جدی در پلتفرمهای مطرح و منتشر شده از جمله
1.Wordpress < 5.0.1 (CVE-2018-20148)
2.Drupal 8.6.x, 8.5.x, 7.x (CVE-2019-6339)
3.Prestashop 1.6.x, 1.7.x (CVE-2018-19126)
4.TCPDF < 6.2.19 (CVE-2018-17057)
5.PhpBB 3.2.3 (CVE-2018-19274)
شده است. در ادامه به توضیح نحوه کارکرد این آسیبپذیری بروی PhpBB 3.2.3 و بهره برداری از آن خواهیم پرداخت و در نهایت شاهد اجرای کدهای دلخواه از راه دور بر روی این پلتفرم خواهیم بود.
درباره فایلهای phar، Deserializerها و هاPHP Wrapper
برای درک بهتر نحوه حمله ابتدا میبایست درک صحیحی از فایلهای phar، چگونگی کار حمله در بازکنندهها یا Deserializerها و در نهایت چیستی بستهبندیکنندهها یا wrapperها در PHP و رابطه متقابل این سه مفهوم داشته باشیم.
فایلهای phar چه هستند؟
فایلهای Phar، به منظور انتشار برنامههای PHP و کتابخانهها در یک فایل است(همانند فایل JAR در زبان جاوا). همچنین فایلهای phar میتوانند به طور مستقیم در کدهای PHP شما استفاده شوند. ساختار فایلها phar به گونهای است که میتوان گفت یک فایل بایگانی شده (archive) هستند که شامل بخشهایی هستند که در ادامه به آن خواهیم پرداخت.
هنگامی که یک فایل phar به صورت یک برنامه مستقل در نظر گرفته شود، حداقل نیاز به اجرای کد زیر است. این قطعه کد به منظور اجرا کننده اولیه فایل مورد استفاده قرار میگیرد.
<?php __HALT_COMPILER();
توضیحات مربوط به کدهای منبع موجود در فایل بایگانی شده. به صورت اختیاری میتواند شامل اطلاعات فراداده (meta-data) باشد (این تکه از فایل اهمیت بالایی در ایجاد زنجیره حمله خواهد داشت که در ادامه میبینیم).
- کدهای منبع و اصلی فایل (قسمت واقعی و اصلی مربوط به کارکرد فایل phar)
- قسمتی دلخواه به منظور امضا برای بررسی صحت فایل
درک حمله در هنگام Deserilizing
بستهبندی (Serialize)، روالی برای ذخیره ویژگیهای (properties) یک کلاس به صورت دودویی (binary) است که باعث میشود تا امکان انتقال روی شبکه و یا ذخیره این ویژگیها بروی حافظه امکانپذیر باشد. عکس این روال بازکردن بستهبندیها (Deserialize)، به منظور بازیابی اطلاعات و ویژگیهای همان کلاس میباشد.
در زبان PHP روال بستهبندی تنها نام کلاس و همچنین ویژگیهای آن را شامل میشود و این به معنی عدم بستهبندی توابع تعریف شده در کلاس است. این عمل نشانه طراحی دقیق و امنیتی روال بازکردن بستهبندیهاست. تنها یک مورد وجود دارد که عمل بازکردن بستهبندیها را خطرناک میکند و آن صدا زدن توابع جادویی (Magic functions) است.
این توابع خاص هر کلاس است. شامل دو زیر خط در ابتدای نام که به صورت ضمنی و یا در هنگام اجرا ممکن است صدا زده شوند. به طور پیشفرض این توابع عملیاتی انجام نمیدهند و این وظیفه توسعهدهنده است که برای آنها عملیات تعریف نماید. در این مقاله دو تابع هستند که ارزش اشاره کردن دارند، چرا که تنها آنها هستند که در هنگام استفاده از بازکنندهبستههای phar صدا زده میشوند.
__wakeup()
به طور ضمنی در هنگام بازکردن بستهبندی صدا زده میشود.destruct()
هنگامی که دیگر یک شی مورد در کد مورد استفاده قرار نمیگیرد که در نهایت توسط جمعکننده زباله (Garbage Collector) از بین میروند.
نگاهی به کد آسیبپذیر زیر بیاندازیم و مشاهده کنیم که چگونه از این آسیبپذیری میتوان استفاده نمود.
1 | # file: dummy_class.php |
همانطور که توضیح داده شد، تابع wakeup__
در هنگام بازکردن بستهبندی به صورت خودکار صدا زده میشود. با توجه به کد میتوان گفت با فراخوانی تابع wakeup__
دستور print_r
با آرگومانهای موجود صدا زده خواهد شد که اشاره به دو ویژگی wake_func
و wake_args
دارد. اجرای ساده کد بالا خروجی زیر را تولید میکند.
1 | $ php dummy_class.php |
اما چه خواهد شد اگر در ۶۰ ثانیهای که برنامه در حالت معلق (suspend) است، فایل بستهبندی را تغییر دهیم تا کنترل اجرای دستورات و روند اجرایی برنامه را به دست بگیریم؟ کد زیر نحوه انجام این مورد را مشخص میکند.
1 | # file: exploit.php |
اجرای قطعه کد بالا باعث میشود تا در زمان ۶۰ ثانیهای که فایل dummy_class در حال انتظار است، به ما اجازه میدهد اجرای یک کد خوب را میدهد که بدون تغییر در کد dummy_class قابل انجام است. اجرای کد بالا باعث میشود تا مقادیر wake_func و wake_args به passthru(“id”) تغییر کند که در نهایت نتیجه نهایی به صورت زیر تغییر میکند.
1 | $ php dummy_class.php |
همانطور که مشاهده میکنید دستور اجرا شده تغییر کرده است و تابع ما اجرا گردید.
در زمینه حمله تزریق شی در PHP، این دنباله از آسیبپذیری از کد به نام گجتها یا زنجیره POP معروف است.
بستهبندیکنندههای PHP
با توجه به اسناد PHP، جریانها (streams) راه مناسبی به منظور تعمیم فایلها، شبکه، متراکمسازی داده و دیگر عملیات به منظور به اشتراک گذاری مجموعهای از توابع و استفاده از آنها است. بستهبندیکنندههای PHP مسئولیت مدیریت پروتکلهای مختلف و ارائه یک رابط برای ایجاد جریان است. این جریانها به طور معمول با توابعی مانند fopen یا copy و یا filesize مورد استفاده قرار میگیرند.
یک جریان به صورت یک شبیه URL به صورت wrapper://source
است. جریانهای معروف و کاربری که PHP ارائه میدهد در زیر آورده شده است.
- دسترسی به فایلهای سیستم
file://
- دسترسی به پروتکل HTTP
http://
- دسترسی به فایلهای سیستم از طریق پروتکل FTP
ftp://
- دسترسی به جریانهای مختلف I/O
php://
جریانی که برای ما اهمیت دارد جریان ارائه شده توسط بستهبندی کنننده //:phar
است. تعریف کلی این جریان به صورت phar://full/or/relative/path
است که دو ویژگی خاص بسیار جالب دارد.
1.این جریان داده حساس به پسوند فایلهایی که به آن معرفی میشود نیست لذا یک نامزد مناسب برای اجرای فایلهای چندزبانی (polyglot) است.
2.اگر یک تابع فایل سیستم به عنوان یک آرگومان از phar صدا زده بشود، طبق طراحی به صورت خودکار بازکردن دستهبندی روی آن اتفاق میافتد.
در زیر لیستی از توابعی که باعث اجرای بازکردن بستهبندی میشود، آورده شده است.
1 | copy file_exists file_get_contents file_put_contents file fileatime |
نحوه انجام حمله با استفاده از جریان phar
حال ما تمام موارد و عناصر لازم برای انجام یک حمله را داریم. نیازمندیها برای شروع حمله به وسیله جریان بازکننده بستهبندی phar معمولاً شامل موارد زیر است.
- حضور یک زنجیره از از گجتها که شامل کتابخانههای خارجی استفاده شده در برنامه میگردد. این مورد قابل یافت شدن از طریق دیدن کدها و خواندن آنها است.
- قابلیت ایجاد و یا وارد کردن فایل phar به صورت محلی و یا از راه دور (مانند بارگذاری (upload) روی کارگزار (server) ).
- نقطه ورودی، جایی که یک تابع سیستمی فراخوانی شده توسط بستهبندی کننده phar تحت اختیار کاربر باشد (این مورد نیز با مشاهده کد امکانپذیر است).
برای مثال، محلی برای بارگذاری عکس برای یک کاربر باشد که عملیات خاصی برای جلوگیری از مشکلات در نظر گرفته نشده است. کاربر به جای استفاده از پروتکل HTTP در هنگام بارگذاری میتواند از پروتکل phar برای بارگذاری استفاده نماید. سمت کارگزار، در همین حین، یک تابع سیستمی مانند file_exists به منظور بررسی وجود فایل مورد استفاده قرار گیرد. این مورد باعث میشود تا بازکننده بستهبندی به صورت خودکار اجرا گردد که با وجود یک زنجیره از گجتها و دستورات امکان به دست آوردن دسترسی به سیستم فراهم میشود.