گرفتن روت شل (Root Shell) با استفاده از PATH

0 77
۵/۵ - (۴ امتیاز)

در این مقاله از سری مقالات امنیت نرم افزار آکادمی ترجنس به بررسی یکی از آسیب پذیری هایی که با استفاده از متغیرهای محیطی یا Environment Variable اکسپلویت (گرفتن روت شل) می شود می پردازیم. قبلا در مورد اهمیت توسعه امن نرم افزار و وجود عدم دانش امنیتی در بسیاری از توسعه دهنده های صحبت کردیم و در این مقاله یکی دیگر از انواع آسیب پذیری هایی که بر اثر عدم دانش امنیتی (و البته دانش سیستم عاملی) توسعه دهنده رخ می دهد را بررسی می کنیم.

حمله از طریق برنامه خارجی

در توسعه نرم افزار بسیار رخ می دهد که یک برنامه، برنامه دیگری را فراخوانی کند. این عمل سطح حمله را در نرم افزار پایه گسترش می دهد. طبیعی است که قبل از فراخوانی برنامه خارجی، سطح حمله برنامه پایه تنها مربوط به ورودی های مستقیم و غیر مستقیم دریافتی توسط برنامه، چگونگی توسعه الگوریتم های رمزنگاری، چگونگی توسعه کنترل دسترسی و… بود اما پس از فراخوانی یک برنامه خارجی، سطح حمله برنامه خارجی نیز به سطح حمله برنامه پایه اضافه می شود. برای مثال یک یه برنامه ممکن است از متغیرهای محیطی یا Environment Variable ها استفاده نکند اما برنامه خارجی که فراخوانی می کند از این متغیرها استفاده کند و بنابراین سطح حمله افزایش پیدا می کند و ممکن است به گرفتن روت شل منجر شود.

دو روش معمول برای فراخوانی برنامه خارجی

معمولا از دو روش برای فراخوانی یک برنامه خارجی از درون یک برنامه پایه استفاده می شود. یکی استفاده از خانواده توابع ()exec که به فراخوانی فراخوان سیستمی ()execve برنامه خارجی درون حافظه بارگذاری شده و اجرا می شود و دیگری استفاده از تابع ()system که این تابع ابتدا با یک عمل ()fork، یک فرآیند فرزند یا Child Process را ایجاد کرده و سپس با استفاده از ()execl برنامه خارجی را فراخوانی می کند. لازم به ذکر است که خود ()execl نیز از ()execve استفاده می کند.
شاید به نظر بیاید چون در هر دو روش در نهایت از ()execve استفاده میشود، سطح حمله یکسان باقی می ماند. اما اینطور نیست! تابع ()system برای فراخوانی یک برنامه خارجی ابتدا با استفاده از ()execve یک شل اجرا می کند (bin/sh/ را اجرا می کند) و از شل اجرای برنامه خارجی را درخواست می کند اما در روش اول برنامه خارجی مستقیما اجرا می شود. احتمالا حدس زده اید که سطح حمله در روش اول اجتماع سطح حمله برنامه پایه با برنامه خارجی اما سطح حمله در روش دوم اجتماع سطح حمله برنامه پایه، شل و برنامه خارجی می باشد. اگر برنامه پایه یک برامه Set-UID یا یک برنامه ممتاز باشد، همین موضوع برای یک مهاجم کافی است چرا که شل ورودی های زیادی از خارج دریافت می کند که بسیاری از آن ها می تواند در کنترل کاربر (مهاجم) باشد. یکی از این ورودی ها، متغیرهای محیطی یا Environment Variable ها هستند که به عنوان یک ورودی غیرمستقیم در نظر گرفته می شوند.

حمله با استفاده از متغیر محیطی

در این بخش با ذکر یک مثال ساده موارد گفته شده را بررسی می کنیم.
فرض کنید برنامه ای نوشته اید که با استفاده از تابع ()system (روش دوم در بخش قبل) برنامه ls را به عنوان یک برنامه خارجی فراخوانی می کند:

#include <stdlib.h>
int main() {
  system("ls");
}

اگر به کد بالا دقت کنیم مسیر مطلق یا Absolute Path برای برنامه ls که bin/ls/ باشد به تابع ()system ارائه نشده است. طبیعی است که چون محل وجود این برنامه (فرمان / Command) مشخص نیست، شل از متغیر PATH استفاده می کند تا مکان برنامه ls را پیدا کرده و آن را اجرا کند.
حال برنامه ای می نویسیم که bash را فراخوانی کند و نام این برنامه را ls می گذاریم!!!

#include <stdlib.h>
int main {
  system("/bin/bash");
}

برنامه اول را کامپایل کرده و آن را یک برنامه Set-UID قرار می دهیم:

$ gcc prog1.c -o prog1
$ sudo chown root prog1
$ sudo chmod 4755 prog1

قبلا در مقاله Capability Leaking گفتیم که ۴ در ۴۷۵۵ برنامه را یک برنامه Set-UID قرار می دهد. حال برنامه را اجرا می کنیم و نتیجه زیر را دریافت می کنیم (توجه کنید این نتیجه روی کامپیوتر من است و قطعا نتیجه شما متفاوت خواهد بود!):

prog1

حال برنامه دوم (که مهاجم نوشته است!) را کامپیال کرده و مسیر نقطه (.) را به ابتدای متغیر PATH اضافه کنید و در نهایت تغییر در متغیر PATH را مشاهده کنید: 

$ gcc ls.c -o ls
$ export PATH=.:$PATH
$ echo $PATH

اگر دقت کنید در ابتدای این متغیر، مکان نقطه (.) که مکان فعلی (جایی که برنامه دوم در آن قرار دارد) اضافه شده است:

echo $PATH

طبیعی وقتی تابع ()system شل را برای اجرای برنامه (فرمان) ls اجرا می کند، شل با استفاده از متغیر PATH که حالا اولین مکان تعریف شده برای آن مکان نقطه (.) یعنی مکان فعلی است می باشد سریعا برنامه ای به نام ls (برنامه دوم) پیدا می کند و آن را اجرا می کند! اما برنامه دوم واقعا ls نیست و یک شل است آن هم با مجوز روت (root)!

root shell

مشاهده می شود که با اجرای برنامه اول یک شل (بش / bash) برگردانده شد که دارای شناسه کاربری موثر (Effective userId \ euid) صفر، یعنی روت (root) می باشد و این به معنی گرفتن یک روت شل و دسترسی به کل سیستم است.
نمونه آسیب پذیری فوق را می توانید در لینکر پویای سیستم عامل مکینتاش نسخه ۱۰.۱۰ مشاهده کنید که در این پست توضیح داده ایم. اکسپلویت کردن این آسیب پذیری را در پست های بعدی توضیح خواهیم داد.

سخن پایانی

در این مقاله از سری مقالات امنیت نرم افزار آکادمی ترجنس یکی دیگر از اسیب پذیری هایی که بر اثر عدم دانش امنیتی توسعه دهنده و استفاده نکردن از DevSecOps رخ می دهد را بررسی کردیم. ورودی های یک برنامه مولفه هایی جذاب برای نفوذ و اکسپلویت می باشند. حال اگر این ورودی ها، ورودی های غیرمستقیمی مثل متغیرهای محیطی باشند که از دید توسعه دهنده پنهان است موضوع جذاب تر شده می توان برای حمله روی آن ها سرمایه گذاری کرد. در پست های بعدی اکسپلویت کردن آسیب پذیری های نرم افزاری در سیستم عامل های مختلف و همچنین معرفی آسیب پذیری های دیگر را ارائه می دهیم.

ارسال یک پاسخ