کمتر از ۲۰ روز پیش در این پست در مورد ضعف امنیتی WHMCS نوشتم. این نرم افزار که به عنوان سیستم پشتیبانی و مدیریت کلاینت ها در بسیاری از سرویس دهنده های میزبانی سایت استفاده می شه در نسخه جدید خود همچنان دارای نواقصی است.
PHP از نسخه ۵.۴.۰ استفاده از register_globals رو حذف کرد به این دلیل که تعریف متغیرها در سطح گلوبال باعث می شد متغیرها به وسیله کاربر تغییر کنند و این مورد ضمن اینکه یک سری کاربردهایی می تونست داشته باشه، به شدت می تونست خطرناک هم باشه.
خب حالا بیایم یه نگاهی به فایل dbfunctions.php این نرم افزار بندازیم، جایی که دستورهای ارسالی به دیتابیس رو هندل می کنه:
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 | <?php function select_query($table, $fields, $where, $orderby = '', $orderbyorder = '', $limit = '', $innerjoin = '') { global $CONFIG; global $query_count; global $mysql_errors; global $whmcsmysql; if (!$fields) { $fields = '*'; } $query = 'SELECT ' . $fields . ' FROM ' . db_make_safe_field($table); if ($innerjoin) { $query .= ' INNER JOIN ' . db_escape_string($innerjoin); } if ($where) { if (is_array($where)) { $criteria = array(); foreach ($where as $origkey => $value) { $key = db_make_safe_field($origkey); if (is_array($value)) { if ($key == 'default') { $key = '`default`'; } if ($value['sqltype'] == 'LIKE') { $criteria[] = $key . ' LIKE \'%' . db_escape_string($value['value']) . '%\''; continue; } if ($value['sqltype'] == 'NEQ') { $criteria[] = $key . '!=\'' . db_escape_string($value['value']) . '\''; continue; } if ($value['sqltype'] == '>') { $criteria[] = $key . '>' . db_escape_string($value['value']); continue; } if ($value['sqltype'] == '<') { $criteria[] = $key . '<' . db_escape_string($value['value']); continue; } if ($value['sqltype'] == '<=') { $criteria[] = $origkey . '<=' . db_escape_string($value['value']); continue; } if ($value['sqltype'] == '>=') { $criteria[] = $origkey . '>=' . db_escape_string($value['value']); continue; } if ($value['sqltype'] == 'TABLEJOIN') { $criteria[] = $key . '=' . db_escape_string($value['value']); continue; } if ($value['sqltype'] == 'IN') { $criteria[] = $key . ' IN (\'' . implode('\',\'', db_escape_array($value['values'])) . '\')'; continue; } continue; } [...] ?> |
می بینید که نویسندگان برنامه از متغیرهای گلوبال استفاده کردند. حالا این کجا می تونه آسیب بزنه؟ برای مثال زمانی که کاربرها می خوان ticket ها رو ببینند. اونجا می شه با تذریق کدهای SQL در قالب یک متغیر GET و یا POST اطلاعات دیتابیس رو به دست آورد.
من هم اون مشکل قبلی رو در برخی هاستینگ های ایرانی چک کردم و هم این مشکل رو که متاسفانه نتایج اصلا خوب نبود. از ۱۰ تا هاستینگی که چک کردم ۸ تاشون تا ۲ روز پیش مشکل داشتند و ۲ تاشون رو هم تونستم با نام کاربری و پسورد ادمین به پنل مدیریت وارد بشم.
متاسفانه برخی سرویس دهنده ایرانی کوچکترین توجهی به مسایل امنیتی نکرده و حتی ساده ترین کار که نصب به موقع بسته های به روز رسانی است رو هم انجام نمی دن.
برای اینکه کاربرها بتونن وضعیت میزبانشون رو بررسی کنند و بتونند از میزبان بخوان که کارهای لازم رو انجام بده یک اسکریپت رو آماده کردم که به صورت اتوماتیک این ضعف رو چک می کنه و در صورت نفوذ، نام کاربری ادمین و ایمیلش رو بهتون می ده. البته نسخه اصلی این اسکریپت برای چک کردن گوگل و نفوذ به وصورت رندوم به هاستینگ ها بود و پسوردها رو هم به صورت هش شده در اختیار میذاشت ولی من برای جلوگیری از سو استفاده های احتمالی تغییراتی دادم توش. یکیش اینکه یک آدرس می گیره و بر اساس جستجوی گوگل نیست. دوم اینکه در خروجی، پسوردهای هش شده رو نشون نمی ده.
با استفاده از نتیجه ای که به شما نشون داده خواهد شد می تونید به صورت مستند از هاستینگتون بخواید که به روزرسانی رو انجام بده.
تاکید مجدد: لطفا از این ابزار برای آسیب رسوندن به دیگران استفاده نکنید.
لینک دسترسی به اسکریپت:
1 | http://pentest.ugig.ir/WHMCS/scanner.php |
Pingback: سوال در مورد مشکل امنیتی whmcs
سلام ممنون پس راهکار بدید برای عدم استفاده از global یا تامین امنیتش. بعضی جاها واقعا نمیشه استفاده نکرد!
باید توی کد از super globals استفاده کنید. یعنی از get و post و امثال اون.
مقاله در موردش زیاد هست. چند نمونه ساده رو اینجا ببینید:
http://wiki.dreamhost.com/Register_globals
https://en.wikibooks.org/wiki/PHP_Programming/Configuration:_Register_Globals
بله ولی اینطوری منظورم بود خطرش چیه :
وقتی جایی لازم بشه کلی متغیر رو با global به تابعابع وارد کنیم مثلا.
[php]
$title = ‘The Title’;
function show_html () {
global $title;
$html = load_html(‘index.html’);
$html = ”
$title
…
“;
echo $html;
}
show_html ();
[/php]
استفاده از متغیر global و گزینه register_global با هم فرق داره. اون گزینه سبب می شه که متغیرهای ارسالی به اسکریپت PHP مستقیما با نام متغیر در دسترس باشند و مقدار دهی بشن. اما متغیر global همونیه که استفاده کردید و برای دسترسی داشتن به متغیر در متدهای دیگه است.
بنابراین اگر register_global خاموش باشه، فکر نمی کنم که استفاده از متغیر global مشکلی داشته باشه.