هجمات حقن SQL بواسطة UNION:

عندما يكون أحد التطبيقات عرضة لحق SQL  ويتم إرجاع نتائج الاستعلام ضمن استجابات التطبيق، يمكن استخدام الكلمة الأساسية UNION لاسترداد البيانات من الجداول الأخرى داخل قاعدة البيانات. وهذا يؤدي إلى هجوم حقن SQL بواسطة UNION. 

تتيح لك الكلمة الأساسية UNION تنفيذ استعلام SELECT إضافي واحد أو أكثر و إلحاق النتائج بالاستعلام الأصلي. فمثلاً: 

SELECT a, b FROM table1 UNION SELECT c, d FROM table2 

سيقوم استعلام SQL هذا بإرجاع مجموعة نتائج واحدة بعمودين، تحتوي على قيم من العمودين a و b في table1 والعمودين c و d في table2. 

ولكي يعمل استعلام UNION ، يجب استيفاء متطلبين أساسيين: 

  • يجب أن تقوم الاستعلامات الفردية بإرجاع نفس عدد الأعمدة. 
  • يجب أن تكون أنواع البيانات في كل عمود متوافقة (أو منسجمة) بين الاستعلامات الفردية. 

لتنفيذ هجوم حقن SQL بواسطة UNION، يلزم التأكد من أن هجومك يلبي هذين الشرطين. وعموماً يتضمن هذا معرفة: 

  • كم عدد الأعمدة التي يتم إرجاعها من الاستعلام الأصلي؟ 
  • ما الأعمدة التي يتم إرجاعها من الاستعلام الأصلي والتي تحتوي على نوع بيانات مناسب للاحتفاظ بالنتائج من الاستعلام الذي تم حقنه؟ 

تحديد عدد الأعمدة المطلوبة في هجوم حقن SQL باستخدام UNION: 

عند تنفيذ هجوم حقن SQL بواسطة UNION، هناك طريقتان فعالتان لتحديد عدد الأعمدة التي يتم إرجاعها من الاستعلام الأصلي. 

تتضمن الطريقة الأولى حقن سلسلة من جمل ORDER BY وزيادة فهرس (أو دليل index) العمود المحدد حتى يحدث خطأ. على سبيل المثال، بافتراض أن نقطة الحقن عبارة عن سلسلة مقتبسة داخل جملة WHERE من الاستعلام الأصلي، فستقدم: 

' ORDER BY 1--  ' ORDER BY 2--  ' ORDER BY 3-- 

… إلخ 

تعدل سلسلة الحمولات (payloads) هذه الاستعلامَ الأصلي لترتيب النتائج حسب أعمدة مختلفة ضمن مجموعة النتائج. يمكن تحديد العمود في جملة ORDER BY بواسطة الدليل (index أو رقم الفهرس) الخاص به، لذلك لن تحتاج إلى معرفة أسماء أيٍّ من الأعمدة. عندما يتجاوز دليل الأعمدة المحدد عدد الأعمدة الفعلية في مجموعة النتائج، تُرجع قاعدة البيانات خطأً، مثل: 

The ORDER BY position number 3 is out of range of the number of items in the select list. 

في الواقع ، قد يعرض التطبيق خطأ قاعدة البيانات في استجابة (response) HTTP الخاصة به، أو قد يُرجع خطأً عاماً، أو ببساطة،  قد لا يُرجع أية نتائج. وشريطة أن تتمكن من اكتشاف بعض الاختلافات في استجابة التطبيق، يمكنك استنتاج عدد الأعمدة التي يتم إرجاعها من الاستعلام. 

تتضمن الطريقة الثانية إرسال سلسلة من حمولات UNION SELECT التي تحدد عدداً مختلفاً من القيم الخالية (null values): 

' UNION SELECT NULL--  ' UNION SELECT NULL,NULL--  ' UNION SELECT NULL,NULL,NULL— 

… إلخ 

