الإثنين, ديسمبر 23, 2024

الأكثر شهرة

الرئيسيةالتقنيةدمج ثنائيات إنترنت الأشياء مع AFL++

دمج ثنائيات إنترنت الأشياء مع AFL++

في الجزء السابق، نظرنا إلى دمج ثنائيات إنترنت الأشياء البسيطة باستخدام AFL++. تقبل هذه البرامج الإدخال من ملف وكان من السهل التشويش عليها.

في هذه المقالة، سننظر في الثنائيات ذات المقبس. تختلف الثنائيات الضبابية التي تتواصل عبر الشبكة باستخدام المقابس عن الثنائيات الضبابية التي تستخدم الإدخال/الإخراج المستند إلى الملفات. لا يدعم Vanilla AFL وAFL++ الثنائيات ذات المقبس الغامض على الرغم من وجود مشاريع مثل AFLNet و AFLNW التي تستخدم إصدارات معدلة من AFL لنفسه. ومع ذلك، سنرى هنا كيفية استخدام AFL++ العادي لتشويش برامج الشبكة. ال httpd ثنائي في /usr/sbin/httpd هو خادم الويب الخاص بالبرنامج الثابت ويمكن استخدامه كمرشح للتشويش.

يمكننا الانطلاق httpd مع sudo كما هو مبين. هناك حاجة إلى Sudo للربط على المنفذ 80.

لاحظ أن qemu يبدأ من داخل ملف www/ الدليل حيث أن هذا هو المكان الذي توجد به موارد الويب (ملفات html وcss وjs). على الرغم من أنه يظهر خطأ ربط، قيد التشغيل netstat يؤكد ذلك httpd يستمع بالفعل على المنفذ 80.

يمكننا أن نفتح http://127.0.0.1 للتحقق من إمكانية الوصول إلى واجهة الويب.

يمكن أيضًا الوصول إلى واجهة الويب باستخدام curl.

باستخدام وكيل اعتراض مثل Burp Suite، يمكننا عرض طلبات HTTP الفعلية التي يتم إرسالها. محاولة تسجيل الدخول إلى لوحة القيادة باستخدام بيانات الاعتماد admin:123456 يؤدي إلى طلب POST كما هو موضح.

في الصورة أعلاه نقوم بتشغيل خادم الويب عبر المنفذ 8080 (بدلاً من 80) عن طريق الإلحاق -p 8080 إلى سطر الأوامر qemu.

من الآن فصاعدًا، تتمثل الفكرة في تعديل هذا الطلب الأساسي باستخدام التشويش بطرق خفية تؤدي إلى تعطل خادم الويب.

الطريقة الساذجة هي إرسال الطلبات الفعلية عبر الشبكة. ومع ذلك، فإن هذا سيكون بطيئا. الطريقة الأكثر ذكاءً والموصى بها هي جعل خادم الويب يقرأ بيانات طلب HTTP من ملف. سوف ننظر في كلا الاتجاهين.

التشويش الساذج باستخدام رادامسا

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

# fuzz-radamsa.py
import socket
import pyradamsa
 
base_login_request = open("base-login-request.txt", "rb").read()
 
rad = pyradamsa.Radamsa()
i = j = 0
 
while True:
    # Create a modified request based on the base request
    fuzzed_request = rad.fuzz(base_login_request)
 
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 
    # 1 second timeout
    sock.settimeout(1)
 
    sock.connect(("127.0.0.1", 8080))
 
    j += 1
    print(f"[+] Request {j} - ", end="")
 
    sock.sendall(fuzzed_request)
    try:
            sock.recv(50000)
        print("OK")
    except Exception as ex:
            i += 1
            open(f"interesting/{i}.txt", "wb").write(fuzzed_request)
            print(f" {ex} -> saved to {i}.txt")
       sock.close()

