
Kibana प्रोटोटाइप प्रदूषण RCE (CVE-2019-7609) के लिए PoC और विश्लेषण।
किबाना संस्करण 5.6.15 और 6.6.1 से पहले के संस्करणों में टिमेलियन विज़ुअलाइज़र में एक मनमाना कोड निष्पादन दोष है। टिमेलियन एप्लिकेशन तक पहुंच वाला एक हमलावर एक अनुरोध भेज सकता है जो जावास्क्रिप्ट कोड को निष्पादित करने का प्रयास करेगा। इससे संभावित रूप से हमलावर होस्ट सिस्टम पर किबाना प्रक्रिया की अनुमतियों के साथ मनमाने आदेशों को निष्पादित कर सकता है।
CVSS:

ब्लॉग: https://research.securitum.com/prototype-pollution-rce-kibana-cve-2019-7609/
पेलोड: https://github.com/mpgn/CVE-2019-7609
सेटअप:
उपयोग:
शीट को पार्स करने के बाद:

पूर्व-प्रसंस्करण शीट के बाद, हमारे पास एक queries ऑब्जेक्ट है:

फिर, हम queries सरणी (जो values विधि का उपयोग करके एक सरणी में परिवर्तित हो जाती है) पर लूप करते हैं और फ़ंक्शन को लागू करने के लिए invoke में query.function और query.arguments पास करते हैं।
invoke फ़ंक्शन में, पहले हम फ़ंक्शन की परिभाषा उसके नाम (query.function) के आधार पर प्राप्त करते हैं:

इस फ़ंक्शन परिभाषा में तीन प्रकार के फ़ंक्शन शामिल हैं: fn, originalFn और timelionFn। फिर, यह args (जो query.arguments है) पर लूप करता है और तर्कों को हल करता है:

इस मामले में, args में तर्क एक ऑब्जेक्ट है जिसका प्रकार 'literal' है, इसलिए यह केवल शाब्दिक मान लौटाता है:

वास्तव में, मान एक प्रॉमिस में लिपटा होता है।

अनुक्रमित तर्क एक byName ऑब्जेक्ट वाला तर्क है जिसमें q सरणी होती है:

उसके बाद, invoke फ़ंक्शन सभी अनुक्रमित तर्कों के साथ functionDef.fn को कॉल करेगा, जो Timelion वर्ग का एक फ़ंक्शन है:

fn फ़ंक्शन originalFn को कॉल करेगा, जो config.fn से आता है जहाँ config tlConfig है। और वह फ़ंक्शन Datasource extends Timelion वर्ग का fn है:

जैसा कि हम देख सकते हैं, यह एक अन्य originalFn को कॉल करता है जिसका नाम esFn है जो एक seriesList ऑब्जेक्ट लौटाता है:

उस फ़ंक्शन का उपयोग "एक elasticsearch इंस्टेंस से डेटा खींचने" के लिए callWithRequest फ़ंक्शन को कॉल करके किया जाता है।
seriesList Datasource.fn में इस प्रकार दिखता है:

और Timelion.fn में यह इस प्रकार दिखता है:

पूर्व-प्रसंस्करण शीट के बाद, श्रृंखला सूची इस प्रकार है:

और कोड श्रृंखला सूची को हल करने के लिए resolveChainList को कॉल करेगा:

प्रत्येक श्रृंखला को एक प्रॉमिस में मैप किया जाएगा जो एक फ़ंक्शन से लौटाया जाता है जो 'first' को fnName और श्रृंखला को args के रूप में invoke करता है।
फ़ंक्शन परिभाषा फिर से नाम से प्राप्त की जाती है:

इस बार, resolveArguments args को एक सरणी के रूप में प्राप्त करता है और यह प्रत्येक तर्क को हल करने के लिए resolveArguments को पुनरावर्ती रूप से कॉल करेगा। लेकिन, हमारे पास सूचकांक 0 के साथ केवल एक तर्क है। और वह तर्क एक ऑब्जेक्ट है जिसका type == chain है।
इसलिए, स्विच केस में, यह invokeChain फ़ंक्शन को कॉल करेगा और उसमें श्रृंखला ऑब्जेक्ट पास करेगा:

इनवोक चेन के अंदर, यह chain सरणी को shift करेगा। shift फ़ंक्शन हटाए गए तत्व को लौटाएगा, इसलिए link es ऑब्जेक्ट होगा:

क्योंकि es का प्रकार 'chain' नहीं है (यह 'function' है) और !result सत्य है, कोड invoke फ़ंक्शन को 'first' के रूप में fnName और es ऑब्जेक्ट को args के रूप में कॉल करता है:
इस बार, प्रक्रिया ऊपर जैसी ही है, इसलिए invokeChain के कॉल पर छोड़ें जहाँ link props ऑब्जेक्ट है:

फिर से, कोड invoke फ़ंक्शन को 'first' के रूप में fnName और props ऑब्जेक्ट को args के रूप में कॉल करता है:

props का originalFn अब firstFn है, es की तरह fn नहीं है, और केवल एक तर्क स्वीकार करता है:

वह मूल फ़ंक्शन अंततः कमजोर unflatten फ़ंक्शन को कॉल करेगा। वास्तव में, यह पहले Timelion के fn को कॉल करेगा। फिर fn props के originalFn को कॉल करेगा:

props का firstFn args के byName ऑब्जेक्ट में inputSeries और global गुणों को छोड़ देगा:

इसलिए unflatten में पास किया गया data होगा:
{
label.__proto__.env.AAA: "a"
}
प्रमाण:

props(label.__proto__.env.AAA="a") का उपयोग करें। data इस प्रकार दिखेगा:
