إخفاء المعلومات في حزم IP

ذات مرة ، قبل الدفاع عن عمل مختبري آخر ، سألوني سؤالًا: ما هي حقول حزمة IP التي يمكن استخدامها لحاف؟ لم أكن أعرف وتجاهلت فقط. ولكن سرعان ما قررت أن أدرس هذه المسألة.

تحت الخفض ، ستجد دراسة رؤوس حزم IP ، أداة ping الخاصة بـ Python وعدة طرق لنقل البيانات دون جذب الانتباه.

المحتويات


  1. بنية حزمة IP
  2. إعداد البيئة
  3. بينغ: خيار سهل
  4. بينغ: خيار صعب
  5. التحسينات؟

بنية حزمة IPv4




حدد الحقول التي لن يؤثر تغييرها بشكل كبير على الحزمة:

يمكن أن يختلف القانون الدولي الإنساني من 5 إلى 15.
يُستخدم حقل ToS لتحديد أولويات إشعارات حركة المرور والازدحام دون إسقاط الحزم. في معظم الأحيان ، يكون هذا الحقل صفرًا. نظريًا ، يمكن استخدامه لإرسال بايت كامل من المعلومات.
طول الرزمة هو حقل ممتاز لإرسال الأرقام من 20 إلى 65535.
يمكن لـ TTL إرسال ما يصل إلى 7 بتات من المعلومات. تحتاج إلى معرفة عدد القفزات للمضيف وأخذ هذا في الاعتبار.

إعداد البيئة


لتكرار التجربة ، ستحتاج إلى جهازين مع Python وإطار عمل scapy.

يمكنك تثبيته باتباع التعليمات من الوثائق . في حالتي ، كانت هاتان القطرتان على DO مع تشغيل الشبكة المحلية. لاختبار قابلية تشغيل stegano ، تم اختيار مسارين: من خلال الشبكة المحلية للقفز الواحد وعبر الإنترنت للقفزتين.

بينغ: خيار سهل


ننفذ أولاً sender.py ، الذي سيرسل حزم ICMP بدون رسائل مخفية.

from scapy.all import * #    10.0.0.2  icmp-type 8 (echo-request) pkt = IP(src="10.0.0.1", dst="10.0.0.2") / ICMP(type = 8) #      sr1(pkt) 

ستقوم Scapy بملء الحقول المتبقية بالقيم الافتراضية قبل الإرسال وستقوم بحساب المجموع الاختباري.

على جانب الاستلام ، اكتب listener.py ، الذي سيستمع ويعرض جميع حزم ICMP الواردة.

 from scapy.all import * #    # filter --  icmp # timeout --   10  # count --    100  # iface --    eth1 packets = sniff(filter = "icmp", timeout = 10, count = 100, iface = "eth1") #      for pkt in packets: #     echo-request if pkt[ICMP].type != 8: continue #    pkt.show() 

إخراج المستمع
 ###[ Ethernet ]### dst = hh:hh:hh:hh:hh:hh src = gg:gg:gg:gg:gg:gg type = 0x800 ###[ IP ]### version = 4 ihl = 5 tos = 0x0 len = 28 id = 24923 flags = frag = 0 ttl = 64 proto = icmp chksum = 0x4364 src = 10.0.0.1 dst = 10.0.0.2 \options \ ###[ ICMP ]### type = echo-request code = 0 chksum = 0xf7ff id = 0x0 seq = 0x0 ###[ Padding ]### load = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' 


يحتوي رأس حزمة IP على حقل معرّف. املأها بالرموز "A" و "B":

 payload = ord("A") * 0x100 + ord("B") pkt = IP(src="10.0.0.1", dst="10.0.0.2", id = payload) / ICMP(type = 8) 

علاوة على ذلك ، يوجد في رأس ICMP نفس الحقل بالضبط حيث يمكن أيضًا تحميل وحدتي بايت.

قم بتغيير المستمع لعرض البيانات المستلمة:

 from scapy.all import * import sys packets = sniff(filter="icmp", timeout = 10, count = 100, iface="eth0") for pkt in packets: if pkt[ICMP].type != 8: continue #    a, b = divmod(pkt[IP].id, 0x100) sys.stdout.write(chr(a)) sys.stdout.write(chr(b)) sys.stdout.flush() 

