
CVE-2022-46169 का चरण-दर-चरण विश्लेषण: प्रमाणीकरण बायपास और कमांड इंजेक्शन के माध्यम से Cacti में अप्रमाणित दूरस्थ कोड निष्पादन, Docker लैब सेटअप और शोषण वॉकथ्रू के साथ।
Cacti एक ओपन-सोर्स परिचालन निगरानी उपकरण है जो PHP, MySQL/MariaDB में लिखा गया है और यह एक अनुकूल इंटरफ़ेस प्रदान करता है।
यह भेद्यता 2022 में पाई गई थी जो 1.2.23 से पहले के सभी संस्करणों को प्रभावित करती है। इस बग को RCE (रिमोट कोड निष्पादन) प्राप्त करने के लिए प्रमाणीकरण बायपास और कमांड इंजेक्शन की एक श्रृंखला की आवश्यकता होती है।
इस CVE विश्लेषण में, मैं Cacti को Docker में चलाऊंगा और कोड विश्लेषण के लिए VSCode का उपयोग करूंगा। सेटअप काफी सरल होगा, पहले हमें एक नया वातावरण बनाने के लिए docker-compose.yaml फ़ाइल की आवश्यकता होगी। नीचे docker-compose.yaml फ़ाइल है:
version: '2'
services:
cacti:
image: "smcline06/cacti"
container_name: cacti
domainname: example.com
hostname: localhost
ports:
- "8088:80"
environment:
- DB_NAME=cacti_master
- DB_USER=cactiuser
- DB_PASS=cactipassword
- DB_HOST=db
- DB_PORT=3306
- DB_ROOT_PASS=rootpassword
- INITIALIZE_DB=1
- TZ=America/Los_Angeles
volumes:
- cacti-data:/cacti
- cacti-spine:/spine
- cacti-backups:/backups
links:
- db
db:
image: "mariadb:10.3"
container_name: cacti_db
domainname: example.com
hostname: db
ports:
- "3307:3306" # Change host port to 3307
command:
- mysqld
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_unicode_ci
- --max_connections=200
- --max_heap_table_size=128M
- --max_allowed_packet=32M
- --tmp_table_size=128M
- --join_buffer_size=128M
- --innodb_buffer_pool_size=1G
- --innodb_doublewrite=ON
- --innodb_flush_log_at_timeout=3
- --innodb_read_io_threads=32
- --innodb_write_io_threads=16
- --innodb_buffer_pool_instances=9
- --innodb_file_format=Barracuda
- --innodb_large_prefix=1
- --innodb_io_capacity=5000
- --innodb_io_capacity_max=10000
environment:
- MYSQL_ROOT_PASSWORD=User@123
- TZ=America/Los_Angeles
volumes:
- cacti-db:/var/lib/mysql
volumes:
cacti-db:
cacti-data:
cacti-spine:
cacti-backups:
फ़ाइल बनाने के बाद, कमांड लाइन खोलें और फ़ाइल निर्देशिका पर जाएं, docker-compose up -d कमांड चलाएं, ब्राउज़र खोलें और localhost:8088 पर जाएं। सबसे पहले आप एक लॉगिन पृष्ठ देखेंगे:

डिफ़ॉल्ट क्रेडेंशियल admin/admin है। सेटअप की प्रक्रिया नीचे फ़ोटो द्वारा प्रस्तुत की जाएगी:

नया पासवर्ड बनाएं

इंस्टॉलेशन पूरा करने के बाद, हमारे पास इस तरह का एक कंसोल स्क्रीन होगा

अब आइए भेद्यता का विश्लेषण शुरू करें। जैसा कि हम जानते हैं, कमजोर फ़ाइल remote_agent.php है, इसलिए हम ब्राउज़र पर फ़ाइल तक पहुंचने का प्रयास करेंगे

यह कहता है कि हम फ़ाइल तक पहुंचने के लिए अधिकृत नहीं हैं। अब फ़ाइल का स्रोत कोड देखने का समय है

यह remote_client_authorized() फ़ंक्शन को कॉल करके जांच करता है। आइए उस फ़ंक्शन में गहराई से जाएं।