يستخدم الكود أعلاه Radamsa لإنشاء بيانات الطلب المعدلة باستخدام طلب تسجيل الدخول الأساسي. يتم بعد ذلك إرسال هذه البيانات عبر المقبس إلى خادم الويب الذي يعمل على المنفذ 8080. إذا لم يستجب الخادم خلال ثانية واحدة، فسيتم حفظ الإدخال في ملف في الدليل المثير للاهتمام.

يمكننا تشغيل الـ Fuzzer كما هو موضح.

انتهت مهلة الطلب 3 أثناء الاستجابة وتم حفظ الإدخال المقابل فيه 1.txt. لاحظ أن المهلة ليست مثل التعطل. إذا تعطل الخادم عند الطلب 3، فلن تنجح الطلبات الأخرى. يعد التشويش بهذه الطريقة غير فعال إلى حد كبير، وبطيئًا، وعرضة للخطأ، وغالبًا ما يؤدي إلى نتائج إيجابية كاذبة.

التشويش مع AFL++

كما تمت مناقشته من قبل، للتشويش مع AFL، يجب أن يقبل البرنامج الإدخال من الملف. ليس لدينا الكود المصدري لـ httpd والتي يمكننا تعديلها لغرضنا. ومن ثم علينا أن نلجأ إلى تعديلات المستوى الثنائي، مثل تصحيح تعليمات التجميع و LD_PRELOAD الحيل. باستخدام هذا الأخير يمكننا تجاوز وظائف الشبكة في libc لجعلهم يقبلون الإدخال من ملف بدلاً من ذلك. ال com.desockmulti يمكن استخدام المشروع على GitHub لهذا الغرض.

قبل أن تظهر كيفية الاستخدام , نحن بحاجة إلى إجراء بعض التعديلات الخاصة بنا. ال httpd ثنائي يتشعب حاليًا إلى الخلفية باستخدام ملف daemon وظيفة. لا نريد هذا السلوك المتشعب أثناء التشويش.

نحن بحاجة إلى تجاوز daemon بحيث يُرجع 0 بدون التفرع في الواقع. يمكن القيام بذلك باستخدام LD_PRELOAD أو تصحيح تعليمات التجميع.

التغيير الآخر الذي يتعين علينا القيام به هو أن نحدثه httpd معالجة طلب واحد بالضبط (على عكس خادم الويب النموذجي الذي يعالج الطلبات إلى أجل غير مسمى) قبل الخروج. بهذه الطريقة يمكننا معرفة الطلب، إن وجد، الذي يعطل خادم الويب.

لإغلاق المقبس، httpd يدعو close وظيفة. هناك ثلاثة مواقع يتم من خلالها استدعاء الإغلاق.

من بينها، نحن بحاجة إلى تعديل واحد في 231c0 للاتصال exit(0) بدلاً من close.

لتصحيح التعليمات سوف نستخدمها القاطع وهو واجهة المستخدم الرسومية ل الرادارات2. يدعم Ghidra أيضًا تصحيح الثنائيات، لكن Cutter أكثر ملاءمة لحالة الاستخدام هذه.

التنقل إلى 0x231c0 في القاطع، نواجه التفكيك التالي.

النقر المزدوج على close يأخذنا إلى 0x106b4.

ال exit تقع الوظيفة في 0x10b64.

وهكذا نستطيع أن نتغير bl close ل bl 0x10b64 للاتصال ب exit وظيفة بدلا من ذلك.

يمكن تغيير التعليمات السابقة مباشرة من mov r0, sl ل eor r0, r0 الذي يحدد التسجيل r0 ل 0 لتعطينا التفكيك التالي.

التأثير الصافي هو أنه يدعو exit(0). التغيير الآخر الذي يتعين علينا القيام به هو تصحيح daemon اتصل على 0x22CB4.

يمكننا تغيير التعليمات إلى eor r0, r0 لجعل التطبيق يصدق أن المكالمة نجحت.

أخيرًا، بعد إجراء التغييرات، انتقل إلى ملف -> تنفيذ التغييرات لحفظ التعديلات. دعونا نعيد تسمية الملف إلى httpd_patched.

