الأحد، 12 سبتمبر 2021

برمجة سكريبت بالبايثون يعرض المنافذ المتاحة ببرتوكول TCP

   بسم الله الرحمن الرحيم

في هذا الشرح البسيط ستتعلم كيف تبرمج برنامج بسيط بالبايثون يظهر لك المنافذ المفتوحة على اي جهاز مشبوك على الشبكة الخاصة ببرتوكول TCP , لكن قبل ان ابدأ يجب ان انبه ان هذا البرنامج للأغراض التعليمية و يجب الا تستخدمه الا على انظمة يحق لك الوصول له .

 

  •  كيف يعمل البرنامج ؟
البرنامج يستخدم عملية handshake في برتوكول TCP في حالة اتمام الاتصال يقوم البرنامج بأنذار المستخدم برقم المنفذ (Port).
 
هذه الصورة تبين عملية اتصال ناجحة لبرتوكول TCP
مصدر الصورة :https://commons.wikimedia.org/wiki/File:Tcp_normal_2.png
 
1. يرسل الجهاز للسيرفر رسالة TCP -SYN 
2. في حالة توافر المنفذ يرد السيرفر برسالة SYN-ACK
3. لتأكيد الاتصال يرسل الجهاز للسيرفر رسالة ACK لتأكيد الاتصال 

طبعا هذا الشرح مبسط جدا  , لغاية عدم تعقيد الموضوع , يمكن في المستقبل اخصص موضوع خاص ببرتوكول TCP .

في حالة عدم نجاح عملية الاتصال سوف يتم اعتبار المنفذ مغلق , و الأن لشرح بسيط لبرمجة الشبكات في البايثون قبل ان نبدأ , بشكل عام جميع لغات البرمجة تتشابه في الخطوات التالية :


 طبعا لمثالنا سوف يكون برنامجنا هو Client لكن من دون ارسال اي بيانات فقط سيحاول الاتصال و سيقوم بعرض النتيجة للاتصال ثم اغلاق الاتصال .

و الأن للنص البرمجي الكامل لمثالنا :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/usr/bin/python3
import sys
import socket

if len(sys.argv) == 2:
    print("Start Scanning : {}".format(sys.argv[1]))
    target = sys.argv[1]
else:
    print(("Usage:{} target".format(sys.argv[0])))
    exit(2)
    
    
try:
    for port in range(1,65535):
        sos = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        result = sos.connect_ex((target,port))
        if result == 0 :
            print ( "{} is Open".format(port))
        sos.close()
        
except KeyboardInterrupt:
    print("\nExiting the program")
    exit(0)
except socket.gaierror:
    print("Host couldn't be reslove")
    exit(1)
except socket.error:
    print("Couldn't connect to {}".format(target))
    exit(2)


بندأ بشرح برنامجنا بالتفصيل , أولا نبدأ في السطرين الأولين  :

1
2
import socket 
import sys   
 
المكتبة البرمجة socket بنستخدمها لعملية الاتصال , هذه المكتبة تستخدم لجميع عمليات الشبكات الاساسية , و مكتبة sys التي بنحتاجها لمعالجة المعطيات من سطر الاوامر .


و الان الى السطر الذي يعالج معطيات سطر الأوامر :


1
2
3
4
5
6
if len(sys.argv) == 2: #اذا طول معطيات سطر الاوامر يساوي 2 
    print("Start Scanning : {}".format(sys.argv[1])) #اطبع اسم الهدف 
    target = sys.argv[1] #احفظ اسم الهدف في المتغير target
else:
    print(("Usage:{} target".format(sys.argv[0]))) #في حال عدم تطابق الشرط اطبع رسالة الاستخدام و اخرج من البرنامج
    exit(2)

هذا مثال على استخدام برنامجنا , في بايثون يكون معاملات البرنامج (program parameters)  تبدأ دائما باسم ملف البرنامج , و يتم تخزين المعاملات في مصفوفة (array) يمكن الوصول لها باستخدام sys.argv