إذا كان عدد القيم الخالية لا يتطابق مع عدد الأعمدة، فتُرجع قاعدة البيانات خطأً، مثل: 

All queries combined using a UNION, INTERSECT or EXCEPT operator must have an equal number of expressions in their target lists. 

مرة أخرى، قد يعرض التطبيق رسالة الخطأ هذه بالفعل، أو قد يعرض خطأ عاماً أو قد لا يعرض نتائج. عندما يتطابق عدد القيم الخالية (null) مع عدد الأعمدة، تُرجع قاعدة البيانات صفاً (أو سطراً row) إضافياً في مجموعة النتائج، يحتوي على قيم فارغة (null) في كل عمود. يعتمد التأثير على استجابة HTTP الناتجة على كود (أو التعليمات البرمجية لـ) التطبيق. وإذا كنت محظوظاً، فستشاهد بعض المحتوى الإضافي داخل الاستجابة، على سبيل المثال، صفٌّ إضافي في جدول HTML. خلاف ذلك، قد تؤدي القيم الخالية إلى خطأ مختلف، مثل NullPointerException. وفي أسوأ الحالات، قد يتعذَّر تمييز الاستجابة عن تلك الناتجة عن عدد غير صحيح من القيم الخالية (nulls)، مما يجعل هذه الطريقة لتحديد عدد الأعمدة غير فعالة. 

ملاحظة: 

  • سبب استخدام NULL كقيم يتم إرجاعها من استعلام SELECT المحقون هو أن أنواع البيانات في كل عمود يجب أن تكون متوافقة بين الاستعلامات الأصلية والاستعلامات التي تم حقنها. ونظراً لأن NULL قابلة للتحويل إلى كل أنواع البيانات الشائعة الاستخدام، فإن استخدام NULL يزيد من فرصة نجاح الحمولة عندما يكون عدد الأعمدة صحيحاً. 
  • في  Oracle، يجب أن يستخدم كل استعلام SELECT الكلمة الأساسية FROM ويقوم بتحديد جدول (table) صحيح (valid). يوجد جدول مضمن في Oracle يسمى DUAL  والذي يمكن استخدامه لهذا الغرض. لذا يجب أن تبدو الاستعلامات التي سيتم حقنها في Oracle كما يلي: 

