
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 इस प्रकार दिखेगा:

पहली पुनरावृत्ति में, prop = '' मौजूद नहीं है, यह cur[''] = {} असाइन करेगा। इसका मतलब है कि result में भी '' नामक एक गुण होगा जिसका मान एक खाली ऑब्जेक्ट होगा। उसके बाद, cur को {} असाइन किया जाता है, जो पिछले असाइनमेंट का वापसी मान है (cur और cur[prop] दोनों एक ही ऑब्जेक्ट की ओर इंगित करते हैं):

अब, prop 'label' बन जाएगा:

पहले की तरह, result में 'label' गुण होगा और prop __proto__ बन जाएगा:

तीसरी पुनरावृत्ति के साथ, cur अपना प्रोटोटाइप बन जाएगा क्योंकि __proto__ हमेशा हर ऑब्जेक्ट में मौजूद होता है:

उसके बाद, prop env बन जाता है।
फिर, चूँकि cur Object.prototype की ओर इंगित करता है, यह Object.prototype में env को एक खाली ऑब्जेक्ट के रूप में जोड़ देगा और cur Object.prototype.env के अंदर env को भी संदर्भित करता है।

उसके बाद, लूप बाहर निकलेगा और cur[prop] = data[p] env[AAA] = 'a' के बराबर होगा।

Object.prototype env के साथ दूषित हो गया है:

forkफ़ंक्शन एकChildProcessलौटाता है जिसका उपयोगspawnको लागू करने के लिए किया जा सकता है
fork फ़ंक्शन को लागू करते समय पोर्ट को 9669 (दूसरा पोर्ट) में बदलें और फिर हम मुख्य प्रक्रिया को सामान्य रूप से डीबग कर सकते हैं:

दूषित Object.prototype को अनुकरण करें और लूप से पहले जाएं:

जैसा कि हम देख सकते हैं, प्रोटोटाइप प्रदूषण के कारण env { AAA: 'a' } के बराबर है। अधिक विशेष रूप से, env को options.env को सौंपा गया है। और options उस गुण को परिभाषित नहीं करता है, इसलिए यह अपने प्रोटोटाइप के मान का उपयोग करेगा।
लूप के बाद:

किसी तरह, अमान्य पर्यावरण चर (AAA=a, env=[Object object]) के साथ, कैनवास एक नया सॉकेट नहीं बना सकता:

लेकिन चाइल्ड प्रक्रिया अभी भी बनाई जा सकती है:

सामान्य प्रवाह के साथ, यह एक नया WebSocket कनेक्शन बनाएगा:

अब पेलोड के साथ प्रयास करें और normalizeSpawnArguments में कूदें:

जैसा कि हम देख सकते हैं, स्टैक ट्रेस समान है।
लेकिन, env दूषित है:

वोइला!
लूप के बाद envPairs:

और हमें रिवर्स शेल मिल गया:

spawn फ़ंक्शन में normalizeSpawnArguments को कॉल करने के बाद:

जैसा कि हम देख सकते हैं, envPairs में हमारा पेलोड है। साथ ही, उसके बाद, spawn internal/child_process.js के अंदर spawn फ़ंक्शन को कॉल करेगा:

options वेरिएबल this._handle.spawn में पास किया जाएगा:

जहाँ this._handle एक प्रक्रिया का हैंडल है:

From 3377f813a5d96ff466bdf7343ce161de24830ed4 Mon Sep 17 00:00:00 2001
From: ppisljar <[email protected]>
Date: Wed, 16 Jan 2019 06:01:20 -0800
Subject: [PATCH] fixes
---
.../core_plugins/timelion/server/series_functions/props.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/legacy/core_plugins/timelion/server/series_functions/props.js b/src/legacy/core_plugins/timelion/server/series_functions/props.js
index 81b74901d4db..80e9cafd6712 100644
--- a/src/legacy/core_plugins/timelion/server/series_functions/props.js
+++ b/src/legacy/core_plugins/timelion/server/series_functions/props.js
@@ -32,7 +32,7 @@ function unflatten(data) {
let prop = '';
let m;
while (m = regex.exec(p)) {
- cur = cur[prop] || (cur[prop] = (m[2] ? [] : {}));
+ cur = (cur.hasOwnProperty(prop) && cur[prop]) || (cur[prop] = (m[2] ? [] : {}));
prop = m[2] || m[1];
}
cur[prop] = data[p];