सबसे पहले, सर्वर get_client_addr() फ़ंक्शन के माध्यम से हमारा IP पता प्राप्त करता है और फिर हमारे IP को होस्टनाम में अनुवाद करने के लिए gethostbyaddr() फ़ंक्शन का उपयोग करता है। फिर सर्वर poller तालिका में उपलब्ध सभी pollers को लाता है और प्रत्येक poller के होस्टनाम की तुलना IP पते से अनुवादित आपके होस्टनाम से करता है। यहां एक बायपास है, get_client_addr() के अंदर:

हम देख सकते हैं कि सर्वर निम्नलिखित हेडर में से एक के माध्यम से IP पता प्राप्त करेगा:
- X-Forwarded-For
- X-Client-IP
- X-Real-IP
- X-ProxyUser-Ip
- CF-Connecting-IP
- True-Client-IP
- HTTP_X_FORWARDED
- HTTP_X_FORWARDED_FOR
- HTTP_X_CLUSTER_CLIENT_IP
- HTTP_FORWARDED_FOR
- HTTP_FORWARDED
- HTTP_CLIENT_IP
- REMOTE_ADDR
यह हमें अपने IP पते के मान को पूरी तरह से नियंत्रित करने की अनुमति देता है। इस मामले में, हम अपने IP को एक मान्य IP पर स्पूफ करने के लिए X-Forwarded-For हेडर का उपयोग कर सकते हैं, जो हमें प्राधिकरण को बायपास करने की अनुमति देता है। X-Forwarded-For हेडर का उपयोग अक्सर मूल IP पते की पहचान करने के लिए किया जाता है यदि क्लाइंट और सर्वर के बीच कोई प्रॉक्सी या लोड बैलेंसर हो। हालाँकि, यह हमलावरों के लिए शोषण करने का एक हमला सतह होगा। चूंकि हम cacti को स्थानीय रूप से चलाते हैं, हमें एक ऐसा IP पता निर्दिष्ट करने की आवश्यकता है जो localhost पर अनुवादित होगा, जो कि 127.0.0.1 है।

अब तो ठीक लग रहा है, है ना? हालाँकि, यह तो शुरुआत है दोस्तों!!! हमें सफलतापूर्वक कमांड इंजेक्ट करने और रिमोट कोड निष्पादन प्राप्त करने के लिए और अधिक कोड विश्लेषण की आवश्यकता है। प्रमाणीकरण समाप्त करने के बाद, प्रोग्राम यह कोड निष्पादित करेगा

सर्वर action पैरामीटर प्राप्त करेगा और Switch/Case में प्रवेश करेगा। यदि action का मान pollerdata है, तो प्रोग्राम poll_for_data() को कॉल करेगा। यह फ़ंक्शन कमांड इंजेक्शन के लिए कमजोर है, इसलिए हम इसका सावधानीपूर्वक विश्लेषण करेंगे।

फ़ंक्शन उपयोगकर्ता के अनुरोध पैरामीटर local_data_ids, host_id, poller_id से प्राप्त 3 पैरामीटर $local_data_ids, $host_id, $poller_id लेगा। पैरामीटर प्राप्त करने के लिए फ़ंक्शन में अंतर पर ध्यान दें, एक get_filter_request_var है और दूसरा get_nfilter_request_var है, अंतिम फ़ंक्शन में एक अतिरिक्त n है, हम इसके बारे में और चर्चा करेंगे। उसके बाद, प्रोग्राम जांच करेगा कि क्या हम local_data_ids पैरामीटर प्रदान करते हैं और प्रत्येक को local_data_ids और host_id के आधार पर poller_item तालिका से डेटा प्राप्त करने के लिए लूप करेगा। क्वेरी $items में सहेजी जाएगी।

यदि क्वेरी परिणामों के साथ लौटती है, तो प्रोग्राम $items में प्रत्येक $item के माध्यम से लूप करेगा और एक Switch/Case स्टेटमेंट में प्रवेश करेगा जो $item['action'] को Switch मान के रूप में लेता है। कई केस हैं लेकिन जिस केस की हमें जांच करनी चाहिए वह POLLER_ACTION_SCRIPT_PHP है जिसका अर्थ है action 2 के बराबर है।