UNION SELECT NULL FROM DUAL-- 

  • تستخدم الحمولات المذكورة تعليق تسلسل الشرطة المزدوج double-dash comment (–) لتعليق ما تبقى من الاستعلام الأصلي بعد نقطة الحقن. في MySQL ، يجب أن يكون تسلسل الشرطة المزدوج متبوعاً بمحرف المسافة (space). بدلاً من ذلك، يمكن استخدام محرف الـ hash (معناها المزج وأحياناً تدعى المربع وتختلف تسميتها بحسب الأشخاص والمهم هو معرفة ما المقصود بها hash character) [#] للإشارة إلى تعليق. 

لمزيد من التفاصيل حول طريقة بناء الجملة (أو أسلوب الكتابة syntax) الخاصة بقواعد البيانات، راجع ورقة الغش (cheat sheet) لحقن SQL.

العثور على أعمدة بنوع بيانات مفيد في هجوم حقن SQL بواسطة UNION: 

سبب تنفيذ هجوم حقن SQL بواسطة UNION هو أن تكون قادراً على استرداد النتائج من استعلام محقون. وبشكل عام، ستكون البيانات المهمة التي تريد استرجاعها على شكل سلسلة نصية (string)، لذلك يلزمك العثور على عمود واحد أو أكثر في نتائج الاستعلام الأصلية بحيث يكون نوع البيانات الخاص به مطابقاً لبيانات من نوع سلسلة نصية string أو متوافقاً معها. 

بعد تحديد عدد الأعمدة المطلوبة بالفعل، يمكنك فحص كل عمود لاختبار ما إذا كان يمكنه الاحتفاظ ببيانات من نوع سلسلة نصية string وذلك من خلال إرسال سلسلة من حمولات UNION SELECT التي تضع قيمة من نوع سلسلة نصية string في كل عمود بالتتابع (أو بالدور in turn). على سبيل المثال، إذا أرجع الاستعلام أربعة أعمدة، فأنت ستقدم (أو سترسل): 

' UNION SELECT 'a',NULL,NULL,NULL--  ' UNION SELECT NULL,'a',NULL,NULL--  ' UNION SELECT NULL,NULL,'a',NULL--  ' UNION SELECT NULL,NULL,NULL,'a'-- 

إذا كان نوع بيانات العمود غير متوافق مع بيانات من نوع سلسلة نصية string، فسيؤدي الاستعلام الذي تم حقنه إلى حدوث خطأ في قاعدة البيانات، كالتالي: 

Conversion failed when converting the varchar value 'a' to data type int. 

إذا لم يحدث خطأ، وكانت استجابة التطبيق تحتوي على بعض المحتوى الإضافي بما في ذلك قيمة السلسلة النصية string المحقونة، فإن العمود الموافق مناسبٌ لاسترداد بيانات من نوع السلسلة النصية string. 

استخدام هجوم حقن SQL بواسطة UNION لاسترداد البيانات الهامة: 

عندما تحدد عدد الأعمدة التي يتم إرجاعها بواسطة الاستعلام الأصلي وتجد الأعمدة التي يمكنها الاحتفاظ ببيانات نصية (من نوع string)، فأنت في وضع يمكِّنك من استرداد البيانات المهمة. 

لنفترض أن: 

  • الاستعلام الأصلي يُرجِع عمودين، وكلاهما يمكنه الاحتفاظ ببيانات من نوع السلسلة النصية string. 
  • نقطة الحقن عبارة عن سلسلة نصية string مضمنة في جملة  WHERE. 
  • تحتوي قاعدة البيانات على جدول يسمى users فية عمودان هما username و password للأعمدة. 

في هذه الحالة، يمكنك استرداد محتويات جدول المستخدمين users عن طريق إرسال الإدخال: 

' UNION SELECT username, password FROM users-- 

بطبيعة الحال، فإن المعلومات الأساسية اللازمة لتنفيذ هذا الهجوم هي أن هناك جدولاً يدعى users مع عمودين يسميان username و password. بدون هذه المعلومات، ستُترَك تحاول تخمين أسماء الجداول والأعمدة. في الواقع، توفر جميع قواعد البيانات الحديثة طرقاً لفحص بنية قاعدة البيانات، لتحديد الجداول والأعمدة التي تحتوي عليها. 

استرداد قيم متعددة في عمود واحد: 

في المثال السابق، افترض بدلاً من ذلك أن الاستعلام يُرجِع عموداً واحداً فقط. 

يمكنك بسهولة استرداد قيم متعددة معاً داخل هذا العمود المفرد عن طريق ربط (concatenating) القيم معاً، وبشكل مثالي يمكنك تضمين فاصل (separator) مناسب ما سيسمح لك بتمييز القيم المُضَمَّنَة. على سبيل المثال، في Oracle يمكنك إرسال (أو تقديم) الإدخال: 

' UNION SELECT username || '~' || password FROM users-- 

هذا يستخدم تسلسل الأنبوب المزدوج (double-pipe sequence) || وهو معامل (operator) ربط السلاسل (string concatenation) في Oracle. يربط الاستعلام المحقون قِيَم حقول (fields) username و password معاً مفصولة بمحرف (~). 

ستتيح لك نتائج الاستعلام قراءة جميع أسماء المستخدمين و كلمات المرور، على سبيل المثال: 

...  administrator~s3cure  wiener~peter  carlos~montoya  ... 

لاحظ أن قواعد البيانات المختلفة تستخدم أساليب بناء جملة مختلفة لتنفيذ ربط السلاسل (string contactenation). لمزيد من التفاصيل، راجع ورقة الغش (cheat sheet) في حقن SQL

المصدر: https://portswigger.net/web-security/sql-injection/union-attacks