اختبار الاختراق بلغة البايثون – الجزء الأول
كلمة Hacker : تعني “مبرمج محترف” وهو الشخص القادر على فهم النظام والبرامج بشكل عميق وتحديد الثغرات وكتابة الاستغلال المناسب وليس الشخص الذي يرتكب جرائم إلكترونية مثل إيقاف أنظمة الكمبيوتر أو اختراق خصوصيات الناس وإلحاق الأذى بهم.
الأفلام والعروض التلفزيونية تجعل عملية الاختراق تبدو مثيرة من خلال عمليات إدخال التعليمات وظهور سيل من الأصفار والواحدات على الشاشة.
هم يجعلون عملية الاختراق تبدو كشيء يجب أن تكون عبقري لتتعلمه.
هم يجعلون الاختراق يبدو كالسحر، هو ليس سحر، هو يعتمد على أجهزة الكمبيوتر وكل عمل يقوم به الكمبيوتر هو عمل مبني على قاعدة منطقية يمكن تعلمها وفهمها.
ليس من الصعب التعلم.
هذه السلسة من المقالات ستجعل منك مبرمج محترف قادر على كتابة برامج اختبار الاختراق و الاستغلال بلغة البرمجة بايثون.
في هذه السلسلة أنا افترض أنك على معرفة سابقة بأساسيات البرمجة بلغة البايثون
لكي تتجاوز مرحلة استخدام أدوات اختبار الاختراق وتستطيع كتابة أدوات اختبار الاختراق و الاستغلال الخاصة بك يجب أن تكون مبرمج محترف.
لغة البرمجة بايثون هي لغة الهكرز المفضلة من أجل كتابة سكريبتات الاستغلال وبرامج وأدوات الاختراق.
البداية سوف تكون مع أساسيات برمجة الشبكات بلغة البايثون
سوف نستخدم الإصدار python 2.7.9 لأن المكتبات اللازمة لهذه البرامج مازالت غير متوفرة بشكل كامل في الإصدار python 3 .
إذا كنت تستخدم نظام كالي لينكس فلن تكون بحاجة للقيام بأي شيء لأن python 2.7 موجود بشكل تلقائي في كالي لينكس أما إذا كنت تستخدم نظام التشغيل ويندوز فيجب عليك تحميل python2.7.9 من موقع بايثون الرسمي. لتنزيله إضغط هنا
أول شيء يجب أن تتعرف عليه في برمجة الشبكات بلغة البايثون هو Socket والطرق methods الخاصة بها وهذا ما سنتعرف عليه في هذا المقال.
وفي المقالات القادمة سوف نقوم بكتابة برامج بلغة البايثون تقوم بعملية جمع المعلومات وفحص المنافذ المفتوحة والبحث عن الثغرات واستغلالها و برامج لاختبار اختراق الشبكات اللاسلكية واختبار اختراق تطبيقات الويب.
ما هو Socket:
أنا أتكلم عن INET (IPv4) socket وعن STREAM (TCP) socket
إذا كنت لا تعرف هذه البرتوكولات فيجب عليك أن تمضي بعض الوقت التعرف عليها أولاً.
Network sockets تحوي على عناوين IP وأرقام المنافذ.
Socket هو طريقة للاتصال بين أجهزة الكمبيوتر.
من أجل خلق socket بلغة البايثون نقوم باستخدام التابع ()socket.socket الموجود في الموديول socket module باستخدام التعليمة التالية:
(s = socket.socket (socket_family, socket_type, protocol=0
حيث:
- socket_family: AF_INET
AF_INET: هو للإشارة لاستخدام العنونة IPv4
- Socket_type : socket.SOCK_DGRAM OR socket.SOCK_STREAM
SOCK_DGRAM: للإشارة أن البرتوكول المستخدم هو UDP
SOCK_STREAM: للإشارة أن البرتوكول المستخدم هو TCP
“client” socket تستخدم للإشارة إلى المستخدم (متصفح المستخدم) أما “server” socket للإشارة إلى السيرفر (سيرفر الويب).
Server socket methods:
- (bind(address: هذه الطريقة تستخدم من أجل الاتصال بعنوان (IP , port) و يجب أن يتم فتح socket قبل الاتصال.
- (listen(q: هذه الطريقة تبدأ الانصات لمدة q ثانية.
- ()accept : هذه الطريقة تستخدم من أجل قبول الاتصال من المستخدم وقبل استخدام هذه الطريقة يجب استدعاء كل من
(socket.bind(address) and socket.listen(q وهذه الطريقة تعيد قيمتين هما client_socket and address
حيث:
client_socket هي socket object جديد يستخدم من أجل إرسال واستقبال البيانات عبر الاتصال.
address هو عنوان المستخدم.
method Client socket:
يوجد طريقة واحدة خاصة ب client socket وهي:
- (connect(address: هذه الطريقة تمكن المستخدم من الاتصال بالسيرفر والعنوان المستخدم في هذه الطريقة هو عنوان السيرفر.
طرق socket العامة:
- (recv(bufsize: هذه الطريقة تستقبل رسالة TCP من socket والبارامتر bufsize الذي يتم تمريره لها هو لتعريف الحد الأقصى للبيانات التي يمكن استقبالها في وقت واحد.
- (recvfrom(bufsize: هذه الطريقة تستقبل البيانات من socket وهي تعيد زوج من القيم: أول قيمة هي البيانات المستقبلة والقيمة الثانية هي عنوان socket الخاص بالمرسل
- (recvfrom_into(buffer: هذه الطريقة تأخذ البيانات من socket وتعيد زوج من القيم (nbytes, address)
حيث : nbyets هو عدد البايتات المستقبلة.
address هو عنوان socket المرسل.
- (send(bytes: هذه الطريقة تستخدم من أجل إرسال البيانات وقبل إرسال البيانات يجب ان تتأكد من أن socket متصل مع جهاز بعيد وهذه الطريقة تعيد عدد بايتات البيانات المرسلة.
- (sendto(data, address: هذه الطريقة تستخدم من أجل إرسال البيانات إلى socket وبشكل عام سوف نستخدم هذه الطريقة مع UDP لأن UDP لا يتأكد من تسليم البيانات connectionless protocol لذلك فإن socket لن يكون مضراً لأن يتصل مع الجهاز البعيد.
address هو عنوان الجهاز البعيد وهذه الطريقة تعيد عدد بايتات البيانات المرسلة.
- (sendall(data: هذه الطريقة تقوم بإرسال كل البيانات وقبل إرسال البيانات يجب ان تتأكد ان socket متصل مع الجهاز البعيد وهذه الطريقة تستمر بإرسال البيانات إلى أن يحدث خطأ وعندها يتم استدعاء ()socket.close من أجل اغلاق socket.
القسم العلمي:
سوف نقوم بكتابة برنامج server-side program يقوم بالاتصال بالمستخدم ويرسل رسالة له
server1.py program
في البداية قمنا باستدعاء socket module وقمنا بتعريف عنوان الجهاز وهو عنوان السيرفر ورقم المنفذ المستخدم بعملية الاتصال.
socket.AF_INET هي للإشارة أن البرتوكول المستخدم هو IPv4.
socket.SOCK_STREAM هي للإشارة انه اتصال عبر برتوكول .TCP
التعليمة ((s.bind((host,port من أجل ربط socket بالجهاز.
التعليمة (s.listen(2 من أجل انتظار المستخدم ليقوم بالاتصال.
التعليمة ()conn , addr = s.accept تعيد قيمتان ويتم حفظهما في المتغيران conn and addr حيث أن المتغير conn يحوي على client socket.
التابع ()conn.send يرسل رسالة إلى المستخدم.
وأخيراً ()conn.close تقوم بإغلاق socket.
وعند تنفيذ هذا البرنامج يصبح السيرفر في وضع الإنصات وينتظر المستخدم لكي يتصل به.
لنرى الكود من طرف المستخدم
client1.py program
في الكود السابق استخدمنا الطريقة ((s.connect((host,port التي تمكن المستخدم من الاتصال بالسيرفر والطريقة (s.recv(1024 التي تستقبل الرسالة المرسلة من السيرفر.
نتيجة تنفيذ كلا البرنامجين تظهر في الشكل التالي:
النتيجة السابقة تظهر أن السيرفر وافق على الاتصال مع 192.168.0.11
عندما يريد السيرفر ارسال رسالة إلى المستخدم يتم ذلك باستخدام conn socket التي تحوي على عنوان IP ورقم المنفذ.
الشكل التالي يظهر كيف أن المستخدم وافق على الاتصال مع السيرفر وكيف أن السيرفر في وضع الإنصات وأن المستخدم اتصل مع السيرفر.
يمكن توسيع العملية من خلال استخدام حلقة while في طرف السيرفر كما في البرنامج التالي:
server2.py program
البرنامج هو نفس البرنامج السابق ولكن قمنا فقط بإضافة حلقة while
عند تشغيل server2.py من طرف السيرفر وتشغيل cliene1.py من قبل طرف المستخدم تكون النتيجة كالتالي:
استخدام طرق socket لجمع المعلومات عن الهدف:
الآن وبعد أن تعرفنا على socket وعلى كيفية عملها بين السيرفر والمستخدم يمكننا كتابة برامج بسيطة بلغة البايثون مفيدة في جمع المعلومات خلال عملية اختبار الاختراق.
- الطريقة ()gethostname تقوم بعرض اسم الجهاز
جرب المثال التالي:
- الطريقة (gethostbyname(hostname تقوم بتحويل اسم الجهاز إلى عنوان IP الخاص به.
جرب المثال التالي:
يمكن الحصول على عنوان IP للجهاز من خلال التعليمة التالية:
بدل أن نقوم بكتابة اسم الجهاز قمنا باستدعاء الطريقة ()socket.gethostname التي تقوم بإعادة اسم الجهاز.
يمكن استخدام هذه الطريقة للحصول على عنوان IP الخاص بأي موقع كما في المثال التالي:
كما تلاحظ يمكننا استخدام لغة البايثون لكتابة برنامج يقوم بعملية DNS lookup
- الطريقة (gethostbyname_ex(name تقوم بتحويل اسم الجهاز إلى عنوان IPv4 ولكن ميزة هذه الطريقة هو أنها تقوم بإعطاء كل عناوين IP الخاصة باسم دومين معين.
جرب المثال التالي:
والمثال التالي:
كما تلاحظ فإن هذه الطريقة قامت بإعادة عدة عناوين IP خاصة باسم دومين واحد.
- الطريقة ([getservbyname(servicename [ , protocol_name تقوم بتحويل اسم برتوكول إلى رقم المنفذ المقابل له.
جرب المثال التالي:
الطريقة ([socket.getservbyport(port [ , protocol_name تقوم بتحويل رقم المنفذ إلى اسم الخدمة المقابلة له.
جرب المثال التالي:
- الطريقة (connect_ex(address تعيد في حال نجاح عملية الاتصال القيمة ‘0’ وفي حال فشل الاتصال تعيد رقم يشير إلى رمز الخطأ.
يمكن الاستفادة من هذه الطريقة من أجل فحص المنافذ المفتوحة.
جرب المثال التالي:
وستكون النتيجة كالتالي:
نتيجة تنفيذ البرنامج تظهر أن المنافذ 155 , 445 هي منافذ مفتوحة.
هذا البرنامج هو فاحص بسيط للمنافذ port scanner
في المقال القادم سوف نقوم بالتعمق بشكل أكبر وكتابة برامج بلغة البايثون تقوم بعملية الاستطلاع وجمع المعلومات من خلال فحص عناوين IP ومعرفة الأجهزة المتصلة ومعرفة الخدمات التي تعمل على هذه الأجهزة.