حملههای تزریق SQL — چگونه با آشکارسازی مقابله کرده و سد دفاعی را دور بزنیم
غالباً گفته میشود که بهترین هکرها ناشناس میمانند و بزرگترین حملهها کشف نمیشوند؛ اما برای یک تست کننده نفوذ خوش آتیه یا هکر کلاه سفید، هر گونه یادگیری بدون نقض یکی از اصول فوق کار دشواری محسوب میشود. در هر صورت هدف نهایی ما در این سری از نوشتهها با موضوع تزریق SQL این است که گزاره فوق را تا حد امکان در زمان هکهای خودمان رعایت کنیم.
زمانی که یک حملهکننده مشغول تست تزریق اسکیوال است به طور مکرر بر روی ورودیهای کاربری که در سمت سرور فیلتر نشدهاند تلاش میکند تا موفق به نفود شود. اما وقتی همه چیز در سمت سرور به درستی فیلتر شده است چه باید کرد؟ روشهای مختلفی برای دور زدن این سد دفاعی وجود دارد که از تکنیکهایی بهره میگیرند که از برخی خصوصیات SQL سوء استفاده میکنند.
روش یکم: فضای خالی
روش نخست که میتوانیم برای اجتناب از تشخیص امضا استفاده کنیم، فضای خالی (White Space) است. افزودن فضاهای خالی یا کاراکترهای خاص مانند tab یا new line بر عبارتهای اسکیوال تأثیر نمیگذارد؛ اما شاید بتواند محمولههای مخرب را از سد فیلترها عبور دهد.
برای مثال:
SELECT * FROM Users WHERE id =1
این عبارت دقیقاً همان عبارت زیر را اجرا میکند:
SELECT * FROM Users WHERE id=1
یک کاراکتر tab یا new line نیز تأثیری بر عبارت نخواهد داشت:
SELECT * FROM Users WHERE id=1
روش دوم: بایتهای null
در اغلب موارد فیلترها باعث توقف اجرای برخی کاراکترهای خاص در عبارتهای اسکیوال میشوند. این احتمالاً یکی از رایجترین روشهای توقف اجرای حمله است، زیرا بدون کاراکترهای خاصی مانند آپستروف یا خط تیره، احتمال موفقیت تزریق بسیار پایین میآید.
یک روش برای دور زدن این محدودیت استفاده از بایتهای نال (%00) در ابتدای هر کاراکتر مسدود شده است. برای نمونه اگر بدانیم که یک برنامه آپستروف را مسدود میکند، تزریق زیر میتواند فیلتر را گمراه کرده و اجازه عبور بگیرد:
%00' or 1=1--
روش سوم: انکودینگ URL
روش دیگر برای اجتناب از شناسایی از طریق انکودینگ URL است. این نوع از انکودینگ برای ارسال اطلاعات آدرس وب بر روی اینترنت از طریق HTTP استفاده میشود. از آنجا که URL ها میتوانند تنها شامل مقادیر ASCII باشند، هر کاراکتر غیر معتبری باید به صورت کاراکترهای معتبر ASCII انکود بشود. URL ها نمیتوانند شامل اسپیس باشند و از این رو معمولاً اسپیس به صورت یک علامت + یا %20 تبدیل میشود. با ایجاد کوئری SQL مخرب از طریق انکودینگ URL این امکان ایجاد میشود که فیلترها را دور زد. برای مثال به تزریق زیر توجه کنید:
' or 1=1--
با استفاده از انکودینگ URL چیزی شبیه زیر خواهد بود:
%27%20or%201%3D1--
روش چهارم: انکودینگ Hex
انکودینگ Hex موجب جایگزینی کاراکترها در عبارت اصلی SQL با مقادیر معادل هگزادسیمال میشود. سیستم عددی هگزادسیمال به صورت سیستمی بر مبنای شانزده نیز نامیده میشود که از شانزده نماد برای نمایش مقادیر 0 تا 15 استفاده میکند. اعداد 0 تا 9 به همان صورت که هستند نمایش مییابند اما حروف A تا F برای نمایش مقادیر 10 تا 15 استفاده میشوند.
با وارد کردن دستور man ascii در ترمینال و کمی اسکرول کردن میتوانید جدول فشردهای از مقادیر هگزادسیمال را مشاهده کنید.
Tables For convenience, below is a more compact table in hex. 2 3 4 5 6 7 ------------- 0: 0 @ P ` p 1:! 1 A Q a q 2: " 2 B R b r 3: # 3 C S c s 4: $ 4 D T d t 5: % 5 E U e u 6: & 6 F V f v 7: ' 7 G W g w 8: (8 H X h x 9: ) 9 I Y i y A: *: J Z j z B: +; K [k { C:, < L \ l | D: - = M ] m } E:. > N ^ n ~ F: /? O _ o DEL
این سیستم عددی استفاده زیادی در مهندسی رایانه و برنامهنویسی دارد، زیرا بازنمایی خواناتری از مقادیر دودویی ارائه میکند و به طور مؤثرتری میتواند اعداد بزرگتر را با ارقام کمتری نمایش دهد. با استفاده از انکودینگ Hex بر روی عبارتهای SQL میتوان از شناسایی حمله تزریق جلوگیری کرد. برای مثال:
SELECT * FROM Users WHERE name='admin'--
معادل انکود شده hex آن چنین است:
SELECT * FROM Users WHERE name=61646D696E--
به طور جایگزین میتوانیم از تابع ()UNHEX برای رسیدن به همان نتایج استفاده کنیم:
SELECT * FROM Users WHERE name=UNHEX('61646D696E')--
روش پنجم: انکودینگ کاراکتر
طرز کار انکودینگ کاراکتر مشابه انکودینگ Hex است و در آن کاراکترها در عبارت اسکیوال اصلی با مقادیر تبدیل شده جایگزین میشوند. این نوع از انکودینگ از تابع CHAR() برای انکود کردن کاراکترها به صورت مقادیر دهدهی استفاده میکند.
همانند روش قبلی با وارد کردن دستور man ascii در ترمینال میتوان یک جدول دهدهی فشرده را مشاهده کرد:
Tables For convenience, below is a more compact table in decimal. 30 40 50 60 70 80 90 100 110 120 --------------------------------- 0: (2 < F P Z d n x 1: ) 3 = G Q [e o y 2: * 4 > H R \ f p z 3:! + 5? I S ] g q { 4: ", 6 @ J T ^ h r | 5: #- 7 A K U _ i s } 6: $. 8 B L V ` j t ~ 7: %/ 9 C M W a k u DEL 8: & 0: D N X b l v 9: ' 1; E O Y c m w
نگاهی به کوئری زیر بیندازید:
SELECT * FROM Users WHERE name='admin'--
با استفاده از انکودینگ کاراکتر، عبارت فوق به صورت زیر در میآید:
SELECT * FROM Users WHERE name=CHAR(97,100,109,105,110)--
روش ششم: الحاق رشته
روش دیگری که برای دور زدن فیلترها استفاده میشود، الحاق رشتهای است. ما قبلاً در نوشته «تزریق SQL پیشرفته»---------(https://blog.faradars.org/sql-injection-fingerprint-databases-perform-general-reconnaissance-successful-attack/) در مورد کارکرد الحاق رشتهای توضیح دادیم، اما همان مفهوم را در اینجا نیز میتوانیم استفاده کنیم. در اغلب موارد با تقسیم کلیدواژهها در کوئری خرابکارانه SQL میتوان از شناسایی آن جلوگیری کرد. به یاد داشته باشید که الحاق رشتهای در سیستمهای پایگاه داده مختلف به طرز متفاوتی عمل میکند. به عبارتهای زیر نگاه کنید:
SELECT * FROM Users WHERE id=1
با استفاده از الحاق رشتهای در مایاسکیوال میتوانیم یک کوئری جعل کنیم که به طور بالقوه فیلترها را دور بزند:
CONCAT('SEL', 'ECT') * FROM Users WHERE id=1
این کوئری در مایاسکیوال چیزی شبیه عبارت زیر است:
'SEL' + 'ECT' * FROM Users WHERE id=1
در پستگرس اسکیوال:
'SEL' || 'ECT' * FROM Users WHERE id=1
و در اوراکل (دو گزینه وجود دارد):
CONCAT('SEL', 'ECT') * FROM Users WHERE id=1
'SEL' || 'ECT' * FROM Users WHERE id=1
روش هفتم: توضیحات (Comments)
سوء استفاده از روشی که اسکیوال توضیحات درونخطی را مدیریت میکند نیز میتواند به دور زدن فیلترها و جلوگیری از شناسایی کد مخرب در زمان اجرای حملههای تزریق اسکیوال کمک کند. از آنجا که ممکن است در یک کد چند توضیح وجود داشته باشد و همچنان نیز معتبر باشد میتوانیم از آنها برای شکستن کوئری و دور زدن احتمالی هر گونه فیلتر موجود استفاده کنیم. برای نمونه میتوانیم توضیحاتی را بین کلیدواژهها به صورت زیر درج کنیم:
SELECT/**/*/**/FROM/**/Users/**/WHERE/**/name/**/=/**/'admin'--
روش هشتم: ترکیبها
گاهی اوقات حتی این تکنیکهای گمراهی امضا نیز به تنهایی نمیتوانند موفق باشند؛ اما میتوانیم آنها را با هم ترکیب کنیم تا شانس دور زدن موفق سد دفاعی و انجام حمله افزایش یابد. برای مثال فرض کنید فیلتری بر روی یک برنامه که در حال حمله داریم، امکان درج کاراکترهای توضیح را نمیدهد. برای حل این مشکل میتوانیم یک کوئری را جعل کنیم که این کاراکترها را در تلاش برای فریب فیلتر و عبور از آن ترکیب کند. کوئری اولیه که شکست میخورد چنین است:
SELECT/**/*/**/FROM/**/Users/**/WHERE/**/name/**/=/**/'admin'--
همین کوئری با استفاده از انکودینگ URL جهت پوشش کاراکترهای توضیحات به صورت زیر در میآید:
SELECT%2F%2A%2A%2F%2A%2F%2A%2A%2FFROM%2F%2A%2A%2FUsers%2F%2A%2A%2FWHERE%2F%2A%2A%2Fname%2F%2A%2A%2F%3D%2F%2A%2A%2F%E2%80%99admin%E2%80%99--
میتوان هر یک از این روشها را با هم ترکیب کرد تا فیلترهای مزاحم را کنار زده و بدین ترتیب شانس موفقیت اجرای حمله تزریق اسکیوال را تا حد زیادی افزایش داد.
روش نهم: تزریقهای درجه دوم
روش نهایی که برای کمک به گمراهی امضا استفاده میکنیم کمی پیچیدهتر است؛ اما بسته به نوع پیکربندی پایگاه داده این نوع از حمله میتواند در صورتی که همه انواع دیگر شکست میخورند، کمک زیادی بکند.
حملههای تزریق درجه دوم زمانی رخ میدهند که برنامههای وب یا پایگاه داده ورودیهای از سوی کاربر را به درستی فیلتر کرده باشند؛ اما پس از این که کوئری اولیه از سد فیلتر عبور کرده و اعتبار سنجی شد هیچ گونه آلودگیزدایی دیگری روی آن انجام نمیدهند. زمانی که برنامه کارکردهای دیگری برای استفاده از پایگاه داده ارائه میکند، کوئری اسکیوال ما به صورت دینامیک اجرا شده و کد مخرب را اجرا میکند. بدین ترتیب میتوان تصور کرد که این نوع حمله دو مرحله متمایز دارد. ابتدا کوئری اولیه که کد مخرب را درون کد معمولی جاسازی کرده است از سد فیلترها عبور میکند و سپس پروسه دیگری این کد را در زمان دیگری اجرا میکند.
یکی از تکنیکهای رایج کاهشی این است که هر گیومه تکی که درون ورودی کاربر وجود دارد را پیش از این که کوئری روی پایگاه داده اجرا شود به گیومه دوتایی تبدیل کنیم. فرض کنید برنامهای داریم که به کاربر امکان ایجاد یک حساب کاربری میدهد و همچنین کارکرد ریست رمز عبور را دارد. زمانی که یک حساب ایجاد میشود کوئری اسکیوال چیزی شبیه زیر خواهد بود:
INSERT INTO Users (username, password) VALUES ('johndoe''', 'hunter2')
این کد هیچ مشکلی برای پایگاه داده ایجاد نمیکند، زیرا هر زمان که گیومههای تکی به گیومههای دوتایی تبدیل میشوند عبارت همچنان معتبر باقی میماند. اینک فرض کنید بخواهیم رمز عبور خود را تغییر دهیم. کوئری که به پایگاه داده ارسال میکنیم چیزی شبیه زیر خواهد بود:
SELECT password FROM Users WHERE username='johndoe''
از آنجا که مقدار نام کاربری که در پایگاه داده ذخیره شده است رشته 'johndoe' است، اینک یک رخنه تزریق اسکیوال باز شده است زیرا ورودی اولیه دیگر فیلتر نمیشود. برای بهرهبرداری از این نقطهضعف تنها کاری که باید انجام دهیم این است که یک نام کاربری حاوی کد مخرب به صورت زیر ایجاد کنیم:
UNION ALL SELECT * FROM Users WHERE username='admin'--
خود فرایند ایجاد حساب کاربری به طور موفق اجرا میشود؛ اما زمانی که میخواهیم رمز عبور را تغییر بدهیم، کوئری خرابکارانه اجرا خواهد شد و از این رو اعتبارسنجی ورودی را دور می زند.
سخن پایانی
همانطور مشاهده کردید تکنیکهای زیادی وجود دارند که میتوان برای دور زدن فیلترها و جلوگیری از شناسایی در زمان اجرای حملههای تزریق اسکیوال مورد استفاده قرار داد. این روشها علاوه بر افزایش شانس موفقیت حمله تزریق اسکیوال، میتوانند باعث ناشناس ماندن شما نیز بشوند که به طور کلی در زمان هک کردن بسیار مهم است.
اگر این نوشته مورد توجه شما قرار گرفته است، احتمالاً به موارد زیر نیز علاقهمند باشید:
- آموزش کاربردی SQL Server
- حفاظت از وبسایت PHP در برابر حملههای تزریق SQL
- آموزش پایگاه داده ها
- تزریق SQL پیشرفته — انگشتنگاری پایگاه داده و شناسایی عمومی برای اجرای حملهای مؤثرتر
- آموزش کار با دستورات پایگاه داده در SQL Server
- اصول پایگاه داده و SQL — همه آن چه یک هکر باید بداند
- آموزش SQL Server Management Studio | کامل، رایگان و گام به گام
==