|=| SQLI |=|
|=| تعريفها |=|
-
قبل ما نعرف هي إيه ثغرة الـ SQL injection خلونا نعرف كام مصطلح الأول:-
-
Database: هي مكان لتخزين،إضافة،وتعديل البيانات زي إننا نخزن باسوردات المستخدمين وكده، وفي أنواع منها زي Centralized Database, Distributed Database, Relational Database, NoSQL Database وغيرهم.
-
DBMS: هي إختصار لكلمة Database Mangement System وهي المسئولة عن التحكم في الـ Database وفي منها MySQL, Oracle, SQLite, PostgreSQL وفي أنواع تاني.
-
SQL: هي إختصار لـ Strucured Query Language ودي لغة تُستخدم للاستعلام عن قواعد البيانات، يعني لو الـ Web Application محتاج يضيف، أو يسترجع بيانات من الـ Dataabse هيكون الوسيط بينهم هي الـ SQL.
-
-
خلونا ناخد مثال لـ SQL query:-
-
Select * from posts where id=5
-
هنا بنستخدم أمر select عشان نسترجع حاجة من الـ Database والـ * يعني كل البيانات وآخر حاجة الـ posts ده الجدول الي في البيانات وبنحدد الـ ID بتاع المستخدم عشان يرجع المقالات أو الـ posts الخاصة بيه.
-
الـ Database بتحتوى على جدول - table - أو أكتر وممكن يكون في علاقة بينهم أو لا.
-
مثال للـ Database في الحياة الواقعية بعيداً عن البرمجة، هو دولاب شئون العاملين :D ده يعتبر داتا بيس وكل ملف جواه يعتبر جدول وكل جدول في بيانات معينة خاصة بمجموعة ناس معينة.
-
-
هنا نقدر نعرف هي إيه ثغرة الـ SQL injection:-
-
هي ثغرة من ثغرات الـ Injections وبكده في هي بتعتمد إن اليوزر هيمرر input معين وبالتالي الـ Attacker هيتلاعب بالـ input ده ويحط malicious code/query عشان يقدر يرجع بيانات تاني مش المفروض ترجع.
-
هل في مشكلة لو الـ Attacker رجع كل البيانات الي موجودة في جدول الـ products أو News اكيد طبعا لا، الفكرة إنه يعرف إن في جدول تاني فيه معلومات العملاء ويرجع كل البيانات الي فيه.
-
وده ممكن يحصل من خلال:
-
Select * from posts where id=’’ union select username,password from users--
-
هنا الـ Attacker إستخدم أمر union الي بيخليك تنفذ أمرين أو أكتر من select وبالتالي خلي الـ Database ترجع المقالات وكمان الـ username,password من جدول تاني خالص إسمه users وبكده هو قدر يوصل لمعلومات المفروض مينفعش يوصلها.
-
-
إيه الفرق بين الـ Static query, Dynamic query؟
-
Static query: هو كويري بنستخدمه عشان نرجع حاجة ثابتة ومش بيعتمد إنه ياخد input من اليوزر.
-
Dynamic: هو الي بياخد input من اليوزر وبيرجع النتايج بناءاً على الـ input ده.
-
طبعا كل الثغرات بتحصل بسبب الـ Dynamic query.
-
-
ملحوظة: لو في بيانات متكررة ومش عايز تكرار ف بنستخدم DISTINCT، ولو عايز كل البيانات حتى المتكرر بنستخدم ALL.
-
لو عايز تعمل Comment عشان هنحتاجها كتير:
-
ممكن تستخدم #
-
أو تستخدم - - وبعدين مسافة.
-
كل نوع من أنواع الـ DBMSs ليها كومنت معين وفي الي بيشترك فيه أكتر من DBMS.
-
|=| خطورتها |=|
-
لو تطبيق فيه فعلا ثغرة SQL injection ممكن الـ Attacker يوصل لإيه؟
-
هيوصل لمعلومات حساسة زي الـ Passwords, credit cards details, personal user information.
-
ممكن توصل لـ Remote code execution.
-
ممكن يقرأ أو يكتب ملفات على السيستم.
-
ممكن يعمل install shells.
-
زي ما بيقدر يضيف داتا هيقدر يحذف داتا وممكن تكون مهمة زي جدول Users مثلا.
-
-
إيه العواقب الي بتترتب على استغلال الـ SQL injection؟
-
فقدان السرية (Confidentiality): بما إن في الغالب الداتا بيس بتحتوى على بيانات حساسة فـ الوصول للبيانات دي يعتبر خطير وبيمثل مشكلة بالنسبة للسرية.
-
المصادقة (Authentication): بما إن الـ Attacker قدر يوصل للداتا بيس، ف ممكن يوصل ليوزر نيم وباسورد الأدمن وبالتالي يـ authenticate as admin وبالتالي يقدر يتحكم في كل حاجة.
-
السلامة (Integrity): المقصود بيها إن مفيش تغيير يحصل، ف فقدان السلامة معناه إن الـ Attacker يقدر يضيف، يحذف، أو يعدل البيانات الي موجودة.
-
-
|=| مثال للكود الضعيف |=|
==> https://www.example.com/articles?article=3
-
خلونا نفهم الكود
-
الـ articleid$ هو variable بيروح يجيب قيمة الـ article ويخزنها.
-
بعدين الـ variable ده بيدخل في الـ SQL query وبيروح للداتا بيس عشان يجيب المقالة الي بالرقم الي أتخزن في المتغير articleid$
-
-
طيب هو هنا بيروح بالـ query دي للداتا بيس ويعدي على صف صف في الداتا بيس لحد ما يلاقي الصف الي الـ articleid بتاعه يساوي 3 ويروح يرجعه للويب ابليكيشن، طيب لو زودنا or 1=1' هيحصل إيه؟
-
الـ Query هيكون كالآتي
-
SELECT * FROM articles WHERE articleid = 3 or 1=1
-
كده الـ Query دايما True وبالتالي هيرجعلي كل البيانات الي موجودة في articles، وطبعا دي مش حاجة خطيرة هنا لإن الـ articles حاجة مش مهمة، بس الفكرة إنه يستخدمه على جدول تاني مهم زي Users, Accounts وغيرهم.
|=| أنواع الـ SQL Injection |=|
-
إيه أنواع الـ SQL injection؟
-
In-Band: والنوع ده من الثغرات بيكون الـ website بيرجع الـ response قدامك وتقدر تحدد إذا كان في ثغرة أو لا، وهنا بنستخدم أمر union في معظم الحالات، وممكن نحسب الـ Erorr-based ضمن الـ In-Band لإننا بنقدر نشوف الـ Erorr.
-
بيُسمى In-Band عشان النتايج بترجع على نفس الـ Connection المفتوح ما بين المتصفح والسيرفر الي بنبعت من خلاله الـ SQL code.
-
في النوع ده من الثغرات لما بنستخدم union في شروط لازم تتحق عشان الاستغلال يتم صح:
-
إن عدد الأعمدة في الـ query ألاول يكون نفس عدد الأعمدة في الـ Query التاني.
-
إن نوع الداتا يكون متطابق برضو يعني لو العمود الأول في الـ query الأول كان نوعه string يبقى لازم العمود الأول في الـ query التاني يكون string وهكذا.
-
-
-
-
وOut-Of-Band: النوع ده من الثغرات السيرفر مش بيظهرلك النتيجة قدامك ومش بتقدر تشوف إذا كان في إيرور أو لا أو حصلت حاجة ولا لا, ف بتستخدم Techniques بتخلينا نبعت الـ results على حاجة زي الأميل مثلا أو لو معانا دومين خارجي.
-
بيُسمى Out-Of-Band عشان بتحتاج سيرفر أو دومين خارجي عشان تبعت النتايج عليه وبالتالي تقدر تشوفها، ع عكس الـ In-Band الي كانت فيه النتايج بترجع على نفس الـ Connection.
-
-
والـ Blind: دي مفيش أي results تقدر تشوفها ولا تقدر تبعتها برضو على سيرفر خارجي، هنا الأعتماد كله على إنك بتسأل السيرفر مجموعة من الـ True/False conditions وبناءاً علي الرد بتبدأ تعرف أسم الداتا بيس وأسماء الجداول والأعمدة وغيرها.
-
هنا بنعتمد على الـ Boolean based condition او الـ Time-based condition.
-
|=| ازاي تتيست SQL Injection |=|
Detection Techniques
-
أول خطوة وأهم خطوة هو إنك تعرف فين المناطق الي التطبيق بيتعامل فيها مع الداتا بيس وهنا شوية أمثلة:
-
المصادقة: غالبا في كل المواقع الـ Authentication زي الـ login, sign-up بيتعامل مع الداتا بيس عشان يتأكد من اليوزر أو يضيف واحد جديد فالـ sign-up.
-
البحث: في الغالب خانة البحث بتكون متصلة بالداتا بيس ولما بتبحث عن حاجة معينة بيروح يدور في الداتا بيس ولو لقيها بيرجعلك النتايج وده مشهور طبعا.
-
الـ E-commerce: في الغالب المواقع دي بتكون متصلة بالداتا بيس عشان تجيب الـ products ومعلومات عنها وباقي كام واتباع منهم كام وكل ده، في دي برضو نقطة مهمة تبص عليها.
-
-
بعد ما جمعت كل الـ points الي غالبا متصلة بالداتا بيس هتبدأ تتيست حاجة حاجة مش كله مع بعض، بتمسك endpoint واحدة وتبدأ تعمل تيست وممكن تجرب الآتي:
-
إنك تضيف ' في نهاية الـ Endpoint وتشوف لو ظهرلك ايرور
-
إنك تكتب نص لما يكون مطلوب منك رقم زي id=ahmed
-
-
ركز مع كل الـ responses الي بتيجي وتشوف لو في حاجة بتتغير أو إيرورز بتظهر وبرضو بص على الـ HTML/javascript source code أحيانا الايرور بيكون هناك.
Classic SQL injection
-
الي بتكون موجودة غالبا في الـ Authentication زي صفحات الـ login وكده.
-
أحيانا بيكون الكود ما بين () والباسورد بيتعمله Hashing ع سبيل المثال MD5 ف هنا في مشكلتين:
-
الأولى هي الباسورد وبكده أي كود هنكتبه مش هيتطابق مع الباسورد لإن الهاش هيختلف وبالتالي محتاجين نعرف الباسورد نفسه، ف أول حاجة تيجي ف دماغك إنك تتخلص من جزء الباسورد فالـ query وهنا نيجي للمشكلة التانية
-
مشكلة الـ () وعشان نعمل تخطي ليها غالبا بيكون الـ exploit كالآتي
-
1' or ‘1’=’1 ))/*
-
ف احنا هنا قفلنا الـ () وبعدها عملنا كومنت لباقي الـ query.
-
-
-
في بعض الأوقات لما بنطبق السيناريو الي موجود فوق ده، بيحصل إن الداتا بيس ترجع أكتر من قيمة رغم إننا محتاجين قيمة/ريكورد واحد عشان نعمل login وبالتالي ممكن نستخدم LIMIT 1 عشان يرجع ريكورد واحد والي غالبا بيكون الـ Admin وهو أول ريكورد في الداتا بيس.
Select statement
-
بتكون في الغالب موجودة في صفحات عرض الـ products وبتعرض معلومات عن كل product.
-
أفضل طريقة تعمل بيها تيست للنوع ده هو AND, OR operations أو Boolen conditions ف تشوف لما تكتب True condition في حاجة هتتغير ولا لا وبعدين false condition ولو لقيت الصفحة فاضية أو ظهرت رسالة إن المحتوى مش موجود ف ده دليل إنك بتقدر تتحكم ف الـ query وهنا في ثغرة.
Stacked queries
-
على حسب الـ API المستخدم في الويب ابليكيشن والـ DBMS ف ممكن إنك تنفذ أكتر من أمر ف نفس الـ Query بس تفصل ما بينهم بالـ ;
-
الـ UNION attacks مقتصرة بس على الـ select statements وإنها بتجمع ما بين الـ Results، إنما الـ stacked query هتخليك تنفذ أوامر تاني زي insert, delete.
-
زي ما قولنا هي مش دايما بتشتغل وبتعتمد على الـ API + DB
-
MySQL/PHP - Not supported (supported by MySQL for other API).
-
SQL Server/Any API - Supported.
-
Oracle/Any API - Not supported.
-
-
الـ stacked query بتخليك تنفذ أمرين أو أكتر زي ما عرفنا، بس لو جيت تنفذ الأمر التاني select مش هتظهر النتيجة، يعني الأمرين هيتنفذوا بس الأول هو الي هيظهر، لإن في حالة الـ stacked query الـ software code أتصمم إنه يتعامل مع الـ result الي جاية من الـ query الأول، ف يستحسن لما نيجي نستخرج داتا نستخدم UNION.
Fingerprinting the Database
-
أول حاجة عن طريق الـ Errors:
-
هنا بعض الايرورز تقدر تشوفها Fingerprinting the Database
-
Exploitation Techniques
UNION Exploitation Technique
-
بتخلينا بندمج أتنين Select query ونشوف الـ results.
-
أول حاجة بتحاول تعملها تشوف عدد الأعمدة ف الـ query الأول وده عن طريق ORDER BY 1 وتزود لحد ما يحصل ايرور ف تعرف إن عدد الأعمدة في الـ query التاني بقى زيادة عن عددهم في الـ query الأول.
-
بعدين بتحاول تعرف نوع الداتا الي موجودة في كل عمود وممكن تستخدم NULL وتبدأ تجرب عمود عمود
-
1 union select 1,NULL,NULL,NULL– -
-
-
لو محصلش ايرور يبقى العمود الأول integer ولو حصل ايرور جرب تخليه string وهكذا.
-
وآخيرا بعد ما عرفت عدد الأعمدة ونوع الداتا الي جوا، بتبدأ تستخرج الداتا الي عايزها.
-
تقدر تقرأ عن باقي التقنيات هنا Exploitation Techniques عشان لو كملت المقال هيطول جامد.
-
طبعا كل الـ Exploitation Techniques الي هتقراها في اللينك الي فوق تقدر تعملها بطريقة automation وده عن طريق أداة SQLmap وتقدر تعرف عنها أكتر وازاي تستخدمها من اللينك ده SQLmap
|=| Code review for SQL Injection |=|
-
لما بتيجي تعمل code review for SQL injection بتروح طبعا للـ SQL queries وتبدأ تبص على الكود وتشوف هل الـ input الي بيجي بيدخل على الـ query على طول ولا بيحصله فلترة الأول؟ طيب هل المبرمج مستخدم Prepared statement أو Input validation أو اي نوع حماية ولا لا، أحيانا بيكون مستخدم نوع من الحماية ممكن تعمله Bypass، ف دايما ركز في الـ inputs الي داخلة الـ query هل هي متفلترة صح ولا لا.
-
من الحاجات الي تبص عليها برضو:
-
الـ database privilege
-
زي Grant-priv لإن دي بتسمح لليوزر إنه يدي صلاحيات ليوزر تاني، والـ Grant-priv المفروض تكون مقتصرة بس على الـ DB Administrators, DB owner، ف لو لقيت يوزر معين معاه الصلاحيات دي وهو مش المفروض تكون معاه، لازم تعدلها.
-
Select * from user where Grant-priv = ‘Y’;
-
Select * from db where Grant-priv = ‘Y’;
-
Select * from host where Grant-priv = ‘Y’;
-
Select * from tables_priv where Grant-priv = ‘Y’;
-
-
الـ alter-priv الي بتحدد مين يقدر يغير فالـ DB structure ودي برضو خطيرة
-
Select * from user where alter-priv = ‘Y’;
-
Select * from db where alter-priv = ‘Y’;
-
Select * from host where alter-priv = ‘Y’;
-
Select * from tables_priv where alter-priv = ‘Y’;
-
-
-
الـ MYSQL configuration file
-
بص على الحاجات دي في الملف:
-
Skip-grant-tables: دي لو موجودة ف معناها إن الـ DB تتجاهل الـ system grant privilege وبالتالي كل اليوزر هيكون ليهم full access على الـ tables.
-
Safe-show-database: دي لو enable في كده هيظهر الـ databases لليوزر الي فعلا ليه access عليها.
-
Safe-user-create: لو الاوبشن ده enable ف كده مفيش يوزر هيقدر ينشئ يوزر جديد باستخدام أمر Grant إلا ف حالة إن ليه صلاحيات INSERT على جدول mysql.user.table
-
-
-
الـ User privileges وهنا بنشوف مين ممكن يعمل malicious actions
-
-
وفي بعض الحاجات الاضافية الي ممكن تعملها:
-
-
اتجنب إنك تستخدم Select * في الـ queries.
-
اتجنب استخدام الباسوردات كـ palin text في الـ tables.
-
اتجنب استخدام FQND أو الـ Hostnames وأنت بتدى صلاحيات لحد.
-
ضيف اليوزر من خلال phpmyadmin وبلاش الـ queries.
-
بص على الـ CHANGE LOG file وشوف لو في تحديثات وكده.
-
احذف الـ test database واي وصول ليها.
-
مصادر للنقطة دي:
|=| ازاي امنع SQL Injection |=|
-
أول حاجة هي الـ Prepared Statement: دي بإختصار وظيفتها إنها تفصل الـ Data عن الـ query، يعني لما يوزر يكتب malicious query زي OR 1=1 هتعتبره كـ نص عادي، وبالتالي الداتا بيس مش هتعتمد على الـ user input عشان تكون query، لا هو في query جاهز ومحتاج الداتا فقط لا غير، ودي أفضل دفاع ضد الـ SQL injection.
-
ممكن تعمل الـ Prepared Statement عن طريق الـ PDO أو الـ SQLi (SQL improved vesion)
-
تاني حاجة الـ Input Validation: بإختصار هو إن الديفلوبر يشوف الـ input الي هو هياخده من اليوزر المفروض يكون ازاي، يعني هل هو محتاج رقم بس ولا نص ورقم ولا علامات وأرقامـ وبعدين بالـ Regex يحط القيم الي محتاجها فقط زي مثلا ^[a-zA-Z]*$
-
تالت حاجة الـ Type casting: وهو إنك تحدد من الأول الـ User input يكون نوعه إيه زي مثلا
$id = int ($_GET[‘id’])
-
رابع حاجة الـ Escaping User Input: وهو إنك بتعمل escape لبعض العلامات والحروف الي أنت مش محتاجها كـ user input زي مثلا ['_-" وغيرهم، وهنا هو بيضيف \ قبل كل علامة وبالتالي بتكون كـ نص عادي.
-
خامس حاجة stored procedures: دي بتحط limitation لأنواع الـ queries/statements الي بيتم تمرريها للباراميترز، ولكن زي ما بتمنع أنواع من الـ queries/statements في أنواع تاني بتعدي، ف النوع ده مش قوي كفاية إنه يمنع الـ SQL injection ولكن ممكن تستخدمه مع حاجة تاني كزيادة أمان.
-
أحيانا النوع ده بيزود مساحة الهجوم (زي ما بيقولوا بيزود الطينة بلة :D )، كمثال على MS SQL server بيكون في 3 أدوار وهما db_datawriter, db_datareader, db_owner، طبعا اليوزر بتاع الويب ابليكيشن الي بيتعامل مع الداتا بيس بيكون واخد صلاحيات/دور واحد من أتنين يا db_datawriter أو db_datareader على حسب هيحتاج إيه، طيب المشكلة فين؟ المشكلة إن الـ Stored procedures بتحتاج إن يتعملها تنفيذ ف أحيانا اليوزر بتاع الويب ابليكيشن بيدولوه صلاحيات db_owner وبالتالي لما الـ Attacker ينفذ SQL injection هيكون ليه نفس الصلاحيات.
-
-
سادس حاجة وهي إضافية الـ least privilege: هو إنك تدي ليوزر الويب ابليكيشن الي بيتعامل مع الداتا بيس أقل الصلاحيات أو بمعنى أصح الصلاحيات الي محتاجها بس، الصلاحيات الي تخليه يقدر يتعامل مع الداتا بيس براحته وف نفس الوقت ميقدرش يعمل حاجة تضر بيها.
-
طبعأ أفضل حل هو الـ Multi-Defense Layers وهو إنك تطبق أكتر من حاجة من الي فوق عشان لو الـ Attacker قدر يتخطى حاجة يكون موجود layer تاني من الدفاع.
-
مصادر للنقطة دي:
التعليقات (0)
لايوجد لديك حساب في عالم البرمجة؟
تحب تنضم لعالم البرمجة؟ وتنشئ عالمك الخاص، تنشر المقالات، الدورات، تشارك المبرمجين وتساعد الآخرين، اشترك الآن بخطوات يسيرة !