في الصورة والتشابه ، يمكنك ملء أي حقل تمت ملاحظته سابقًا بأنه مناسب للحاف.

بينغ: خيار صعب


لم يكن نقل البيانات من الفقرة السابقة هو الأكثر وضوحًا ، ولكن يمكننا أن نجعلها أكثر وضوحًا. يمكنك إخفاء البيانات الموجودة في الحقل من أجل المجموع الاختباري. وفقًا لـ RFC1071 ، يكون المجموع الاختباري (فجأة!) انعكاسًا أحاديًا لمجموع حسابي أكثر تعقيدًا قليلاً.

شرح بمثال
لنفترض أن لدينا رأسًا نريد حساب المجموع الاختباري له. في وقت الحساب ، تتم إعادة تعيين حقل المجموع الاختباري.

 4500 003c 000a 0000 8001 [checksum] c0a8 000d c0a8 000d 

1. اجمع كل الكلمات ذات 16 بت ، وتذكر النقل من الترتيب العالي:

 4500 + 003c + 000a + 0000 + 8001 + [checksum=0000] + c0a8 + 000d + c0a8 + 000e = = (2) 46b2 

2. أضف النتيجة مع التحويلات:

 46b2 + 2 = 46b4 

3. عكس:

 ~(46b4) = b94b 

b94b هو المجموع الاختباري الذي نبحث عنه . للتحقق ، يمكنك الاستبدال في الرأس وتنفيذ الخطوتين 1 و 2. إذا حصلت على FFFF ، فإن المبلغ الموجود صحيح.

التحقق:

 1. 4500 + 003c + 000a + 0000 + 8001 + [checksum=b94b] + c0a8 + 000d + c0a8 + 000e = = (2) FFFD 2. FFFD + 2 = FFFF 


نحن نعلم أن المجموع الاختباري للحزمة يتغير مع مرور العقد عبر الشبكة ، مع تغير TTL. أيضًا ، عند المرور عبر NAT في الحزمة ، يتم استبدال "عنوان المصدر" ، مما يؤثر أيضًا على المجموع الاختباري. وكم ستنخفض TTL عند الوصول إلى مستمعنا ... الكرز على الكعكة هو أن شهادة "المعرف" تتزامن مع شاهد المجموع الاختباري. تسمح لنا هذه الحقيقة بالتأثير على المجموع الاختباري وتغييره إلى أي قيمة من منطقة التعريف. نظرًا لأنه سيتم حساب المجموع الاختباري (الحمولة) فقط عند تمرير العقدة الأخيرة في المسار ، فمن المهم أن تأخذ في الاعتبار كل ما يمكن تغييره في الحزمة أثناء المسار أثناء الحسابات.

خوارزمية العثور على "المعرّف" ، والتي ستمنحنا المجموع الاختباري المطلوب:

  1. نقوم بتكوين الحزمة كما هو الحال عند المرور عبر العقدة الأخيرة (IP ، TTL ، إلخ)
  2. في "المعرف" اكتب الحمولة
  3. نحسب المجموع الاختباري
  4. يجب كتابة النتيجة في "معرف" الحزمة المرسلة

سنكتب وظيفة ستشكل حزمة حسب عدد الآمال ، عناوين IP وراء NAT واثنان بايت من الحمولة.

 # src -   # src_nat -    NAT # dst -   # dttl -       # a, b --      def send_stegano(src, src_nat, dst, dttl, a, b): #       payload = ord(a)*0x100 + ord(b) #         pkt = IP(dst=dst, src=src_nat, ttl=64-dttl, id = payload) / ICMP(type=8) #  Scapy  chksum pkt = IP(raw(pkt)) #     pkt[IP].src = src pkt[IP].ttl = 64 pkt[IP].id = pkt[IP].chksum #   chksum,  Scapy   del pkt[IP].chksum # Scapy      pkt = IP(raw(pkt)) #      sr1(pkt) 

التحسينات؟


  • الحقول chksum ، seq ، id في رأس بروتوكول ICMP يمكن استخدامها أيضًا لنقل البيانات
  • يمكن استخدام ToS لتحديد الحزم "من تلقاء نفسها" وتجاهل طلب صدى الآخرين.

Source: https://habr.com/ru/post/ar413851/


All Articles