اختبار مصححة httpd

جري httpd_patched يمكننا أن نرى أنه لا يتفرع إلى الخلفية.

بالإضافة إلى ذلك، فإنه يتم إنهاؤه بعد معالجة طلب واحد كما هو موضح أدناه.

إعداد desockmulti

نحتاج إلى استخدام مترجم ARM المتقاطع للتجميع com.desockmulti. ال Armv7-eabihf-uclibc تعمل سلسلة الأدوات من Bootlin بشكل رائع لهذا الغرض. نحن بحاجة إلى استخدام سلسلة أدوات تعتمد على uclibc حيث تستخدم ثنائيات البرامج الثابتة نفس الشيء أيضًا. تشغيل أمر الملف /usr/bin/httpd يشير إلى أن الثنائي مرتبط ديناميكيًا بـ ld-uClibc.

$ file usr/sbin/httpd
usr/sbin/httpd: ELF 32-bit LSB executable, ARM, EABI4 version 1 (SYSV), dynamically linked, interpreter /lib/ld-uClibc.so.0, stripped

قبل التجميع com.desockmulti، علينا إجراء تغيير بسيط على مصدره.

$ git diff
diff --git a/desockmulti.c b/desockmulti.c
index 719e6ac..6bcc223 100644
--- a/desockmulti.c
+++ b/desockmulti.c
@@ -450,7 +450,7 @@ int socket(int domain, int type, int protocol)
                pthread_mutex_unlock(&mutex);
        }
 