kh@DESKTOP-3444:~$ ./myscript target
 
و الأن إلى الجزء الذي يقوم بالعمل الفعلي :

1
2
3
4
5
6
7
for port in range(1,65535): # المدى يمثل جميع منافذ برتوكول TCP
        sos = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #انشاء مقبس الشبكة
        result = sos.connect_ex((target,port)) # محاولة الاتصال 
        if result == 0 : #اذا كانت نتيجة الاتصال صفر فالاتصال ناجح
            print ( "{} is Open".format(port)) #طباعة رسالة للمستخدم
        sos.close() #اغلاق الاتصال

قمت بوضع هذه الأوامر في كتلة Try-Except للتعامل مع الإستثاءات التي قد تواجه التنفيذ , والأن لشرح هذه الاسطر بتفصيل اكثر:


1
sos = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

هذا السطر الذي ينشيء المقبس (socket) , و يخبر النظام لحجز الموارد كما يحدد نوع نظام العناوين و نوع الاتصال :
 
  • AF_INET : نظام عناوين الانترنت النسخة الرابعة Internet protocol version 4 أو اختصارا IPv4 , هو النظام الحالي المستخدم لعنونة الاجهزة على شبكة الانترنت
  • SOCK_STREAM : استخدام برتوكول TCP كنوع البرتوكول المستخدم لتوصيل البيانات .
للعلم يمكنك كتابة امر تحديد المقبس (socket) من دون تحديد نظام العناوين و نوع الاتصال حيث انه القيم الافتراضية .
 
1
sos = socket.socket()

و الأن بعد انشاء الاتصال سنحاول اجراء الاتصال باستخدام connect_ex , في حالة نجاح الاتصال سنحصل على القيمة صفر , و في هذه الحالة فقط سيتم طباعة رقم المنفذ :

1
2
3
result = sos.connect_ex((target,port))  
        if result == 0 : 
            print ( "{} is Open".format(port)) 

و في الاخير سنقوم بأغلاق المنفذ :

1
sos.close()

و للتعامل مع جميع الاستثناءات (exceptions) قمنا باستخدام try..except :
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
try:



except KeyboardInterrupt:
    print("\nExiting the program")
    exit(0)
except socket.gaierror:
    print("Host couldn't be reslove")
    exit(1)
except socket.error:
    print("Couldn't connect to {}".format(target))
    exit(2)

و هذا شرح للاستثناءات :
  • KeyboardInterrupt : في حالة ضغط المستخدم Ctrl+C سيتم اغلاق البرنامج
  • socket.gaierror :  في حالة فشل البرنامج بتحويل النطاق (Domain) إلى عنوان رقمي IP
  • socket.error : في حالة فشل انشاء مقبس (socket) 

هذا شرح مبسط لهذا البرنامج البسيط , لكن هل هذا البرنامج يعمل , اذا اردت تجربة البرنامج تستطيع استخدام جهازك مباشرة باستخدام العنوان localhost .
لكن هل هذا البرنامج عملي ؟ , بصراحة هذا البرنامج يعمل و لكن هنالك الكثير من الامور الذي يجب توضيحها 
  • اولا هذا البرنامج سيكون بطيء بشكل كبير حيث يتم تنفيذه بشكل خطي و اذا اردنا تسريعه يجب ان يتم التنفيذ بأستخدام التنفيذ متزامن (concurrent execution ) .
  • عملية مسح المنافذ (port scan ) باستخدام جميع المنافذ و بالتسلسل و بدون وجود وقت انتظار سيجعل ابسط برنامج جدار نار (Firewall) ينذر المستخدم .
  • عملية المسح باستخدام عملية الاتصال كاملة , "مصافحة برتوكول TCP" الكاملة بطيئة و مكشوفة للبرامج جدران النار.
في النهاية هذا رابط لموضوع عن برمجة الشبكات ببايثون بالتفصيل :



ليست هناك تعليقات:

إرسال تعليق