هر کسی با هر پیشزمینهای هستید، وقتهای پیش میآید که ممکن است بخواهید یک حمله SQL Injection را روی یک سایت اجرایی کنید. چه یک برنامهنویس فریلنسر یا مستقل باشید که میخواهید از امنیت سایت خود مطمئن شوید، چه یک متخصص امنیتی یا یک هکر کلاه سفید باشید که با اجازه صاحب سایت میخواهید به آن نفوذ کنید و یا حتی اگر فردی بدون هیچ ارتباطی با علوم کامپیوتر و cybersecurity باشید که صرفاً دنبال یک سرگرمی عصرانه در یک محیط کنترلشده است. البته احتمالا کسانی هم هستند که به قصد بدی میخواهند این حمله را انجام دهند؛ اگر شما جز این دسته هستید پیشنهاد میکنم که دست نگه دارید و کمی بیشتر فکر کنید و این صفحه را هم به کل ببندید! اما اگر تازهکاری از دستههای قبل هستید که لازم است این حمله را یاد بگیرید، میتوانید یک حملهی ساده را با دنبال کردن مطلب زیر پیادهسازی کنید. البته فرض این مطلب بر آن است که مقدمات سیکوئل اینجکشن را بلد هستید. اگر هیچ آشناییای با این حمله ندارید با خواندن مقالهی «حمله SQL Injection چیست و چگونه عمل میکند؟» برای مطالب این مطلب آماده میشوید. علاوه بر SQL کمی هم از دانش وب استفاده میکنیم که در خود مطلب توضیح آن داده میشود.
در این مقاله میخواهیم به طور عملی چند حملهی SQL Injection روی وب اپلیکیشن OWASP Juice Shop پیادهسازی کنیم. نگران نباشید کار خلافی نمیکنیم! این وب اپلیکیشن اصلا برای همین کارها ساخته شده است! به گفتهی خودشان جوس شاپ مدرنترین وباپلیکیشن ناامن است! جوس شاپ شامل انواع مشکلات امنیتی هست اما ما میخواهیم فقط روی ضعفهای sql injection تمرکز کنیم. برای یادگیری بهتر میتوانید همراه من پیش بیایید و خودتان انجام دهید.
راهاندازی و استفاده از این وب اپلیکشن روشهای مختلفی دارد مثلا میشود از node.js یا Docker و یا Vagrant یا خیلی روشهای دیگر استفاده کرد که توضیحات آنها را به صورت دقیق در گیتهاب جوس شاپ میتوانید پیدا کنید. اما در این مطلب برای اینکه درگیر یادگیری این ابزارها نشویم از گزینهی راحتتر Heroku استفاده میکنیم که همهی کارهای راهاندازی اپلیکیشن را برای ما انجام میدهد. کافی است در Heroku ثبت نام کنید، وارد اکانتتان شوید و سپس در صفحه گیتهاب جوس شاپ گزینهی Deploy to Heroku رو بزنید.
احتمالا بسته به زمانی که این مطلب را میخوانید حتی نیاز به ساخت اکانت نداشته باشید و بتوانید وارد جوس شاپی که به اکانت من در Heroku وصل است بشوید: peaceful-beach-07946.herokuapp.com
پس از آن صفحهای میآید که در آن میتواند نام و ریجن اپ خود را تغییر دهید (یا ندهید!) و صبر کنید تا اپلیکیشن ساخته شود. پس از اتمام آن گزینهی Manage App را بزنید که وارد صفحه اپلیکیشن خود شوید. حالا برای باز کردن جوس شاپ کافی است روی گزینهی Open app را در بالا سمت راست کلیک کنید و کار تمام است! حالا یک ساخت وب اپلیکیشن جوس شاپ در اختیار داریم تا هر حملهای که میخواهیم روی آن پیاده کنیم!
اخطار: البته اگر همراه این مقاله از Heroku استفاده میکنید این نکته یادتان باشد که در این روش نمیتوان (و نباید) حملهی DDoS اجرا کرد چون سرورها برای Heroku اند و نه جوس شاپ.
حالا بعد از بستن پیام توضیحات و قبول کردن کوکیها، (برای ذخیره کردن پیشرفت در نفوذ به سایت از کوکی استفاده میشود) با صفحهی اصلی جوس شاپ که یک سایت خرید آبمیوه هست روبهرو میشویم که در عکس پایین میتوانید آن را ببینید. (که در صورتی که خودتان در Heroku اکانت ساخته باشید آدرس متفاوتی در مرورگر میبینید.) اگر همراه با من پیش میآیید در جوس شاپ خودتان کمی گشت و گذار کنید تا ببینید چه مشکلات احتمالیای پیدا میکنید.
خب دیگر دست دست نکنیم و کاری که برایش اینجاییم را شروع کنیم! در بالا سمت راست در قسمت اکانت وارد صفحهای لوگین شوید. اول با امتحان کردن لوگین شروع میکنیم و فقط در قسمت یوزر و پسورد یک تک کوتیشن خالی میگذاریم تا ببینیم سایت چگونه با آن برخورد میکند. میبینیم که سایت ارور میدهد که این نشانهی خوبی هست. از طرف جوس شاپ پیامی هم میگیریم که یک چالش سایت را حل کردیم که گرفتن اروری است که خوب هندل نشده.
ارور [object Object] مربوط به سیکوئل نیست بلکه از طرف جاواسکریپت و احتمالا فانکشن stringify میآید پس راجع به RDBMS به ما اطلاعاتی نمیدهد.
قبل از اینکه ادامه مطلب و راه حل را بخوانید سعی کنید خودتان وارد شوید. چون نمیدانیم کوئری چیست باید ورودیهای مختلفی را امتحان کنیم تا به ورودی درست برسیم. تک کوتیشن یا دابل کوتیشن، -- یا # برای کامنت کردن، کوئری یوزر و پسوورد جدا از هماند یا نه و گزینههای دیگر را امتحان کنید.
خب حالا که برگشتید (یا شاید هم اصلا نرفته بودید!) راه حل اصلی را میتوانید در زیر ببینید.
بعد از امتحان کردن ورودیهای مختلف این یکی از روشهایی است که میتوان وارد اکانتی در جوس شاپ شد. LIMIT از آن روشهایی است که اکثرا یا اصلا از آن اطلاع ندارند و یا فراموشش میکنند. اکثر سایتها سیستمی دارند که اگر کوئری لوگین نتیجهای به جز یک یا هیچ خط داشته باشد اجازه دسترسی نمیدهند، یک راه دور زدن این در بعضی موارد استفاده از LIMIT است که نتیجه را به خط اول محدود میکند و یک پوئن مثبت دیگرش این است که خط اول معمولا اولین اکانت ثبت شده در دیتابیس است که در بیشتر مواقع اکانتی با دسترسی ادمین است که در جوس شاپ هم ما دقیقا به همین نتیجه میرسیم. اگر LIMIT در این موقعیت به یادتان نیامد هم مشکلی نیست صفحه اصلی جوس شاپ را اگر کمی با دقت گشته باشید، در بعضی محصولات نظراتی وجود دارند که ایمیل نظردهنده (که ایمیل ادمینستر علاوه بر یوزرهای دیگری بین آنها هست) هم در آنها وجود دارد که با استفاده از آنها به روش معمول بدون لیمیت هم میتوانیم وارد اکانتی در سایت شویم.
پینوشت: ظاهرا اصلا در اینجا نیازی به لیمیت نداریم زیرا سایت نتیجه کوئری را به صفر و یک محدود نکرده است و با نتیجه چند خط وارد کاربر اولین خط میشود. (همان ادمین)
این ورودمان هم چالش دیگری در جوس شاپ بود. اگر کمی اطلاعات مربوط به جوس شاپ را بخوانیم میفهمیم که این سایت قسمت امتیازات یا اسکوربوردی هم دارد که این پیشرفتمان در چالشها را در آنها (با استفاده از کوکی) ثبت میکند. اما با کمی گشت و گذار در سایت میبینیم که نمیتوانیم همچین صفحه و اسکوربوردی در جایی پیدا کنیم! شاید پیدا کردن این صفحه هم به کمی کارآگاهی نیاز دارد! راهها یا pathهای یک سایت معمولا در جاوااسکریپت فرانتاند آنها وجود دارد پس شاید بتوانیم با کمی گشت و گذار در سورس چیزی پیدا کنیم. اگر نمیدانید از چی حرف میزنم اشکالی ندارد قدم به قدم راه را نشان میدهیم.
برای دیدن جاوااسکریپت و سورس صفحه و اطلاعات راجع به فرانتاند یک سایت و خیلی چیزهای دیگر میتوانیم از Developer Tools مرورگر استفاده کنیم. در کروم برای باز کردن آن چند روش داریم. سه نقطهی بالا سمت چپ را بزنید More tools و سپس Developer tools را انتخاب کنید، روی صفحه کلیک راست کنید و گزینهی Inspect را انتخاب کنید و یا راحتتر از همه کنترل، شیفت و حرف I را با هم بزنید. (Ctrl+Shift+I) باز کردن آن در مرورگرهای دیگر هم به همین راحتیست اما جزئیاتش را به خودتان میسپارم. حالا تب Sources را انتخاب کنید.
در Sources کنترل + P بزنید تا لیست فایلها را ببینیم. معمولا pathهای یک سایت در فایل جاوااسکریپت main هستند پس main.js را باز کنید.
حالا فایل main را داریم اما زیاد خواندنش راحت نیست. در کروم میتوانید در قسمت پایین سمت چپ کد علامت {} را ببینید که اگر روی آن بزنید فایل را برایتان به فرمت قابل خواندن در میآورد. حالا کافی است در این فایل سرچ کنیم تا ببینیم مسیری به اسکوربورد وجود دارد یا نه. ctrl + shift + f جعبهی سرچی را باز میکند. حالا کلمه score را سرچ میکنیم تا ببینیم چیزی به تورمان میخورد یا نه. در نتایج اگر نگاه کنید میبینیم که یک path داریم به نام score-board یعنی کافی است در لینک سایت score-board اضافه کنیم تا به صفحه امتیازات برویم. (بعد از این گزینهی score board را در منوی سمت چپ سایت هم داریم)
این مطلب برای یادگیری SQL Injection است پس بگذارید ببینیم چالشهای جوس شاپ برای این حمله چیستند. در ردیف بالا Show all را بزنید سپس در ردیف پایین ابتدا Hide all و سپس روی Injection کلیک کنید. حالا لیستی از چالشهای نوع اینجکشن داریم.
خب حالا بریم تا چالش با سختی سه ستاره پیدا کردن اسکیمای دیتابیس را انجام دهیم. معمولا چنین نفوذی را از صفحه سرچ انجام میدهند پس بریم یک نگاهی به امنیت آن بیاندازیم. اگر در سرچ بار و یا متغییر q در لینک تک کوتیشن، دابل کوتیشن، نقطه ویرگول، علامتهای کامنت کردن و ترکیب آنها را امتحان کنیم میبینیم که جستجو در مقابل نفوذ امن است. حالا چی؟ شاید باز هم باید ذرهبین کارآگاهی دستمان بگیریم. Dev tools را دوباره باز کنید اما این بار به تب network بروید. صفحه را ریلود کنید تا ریکوئستها لاگ بشوند. اگر کمی در ریکوئستها نگاه کنیم یک ریکوئست GET با url زیر میبینیم:
https://peaceful-beach-07946.herokuapp.com/rest/products/search?q=
این لینک با لینکی که موقع سرچ در خود سایت میبینیم فرق میکند. ممکن است لینکی باشد که از ورژنهای قبلی سایت باقی مانده باشد یا چیز دیگر. به هر حال لینک را کپی کنید و در مرورگر پیست و اجرا کنید. میبینیم که با صفحهی عجیبی مواجه میشویم. اما با کمی دقت میتوان فهمید که در واقع همان نتایج سرچ را به صورت نوشته داریم میبینیم.
حالا باید ببینیم این سرچ هم در مقابل نفوذ امن است یا نه. (باید در مقابل q در لینک ورودیهای مد نظرتان را وارد کنید) خودتان اول سعی کنید اروری بگیرید و بعد برگردید.
احتمالا خودتان توانستین ارور بگیرید اگر نه یکی از راههای گرفتن آن قرار دادن «;'» است که با آن ارور زیر را میگیریم.
خب داریم جلوتر میرویم، با این ارور هم میفهمیم که این سرچ بر خلاف سرچ اصلی سایت در مقابل نفوذ امن نیست و هم اینکه DBMS استفاده شده SQLite است که این دانش برای قسمت بعدی مهم است. میخواهیم DB schema جوس شاپ را پیدا کنیم. این اطلاعات در کجا ثبت میشود. اگر به faq سایت sqlite بروید در سوال هفتم این جواب را پیدا میکنیم. SQLITE_SCHEMA جدولی مخصوص sqlite است که نام تمام جدولهای پایگاه داده در ستون tbl_name آن ثبت میشود. علاوه بر آن ستونی به نام sql دارد که کوئری اولیه ساخت جدولها در آن است که با آن هم نام جدولها و هم نام ستونهایشان را پیدا میکنیم. حالا کافی است با استفاده از UNION نام این جدولها را پیدا کنیم. پس از امتحان کردن خودتان به بخش بعد بروید تا راه حل را ببینید.
اول از همه راه بستن کوئری را باید پیدا کنیم که بعد از بررسی عبارتهای معمول به «--(('» میرسیم که همهی اجسام فروشگاه را به ما برمیگرداند. حالا برای یونیون کردن باید بفهمیم نتیجهی سرچ چند ستون برمیگرداند. معمولا برای این کار نیاز به امتحان و خطا داریم تا تعداد ستونها را پیدا کنیم. اما در این مورد به خصوص کافی است تعداد نتایج یک جسم را بشماریم.
{"id":1, "name":"Apple Juice (1000ml)", "description":"The all-time classic.", "price":1.99, "deluxePrice":0.99, "image":"apple_juice.jpg", "createdAt":"2022-06-20 16:00:31.888 +00:00", "updatedAt":"2022-06-20 16:00:31.888 +00:00", "deletedAt":null}
در بالا آبمیوهی سیب را داریم که در آن قسمتهای بولد شده نام ستونها هستند و با شمردن آنها میفهمیم که در UNION باید ۹ ستون داشته باشیم. برای امتحان کوئری زیر را در لینک مینویسیم که در نتیجه میتوانیم ببینیم که اولی خطمان نتایج اعدادی که گذاشتیم را دارد:
https://peaceful-beach-07946.herokuapp.com/rest/products/search?q=')) UNION SELECT 1, 2, 3, 4, 5, 6, 7, 8, 9 --
نکته: اگر کوئری را به طور معمولی در قسمت url بنویسید کروم به طور خودکار آن را تبدیل به url صحیح میکند.
حالا کافی است ستون sql از SQLITE_SCHEMA را با کوئری زیر به دست آوریم. جهت کم شدن نتایج و خواناتر شدن لیست قبل کوتیشن کلمهای بیمعنی اضافه کنید که نتیجهای از اجسام نداشته باشیم.
https://peaceful-beach-07946.herokuapp.com/rest/products/search?q=nothing')) UNION SELECT sql, 2, 3, 4, 5, 6, 7, 8, 9 FROM sqlite_schema --
و بالاخره اسکیمای دیتابیس را به دست آوردیم. هرچند کمی خواندنش سخت است!
اگر الان به اسکوربورد نگاه کنید میبینیم که چالش اسکیما را حل کردهایم اما صبر کنید هنوز همینجا که هستید بمانید! یک چالش دیگر پیدا کردن اطلاعات ورود کاربرهاست. حالا که اسکیما را داریم به راحتی از همین روش میتوانیم این چالش را نیز حل کنیم. این هم خودتان حل کنید و بعد ادامه را بخوانید.
راهنمایی: برای فرمت کردن JSON (نتایج این سرچ به صورت JSON است) ابزارهای آنلاین زیادی وجود دارد. مثلا میتوانید از این سایت استفاده کنید.
با خواندن اسکیما میبینیم که جدولی به نام Users داریم با ستونهای username email password. (پسوردها به صورت هش شدهاند.)
https://peaceful-beach-07946.herokuapp.com/rest/products/search?q=nothing')) UNION SELECT username, email, password, 4, 5, 6, 7, 8, 9 FROM Users --
حالا میتوانید قسمت سرچ را ترک کنید اما ستونهای جدول Users را یادتان بماند در ادامه آنها را لازم داریم. اگر الان اسکوربورد را ببینید هر دو چالشهای قبلی حل شدهاند. خب حالا قبل از اتمام مطلب یک چالش نهایی جالب را حل میکنیم. چالشی که خواسته با کاربری با ایمیل acc0unt4nt@juice-sh.op که در حال حاضر وجود ندارد بدون ثبت نام وارد سایت شوید.
دوباره به صفحهی لوگین برگردید و Dev tools را باز کنید و باز به تب نتورک بروید. حالا ارور [object Object] را دوباره بگیرید. حالا در تب نتورک به login بروید. در اینجا میتوانیم کوئریای که لوگین استفاده میکند را پیدا کنیم. (بله در قسمت لوگین هم میشد از این طریق کوئری را پیدا کرد و با آزمون و خطا پیش نرفت!)
SELECT * FROM Users WHERE email = ' ' AND password = ' ' AND deletedAt IS NULL
کمی فکر کنیم. چطور میتوانیم سایت را گول بزنیم که با اکانتی که در جدول یوزرز نیست وارد شویم؟ مثلا اگر بتوانیم با روشی خطی به نتایج اضافه کنیم که در اصل در جدول Users نباشد... بله درست است! این بار هم یار همیشگیمان UNION به کارمان میآید. دقت کنید که کوئری با * خط را میآورد. یعنی اگر بخواهیم یونیونمان موفق باشد باید همهی ستونهای یوزرز را بیاوریم که هم تعداد درست باشه هم سایت با موفقیت گول بخورد و برایمان session ایجاد کند. ستونهای یوزرز را در مرحله قبل پیدا کردیم حال کافی است از آن استفاده کنیم. قبل از خواندن راه حل، خودتان سعی کنید کوئری درست را بنویسید.
' UNION SELECT * FROM (SELECT 15 as 'id', '' as 'username', 'acc0unt4nt@juice-sh.op' as 'email', '12345' as 'password', 'accounting' as 'role', '123' as 'deluxeToken', '1.2.3.4' as 'lastLoginIp' , '' as 'profileImage', '' as 'totpSecret', 1 as 'isActive', '1999-08-16 14:14:41.644 +00:00' as 'createdAt', '1999-08-16 14:33:41.930 +00:00' as 'updatedAt', null as 'deletedAt')--
امیدوارم این مطلب برایتان مفید واقع شده باشد.
معرفی، توضیح، راهنمایی و راه حل همهی چالشهای جوس شاپ
چالشهای SQL Injection بیشتر:
RedTigers Hackit
RingZer0 Online CTF Challenges
نویسنده: پرنیا اسحاقی | Parnia Eshaghi
دانشگاه آزاد اسلامی تهران مرکز
کلاس پایگاه داده
استاد: دکتر مریم حاجی اسمعیلی | دکترای علوم کامپیوتر از دانشگاه کینگستون لندن
Dr.Maryam Hajiesmaeili | PhD of computer science from Kingston university of London
در لینکدین ببینید.