-       setup_timer();
+       //setup_timer();
 
        if ((fd = original_socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
                perror("socket error");

في desockmulti.c هناك مكالمة إلى أ setup_timer الوظيفة التي تحتاج إلى التعليق عليها كما هو موضح في الفرق أعلاه.

يمكننا بعد ذلك تشغيل إجراء تحديد الحمام للمترجم Arm-linux-gcc في ملف CC متغير البيئة.

$ make CC=~/armv7-eabihf--uclibc--stable-2020.08-1/bin/arm-linux-gcc      

الملف الذي تم إنشاؤه desockmulti.so يمكن نسخها إلى squashfs-root دليل.

اختبار desockmulti

لاختبار ذلك com.desockmulti يعمل بالفعل كما هو متوقع يمكننا تصحيحه httpd مع gdb-متعدد الآرش. أولاً، نحتاج إلى إضافة تبعية إلى المكتبة libpthread.so.0 استخدام patchelf. يمكن تثبيت Patchelf باستخدام apt. وهذا ضروري كما com.desockmulti يستخدم المواضيع في حين httpd لا يرتبط ب libpthread بشكل افتراضي.

$ patchelf --add-needed ./lib/libpthread.so.0 ./usr/sbin/httpd_patched

في المحطة 1، قم بتشغيل الملف الثنائي في qemu مع تحديد المعلمة -g.

ubuntu@binwalk:~/cisco/_RV130X_FW_1.0.3.55.bin.extracted/squashfs-root/www$ sudo qemu-arm-static -g 5555 -L .. -E USE_RAW_FORMAT=1 -E LD_PRELOAD=../desockmulti.so ../usr/sbin/httpd_patched
-p 8080 < ../../base-login-request.txt

الطريق الى desockmulti.so تم تحديده في LD_PRELOAD متغير البيئة. المتغير الآخر USE_RAW_FORMAT خاص ب com.desockmulti.

في محطة أخرى، يمكننا أن نبدأ gdb-متعدد الآرش، قم بتعيين نقطة توقف على fprintf ونعلق على المنفذ 5555.

$ gdb-multiarch -q ./usr/sbin/httpd
GEF for linux ready, type `gef' to start, `gef config' to configure
95 commands loaded for GDB 9.2 using Python engine 3.8
[*] 1 command could not be loaded, run `gef missing` to know why.
Reading symbols from ./usr/sbin/httpd...
(No debugging symbols found in ./usr/sbin/httpd)
gef➤  b fprintf
Breakpoint 1 at 0x10a38
gef➤  target remote :5555
…
gef➤  c

عندما تكون نقطة التوقف قيد التشغيل fprintf يمكننا الضغط على c والاستمرار عدة مرات لفحص محتويات السجل أخيرًا r2.

0xfffe5fa8│+0x0018: 0x30303220  →  0x30303220
0xfffe5fac│+0x001c: 0x0d6b4f20  →  0x0d6b4f20
─────────────────────────────────────── code:arm:ARM ────
   0xff4eb7b8       push   {lr}              ; (str lr,  [sp,  #-4]!)
   0xff4eb7bc       add    r2,  sp,  #8
   0xff4eb7c0      ldr    r1,  [sp,  #4]
 → 0xff4eb7c4      bl     0xff4ee024 
   ↳  0xff4ee024      push   {r4,  r5,  r6,  r7,  r8,  lr}
      0xff4ee028      mov    r5,  r0
      0xff4ee02c      ldr    r6,  [r0,  #76]        ; 0x4c
      0xff4ee030     ldr    r12,  [pc,  #144]      ; 0xff4ee0c8 
      0xff4ee034     cmp    r6,  #0
      0xff4ee038     add    r12,  pc,  r12
──────────────────────────────────── arguments (guessed) ────
vfprintf (
   $r0 = 0x000be3c0 → 0xff006085 → 0xff006085,
   $r1 = 0x00093f5c → 0x00007325 → 0x00007325,
   $r2 = 0xfffe5f98 → 0xfffe5fa0 → 0x50545448 → 0x50545448,
   $r3 = 0x000006c8 → 0x000006c8
)
────────────────────────────────────────────── threads ────
[#0] Id 1, stopped 0xff4eb7c4 in fprintf (), reason: BREAKPOINT
───────────────────────────────────────────── trace ────
[#0] 0xff4eb7c4 → fprintf()
[#1] 0x1dd5c → add sp,  sp,  #1004      ; 0x3ec
───────────────────────────────────────────────────────────
gef➤  x/s *$r2
0xfffe5fa0:     "HTTP/1.1 200 Ok\r\n"

يشير R2 إلى سلسلة قابلة للقراءة “HTTP/1.1 200 Ok\r\n” وهي السطر الأول من استجابة HTTP النموذجية. وهذا يدل على ذلك com.desockmulti يعمل. لا يمكننا رؤية استجابة HTTP على الشاشة ولكنها مع ذلك تعمل على النحو المنشود.

عند هذه النقطة يمكننا البدء في التشويش httpd_patched ومع ذلك، يمكننا إجراء المزيد من التحسينات على نوعية الحياة. على سبيل المثال، يتطلب الملف الثنائي الجذر للتشغيل. يقوم بطباعة رسالة الخطأ التالية إذا بدأ بدون الجذر.

ubuntu@binwalk:~/cisco/_RV130X_FW_1.0.3.55.bin.extracted/squashfs-root/www$ qemu-arm-static -L .. -E USE_RAW_FORMAT=1 -E LD_PRELOAD=../desockmulti.so ../usr/sbin/httpd_patched -p 8080 < ../../base-login-request.txt
===>HTTPD : scheduler set RR with proirity = 99 FAILED
--- [1640588459:322474] accept_num=1, connect_num=0
--- [1640588459:323006] Get pkt, sockindex=0, length=943, pkt[0]=80
+++ [1640588459:323333] Intercepted socket()! original type=AF_INET6 fd=4
--- [1640588459:323785] preeny socket bound, Emulating bind on port 8080
--- [1640588459:324011] preeny listen called, accepting connections ...
--- [1640588459:324223] preeny connect_write for serverfd=4 started
--- [1640588459:324466] preeny connect succeeds, write for serverfd=4, client sock index=0
--- [1640588459:324778] preeny write a 943 bytes packet, client socket index = 0, client sockfd=5
--- [1640588459:325074] preeny connection for serverfd=4 client sockfd=5 shutdown
--- [1640588459:325151] pthread_created or directly called for preeny_connect_write, accept_done_num 1, selected_fd_index 0  
+++ [1640588459:325246] Intercepted socket()! original type=AF_INET6 fd=6
--- [1640588459:325334] preeny socket bound, Emulating bind on port 8080
--- [1640588459:325393] preeny listen called, accepting connections ...
+++ [1640588459:325488] Intercepted socket()! original type=AF_INET fd=7
--- [1640588459:325725] preeny socket bound, Emulating bind on port 8080
--- [1640588459:325747] preeny listen called, accepting connections ...
+++ [1640588459:325976] Intercepted socket()! original type=AF_INET fd=8
--- [1640588459:326095] preeny socket bound, Emulating bind on port 81       
--- [1640588459:326118] preeny listen called, accepting connections ...      
+++ [1640588459:326480] Intercepted socket()! original type=AF_INET6 fd=9    
--- [1640588459:329767] preeny socket bound, Emulating bind on port 81       
--- [1640588459:329820] preeny listen called, accepting connections ...      
/var/run/httpd.pid: Permission denied
+++ [1640588459:330676] shutting down desockmulti...
+++ [1640588459:330844] ... shutdown complete!

فشل في محاولة الوصول /var/run/httpd.pid. يمكننا تصحيح الملف الثنائي وتغيير المسار إلى شيء لا يتطلب امتيازات الجذر للوصول إليه. يمكن القيام بذلك باستخدام محرر سداسي عشري وأيضًا باستخدام Cutter.

يمكننا أن نتغير /var/run/httpd.pid ل /home/ubuntu/h.pid وحفظ. يقع المسار الجديد ضمن الدليل الرئيسي ويمكن الوصول إليه بدون الجذر. من المهم أيضًا ملاحظة أن طول السلسلة البديلة يجب أن يكون أقل من السلسلة الأصلية أو يساويها.

إعادة التشغيل httpd_patched يمكننا أن نرى أنه لا يُظهر خطأ رفض الإذن بعد الآن.

ubuntu@binwalk:~/cisco/_RV130X_FW_1.0.3.55.bin.extracted/squashfs-root/www$ qemu-arm-static -L .. -E USE_RAW_FORMAT=1 -E LD_PRELOAD=../desockmulti.so ../usr/sbin/httpd_patched -p 8080 < ../../base-login-request.txt
===>HTTPD : scheduler set RR with proirity = 99 FAILED
--- [1640594090:533269] accept_num=1, connect_num=0
--- [1640594090:533738] Get pkt, sockindex=0, length=943, pkt[0]=80
+++ [1640594090:533930] Intercepted socket()! original type=AF_INET6 fd=4
--- [1640594090:534277] preeny socket bound, Emulating bind on port 8080
--- [1640594090:534400] preeny listen called, accepting connections ...
--- [1640594090:534562] preeny connect_write for serverfd=4 started
--- [1640594090:534704] preeny connect succeeds, write for serverfd=4, client sock index=0
--- [1640594090:534880] preeny write a 943 bytes packet, client socket index = 0, client sockfd=5
--- [1640594090:535045] preeny connection for serverfd=4 client sockfd=5 shutdown
--- [1640594090:535144] pthread_created or directly called for preeny_connect_write, accept_done_num 1, selected_fd_index 0
+++ [1640594090:535228] Intercepted socket()! original type=AF_INET6 fd=6
--- [1640594090:535283] preeny socket bound, Emulating bind on port 8080
--- [1640594090:535316] preeny listen called, accepting connections ...
+++ [1640594090:535359] Intercepted socket()! original type=AF_INET fd=7
--- [1640594090:535389] preeny socket bound, Emulating bind on port 8080
--- [1640594090:535404] preeny listen called, accepting connections ...
+++ [1640594090:535432] Intercepted socket()! original type=AF_INET fd=8
--- [1640594090:535478] preeny socket bound, Emulating bind on port 81
--- [1640594090:535511] preeny listen called, accepting connections ...
+++ [1640594090:535559] Intercepted socket()! original type=AF_INET6 fd=9
--- [1640594090:535601] preeny socket bound, Emulating bind on port 81
--- [1640594090:535632] preeny listen called, accepting connections ...
--- [1640594090:537111] Accept socket at serverfd=4, got fd=10, accept_sock_num=1.
+++ [1640594090:550073] shutting down desockmulti...
+++ [1640594090:550229] ... shutdown complete!

بالإضافة إلى ذلك، الملف h.pid يتم إنشاؤه داخل الدليل الرئيسي للمستخدم.

$ ls -la /home/ubuntu/h.pid
-rw-rw-r-- 1 ubuntu ubuntu 4 Dec 27 08:34 /home/ubuntu/h.pid

غامض httpd

يمكننا الآن أخيرًا المضي قدمًا في تشويش التصحيح httpd ثنائي. نحن بحاجة إلى إنشاء دليلين: الإدخال-httpd و الإخراج-httpd. السابق سوف يحتوي على الملف طلب تسجيل الدخول الأساسي.txt والتي سيستخدمها AFL++ لإنشاء المزيد من حالات الاختبار.

ubuntu@fuzz:~/_RV130X_FW_1.0.3.55.bin.extracted/squashfs-root/www$ QEMU_LD_PREFIX=.. QEMU_SET_ENV=USE_RAW_FORMAT=1,LD_PRELOAD=../desockmulti.so ../../../AFLplusplus/afl-fuzz -Q -i ../../input-httpd/ -o ../../output-httpd/ -- ../usr/sbin/httpd_patched -p 8080

يمكننا أن نترك التشويش كما هو لمواصلة التشويش. للخروج، اضغط على Ctrl+C في أي وقت. في اختبارنا الموجز، لم يتمكن AFL++ من تعطيل التطبيق.

بهذا نصل إلى نهاية سلسلة AFL المكونة من جزأين. في الجزء الأول، رأينا كيفية تشويش الثنائيات البسيطة التي تقبل الإدخال من ملف. لم تكن تتطلب أي تعديلات وكانت سهلة التشويش. في هذا الجزء، تعلمنا كيفية تحويل ملف ثنائي مأخذ التوصيل لقبول الإدخال من ملف بدلاً من ذلك. يتطلب هذا تصحيح الملف الثنائي على مستوى التجميع واستخدام LD_PRELOAD بشكل أكبر لتجاوز وظائف libc. لقد رأينا أيضًا كيفية استخدام الرادامسا لإنشاء حالات اختبار كطريقة بدائية للتشويش. لا توجد تقنية عالمية يمكن تطبيقها كما هي لتشويش أي برنامج ثنائي ثابت محدد لإنترنت الأشياء. وسوف تختلف على أساس كل حالة على حدة ولكن الفكرة متشابهة. لأية تعليقات أو أسئلة أو اقتراحات لا تتردد في ترك تعليق أدناه.

ADVTUT
ADVTUThttps://advtut.com
رحلتي تتمحور حول شغفه بأمان البيانات والشبكات، مما قاده إلى إنشاء مدونة توب ديلي. من خلالها، يشارك رؤى ونصائح عملية لجعل الأمان الرقمي متاحًا للجميع. بفضل خلفيته التعليمية القوية، نفهم أمان البيانات في عالم اليوم الذي تتطور فيه التهديدات الإلكترونية أمر ضروري لجميع المستخدمين، وليس فقط للخبراء التقنيين. يهدف إلى تمكين القراء - سواء كانوا من عشاق التقنية المحترفين أو مجرد أشخاص يسعون لحماية معلوماتهم الشخصية. انضموا الينا بينما يستكشف عالم أمان البيانات المثير، ويساعدكم على تعزيز سلامتكم الرقمية على طول الطريق!
مقالات ذات صلة

ترك الرد

من فضلك ادخل تعليقك
من فضلك ادخل اسمك هنا