2 पॉइंट द्वारा GN⁺ 2023-10-12 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • curl 8.4.0 की रिलीज़ के साथ सामने आया CVE-2023-38545 SOCKS5 proxy handling के दौरान हुआ heap buffer overflow है, और curl security issues में दुर्लभ HIGH severity vulnerability है
  • समस्या 2020 में SOCKS5 connection code को blocking call से non-blocking state machine में बदलने के दौरान आई, और curl 7.69.0 से प्रभावित करती है
  • remote name resolution mode में 255 bytes से बड़े hostnames को local resolution में बदलने वाला पुराना logic, state machine की re-call के साथ मिलकर, बहुत लंबा hostname छोटे buffer में copy कर सकता था
  • attack सफल होने के लिए libcurl client को SOCKS5 proxy-resolver-mode और automatic redirects का उपयोग करना होगा, और attacker-controlled HTTPS server को 16KB से बड़े और 64KB या कम hostname वाला HTTP 30x Location: लौटाना होगा
  • curl 8.4.0 से बहुत लंबे hostnames पर remote resolution को local resolution में बदलने के बजाय error लौटाया जाता है, और इसी scenario को रोकने वाला test जोड़ा गया है

CVE-2023-38545 और curl 8.4.0

  • curl 8.4.0 release के साथ CVE-2023-38545 security advisory और details सार्वजनिक किए गए
  • इस issue को curl में लंबे समय बाद आया सबसे गंभीर security issue माना गया, और severity HIGH तय की गई
  • मुख्य flaw SOCKS5 proxy connection handling के दौरान खास conditions में होने वाला heap buffer overflow है

SOCKS5 और name resolution के तरीके

  • curl August 2002 से SOCKS5 support करता है
  • SOCKS5 एक proxy protocol है जो बीच के server के जरिए network communication setup करता है
    • इसे Tor के जरिए communication setup करने के लिए इस्तेमाल किया जा सकता है
    • संगठन या company के अंदर से internet access करते समय भी इसका इस्तेमाल हो सकता है
  • SOCKS5 में hostname resolution के दो तरीके हैं
    • client hostname को locally resolve करने के बाद resolved address proxy को देता है
    • client पूरा hostname proxy को भेजता है और proxy remotely resolve करता है

2020 का बदलाव जिससे vulnerability आई

  • 2020 की शुरुआत में SOCKS5 proxy से connect करने वाला function blocking call से non-blocking state machine में बदला गया
  • यह बदलाव 14 February 2020 को master में गया, और curl 7.69.0 में शामिल हुआ
  • curl 7.69.0 इस improvement वाली पहली release थी और नतीजतन CVE-2023-38545 के लिए vulnerable पहली release भी बनी
  • बदलाव का उद्देश्य यह था कि जब कई parallel transfers सभी SOCKS5 से गुजरें, तो अधिक दिखाई देने वाला improvement मिले

state machine में टूटा resolution mode

  • state machine function connection स्थापित होने तक हर बार अधिक network data आने पर बार-बार call होता है
  • function के top पर socks5_resolve_local local variable यह बताता है कि curl hostname को खुद resolve करेगा या name proxy को भेजेगा
  • यह variable हर बार state machine चलने पर function call की शुरुआत में proxy mode के आधार पर फिर से set होता है
  • INIT state की condition ने समस्या बनाई
    • SOCKS5 का hostname field अधिकतम 255 bytes तक ही allow करता है
    • अगर hostname 255 bytes से बड़ा हो, तो SOCKS5 proxy उसे resolve नहीं कर सकता
    • पुराने curl code में remote resolution mode में बहुत लंबा hostname मिलने पर socks5_resolve_local को TRUE कर के local resolution mode में switch किया जाता था
  • अगर user ने remote resolution request किया था, तो curl को mode बदलने के बजाय fail होना चाहिए था, लेकिन बहुत पहले जोड़ा गया switch behavior वैसे ही बना रहा

heap overflow होने का flow

  • अगर SOCKS5 server पर्याप्त तेज़ न हो और state machine को आगे बढ़ने के लिए network data न मिले, तो function return हो जाता है
  • बाद में data मिलने पर वही state machine function फिर call होता है
  • re-call के समय socks5_resolve_local function के top पर proxy mode के आधार पर फिर set होता है
    • previous call में बहुत लंबे hostname की वजह से TRUE हुआ value कायम नहीं रहता
    • value फिर से proxy को name remotely resolve करना चाहिए वाली state में आ जाता है
  • curl proxy को भेजने के लिए protocol frame memory buffer में बनाता है और destination information copy करता है
  • गलत state value की वजह से अगर बहुत लंबे hostname को जस का तस भेजने की कोशिश होती है, तो allocated target buffer से आगे जाकर पास की heap memory तक overwrite हो सकती है

buffer size और hostname constraints

  • curl proxy को भेजने के लिए protocol frame बनाते समय normal download buffer को reuse करता है
  • download buffer size की conditions ये हैं
    • default value 16KB है
    • curl tool buffer size को 100KB पर set करता है
    • application request के अनुसार अलग size इस्तेमाल हो सकता है
    • allowed minimum size 1024 bytes है
  • अगर buffer size 65541 bytes से छोटा हो, तो यह overflow संभव है
  • buffer जितना छोटा होगा, संभावित overflow size उतना बड़ा होगा
  • URL के hostname पर practical size limit नहीं है, लेकिन libcurl URL parser 65535 bytes से बड़े names को reject करता है
  • DNS अधिकतम 253 bytes तक के hostnames ही allow करता है
  • 253 bytes से बड़े legal names दुर्लभ हैं, और 1024 bytes से बड़े real names practically देखने को नहीं मिलते, इसलिए attack के लिए जानबूझकर बेहद लंबा hostname चाहिए
  • URL के hostname field में केवल कुछ octets ही आ सकते हैं, और invalid byte values को URL parser reject कर देता है
  • अगर libcurl IDN library इस्तेमाल करने के लिए build किया गया हो, तो वह library भी invalid hostnames को reject कर सकती है

attack सफल होने की शर्तें

  • attacker को ऐसा HTTPS server control करना होगा जिस तक libcurl इस्तेमाल करने वाला client SOCKS5 proxy के जरिए proxy-resolver-mode में access करता है
  • attack server HTTP 30x response के रूप में crafted redirect लौटा सकता है
  • redirect के Location: header में इस form का बहुत लंबा hostname हो सकता है
  • अगर libcurl client में automatic redirect following on हो, और SOCKS5 proxy इस local variable issue को trigger करने के लिए “काफी slow” हो, तो crafted hostname बहुत छोटे buffer में copy हो जाता है
  • ये conditions पूरी होने पर पास की heap memory तक write होता है और heap buffer overflow बनता है

fix और bug bounty

  • curl 8.4.0 से बहुत लंबे hostname की वजह से remote resolution से local resolution में mode बदलने के बजाय error return होता है
  • इसी scenario के लिए dedicated test case भी जोड़ा गया
  • इस issue को Jay Satiro ने report, analyze और patch किया
  • इस vulnerability के लिए अब तक curl में दी गई सबसे बड़ी bug bounty दी गई
    • reporter को 4,660 dollars
    • IBB policy के तहत curl project को 1,165 dollars

C और memory-safe languages

  • अगर curl C के बजाय memory-safe language में लिखा गया होता, तो इस category के flaws नहीं होते
  • लेकिन curl को किसी दूसरी language में port करना फिलहाल agenda में नहीं है
  • practical approach दो बातों तक सीमित होती है
    • memory-safe languages में लिखी dependencies को अधिक allow, use और support करना
    • hyper adoption की तरह curl के हिस्सों को gradually replace करना
  • ऐसी development अभी बहुत धीमी चल रही है, और संबंधित difficulties भी साफ दिखती हैं
  • curl निकट भविष्य में भी C में लिखा हुआ ही रहेगा
  • curl 8.4.0 में report किए गए latest 2 CVEs को मिलाकर, अब तक curl में पाई गई security vulnerabilities में से 41% शायद memory-safe language इस्तेमाल करने पर नहीं होतीं
  • हालांकि C-related issues के शुरुआती लगभग 80% जब introduce हुए थे, उस समय Rust इस उद्देश्य के लिए practical choice नहीं था

1315 दिन बाद मिली flaw

  • यह flaw code में 1315 दिन तक रहा
  • बेहतर test set होता तो इसे पकड़ा जा सकता था
  • curl कई static code analyzers बार-बार चलाता है, लेकिन इस function की समस्या किसी analyzer ने नहीं पकड़ी
  • 20 billion से ज्यादा installations में गए code में heap overflow ship करने का अनुभव recommend करने लायक नहीं था
  • public disclosure से पहले की report और handling process HackerOne report में देखी जा सकती है

1 टिप्पणियां

 
GN⁺ 2023-10-12
Hacker News की राय
  • यह अब भी हैरान करने वाला है कि इतने सारे डिवाइस असल में एक ऐसी library पर निर्भर हैं जिसका ज़्यादातर हिस्सा एक ही व्यक्ति ने लिखा है। बोझ बहुत बड़ा रहा होगा, और नीचे के वाक्य से भी यह साफ दिखता है
    “अब code पढ़ता हूँ तो bug न दिखना असंभव है। यह स्वीकार करना सचमुच तकलीफदेह है कि मैंने यह गलती नहीं पकड़ी, और यह खामी 1315 दिनों तक code में बिना पकड़े रही। माफ़ी चाहता हूँ। मैं आखिर इंसान ही हूँ।”
    अगर Daniel यह देख रहे हों, तो मुझे लगता है कि इतनी मेहनत के लिए धन्यवाद, और माफ़ी मांगने की बिल्कुल ज़रूरत नहीं है। आखिर source सभी के पढ़ने और review करने के लिए खुला था

    • मुझे पहले का OpenSSL याद आता है, जिसे कुछ समय तक Steve नाम के दो लोग develop और maintain कर रहे थे। अब लगता है कि टीम फिर भी लगभग 7 लोगों तक बढ़ गई है
      https://www.buzzfeed.com/chrisstokelwalker/the-internet-is-b...
    • बिल्कुल सही बात है। HackerOne report के इस वाक्य में भी यह साफ दिखता है
      “यह report पूरी तरह सही लगती है, और दिल से तकलीफ देती है।”
      blog में लिखा “2 अरब से ज़्यादा installations में जाने वाले code में heap overflow deploy करने का अनुभव मैं recommend नहीं करूँगा” भी ऐसा ही है; इतनी बड़ी ज़िम्मेदारी को इतने कम reward के साथ उठाना कठोर है
    • मुझे लगता है कि quote का पहला वाक्य इंसान की learning और attention कैसे काम करती है, उसका एक हिस्सा अच्छी तरह समेटता है
      निजी तौर पर मैं अक्सर सोचता रहा हूँ कि चाहे मैं कितना भी focus करने की कोशिश करूँ, कितनी चीज़ें छूट जाती हैं। code review जैसी गतिविधियाँ इस पहलू—यानी attention training या समग्र और contextual awareness बढ़ाने—के लिए अच्छा तरीका लगती हैं। उदाहरण के लिए, एक जगह जहाँ मैं कई सालों से अक्सर गुजरता था, वहाँ किसी ने अच्छी तरह सँवारी हुई फूलों की क्यारी बनाई थी; पहली बार ध्यान में आने के बाद करीब 1 साल तक मैं रुककर उसे देखा करता था, लेकिन कुछ महीने पहले पहली बार पता चला कि उसके ठीक कुछ फीट बगल में जोड़ी जैसी एक और क्यारी भी है। बहुत संभावना है कि वह क्यारी शुरू से ही रही हो, लेकिन उसके अस्तित्व का ही पता नहीं था, इसलिए पक्का नहीं कह सकता
      इसे पूरी मानवता के ज्ञान तक फैलाकर सोचें, तो कभी-कभी लगता है कि कोई एक ही व्यक्ति किसी चीज़ को नोटिस करता है, और वह observation व्यवहार बदलते हुए हम सभी तक फैलना शुरू हो जाता है। कभी-कभी कई कोशिशें और लंबा समय चाहिए होता है। यह भी सोचता हूँ कि ऐसे कितने low-hanging fruit होंगे जिन्हें अभी तक किसी ने नोटिस नहीं किया, और जो लोग पहले से ध्यान देते आए हैं उनके बनाए सरल और बुनियादी best practices को integrate करने भर से भी सभी का न्यूनतम स्तर ऊपर उठ सकता है
      Julia Evans का https://jvns.ca/blog/2023/10/06/new-talk--making-hard-things... और Dan Luu का https://danluu.com/p95-skill/ भी इसी से जुड़ते हैं। निष्कर्ष में, Stenberg और curl, और internet infrastructure के वे कई हिस्से बनाने वाले लोगों के प्रति बहुत आभार महसूस होता है जिन्हें हम रोज़ स्वाभाविक मानकर इस्तेमाल करते हैं
    • https://xkcd.com/2347/ प्रकाशित होने से पहले भी कई सालों तक सच था, और प्रकाशित होने के बाद भी कई सालों तक सच बना हुआ है
      कभी-कभी “अगर टूटा नहीं है तो ठीक मत करो” वाला सिद्धांत “टूटने तक support मत करो” के रूप में समझ लिया जाता है, जिससे काफी अप्रिय surprises मिलते हैं
    • single-developer projects में contributor experience हमेशा शानदार रहा है, जबकि company या vendor projects में अक्सर काफी खराब रहा। project को बेहतर बनाने के लिए साथ काम करने की कोशिशों में passion साफ दिखता है
      sustainability की समस्या हो सकती है, लेकिन ऐसे projects आगे भी बने रहेंगे, और Daniel की तरह सिर्फ अपने लिए नहीं बल्कि community के लिए काम करने वाले सभी लोगों को मेरा सम्मान
  • memory safety और memory-safe languages पर निष्कर्ष बहुत उचित है। सार यह है
    अगर curl C की जगह किसी memory-safe language में लिखा गया होता, तो इस तरह की defects की पूरी category असंभव होती
    उस दिशा में जो तरीका व्यवहार्य और उचित लगता है, वह है memory-safe languages में लिखी dependencies को अधिक allow, use और support करना, और hyper अपनाने की तरह curl के हिस्सों को धीरे-धीरे टुकड़ों में replace करना
    लेकिन ऐसा development फिलहाल लगभग glacier जैसी धीमी गति से चल रहा है, और इससे जुड़ी कठिनाइयों को दर्दनाक रूप से साफ दिखाता है। निकट भविष्य में curl C में ही रहेगा। जिसे यह पसंद नहीं, वह खुद sleeves चढ़ाकर काम कर सकता है
    curl 8.4.0 में report किए गए नवीनतम दो CVE तक शामिल करें, तो अब तक curl में मिले security vulnerabilities के cumulative total में से 41% शायद memory-safe language इस्तेमाल करने पर पैदा ही नहीं होते। लेकिन Rust उस समय इस उपयोग के लिए व्यावहारिक विकल्प नहीं था, जब C से जुड़ी समस्याओं के शुरुआती करीब 80% introduce हो रहे थे
    कई static code analyzers बार-बार चलाए गए, लेकिन इस function में कोई समस्या नहीं पकड़ पाए

    • लगता है पिछले हफ्ते नया fuzzer और tests भी जोड़े गए। इस बिंदु पर, safety-critical क्षेत्र से बाहर के C projects के लिए भी ऐसी pipeline अपनाना अच्छा रहेगा
    • curl के कुछ हिस्सों को Rust से replace करना संभव नहीं होगा। ज़्यादातर environments source से build करना चाहते हैं, और toolchain में नया compiler नहीं लाना चाहते। ऊपर से Rust संभावित C target platforms के बहुत छोटे हिस्से को ही support करता है
  • बेहतरीन analysis post है। हालांकि CVE तक पढ़ने के बाद भी यह अभी स्पष्ट नहीं है कि किन परिस्थितियों में असर पड़ेगा। मेरी समझ के मुताबिक, नीचे दी शर्तें पूरी होने पर असर पड़ता है
    SOCKS5 proxy इस्तेमाल हो, उस proxy से host name resolve कराया जा रहा हो, buffer size default 100KB से बदलकर 65541 bytes से कम कर दिया गया हो, और SOCKS5 proxy request को तुरंत process करने के लिए बहुत slow हो
    सुधार: buffer से जुड़ा विवरण सही नहीं है। libcurl download buffer को reuse करता है और default 16KB है, लेकिन कहा गया है कि curl खुद --limit-rate का इस्तेमाल न करने तक इसे manually 100KB पर set करता है। delay वाली शर्त भी गलत थी। CVE के मुताबिक, सामान्य server delay भी इस bug को trigger करने के लिए पर्याप्त “slow” होने की अच्छी संभावना है, और attacker को denial of service या SOCKS server control के ज़रिए असर डालने की जरूरत नहीं है
    इसलिए attack path बहुत narrow लगता है; सोच रहा हूं कि क्या मैं कुछ miss कर रहा हूं

    • आखिरी शर्त “SOCKS5 proxy request को तुरंत process करने के लिए बहुत slow हो” को समझने की कोशिश की, लेकिन request बिना किसी delay या redirect के तुरंत segmentation error देती है
      root@1aac5e228e16:/build/curl-7.74.0# curl -vvv -x socks5h://host.docker.internal:9050 $(python3 -c "print(('A'10000), end='')")
      Trying 192.168.65.254:9050...
      * SOCKS5: server resolving disabled for hostnames of length > 255 [actual len=10000]
      * SOCKS5 connect to AAAAA...
      * Send failure: Bad file descriptor
      * Failed to send SOCKS5 connect request.
      Segmentation fault
      https://gist.github.com/xen0bit/0dccb11605abbeb6021963e2b1a8...
    • सुधारे गए content के आधार पर, यह सही लगता है। यह मुख्य तौर पर ऐसे software से संबंधित होगा जो shared infrastructure पर चलता है, attacker द्वारा दिए गए URL पर request भेजता है, और SOCKS5 proxy इस्तेमाल करता है। उदाहरण के लिए webhook जैसी चीजें
    • मैंने docker-proxy नाम से shell scripts का एक bundle बनाया है, जो openconnect VPN चलाने वाले Docker container के जरिए SOCKS5 tunnel बनाता है। यह तब काम आता है जब कई customers के अलग-अलग VPN संभालने हों और हर VPN machine का सारा traffic अपनी तरफ भेजने की मांग करे
      https://github.com/carlosonunez/docker-proxy
      इसे इस तरह design किया गया है कि DNS resolution remote पर हो, इसलिए यह CVE यहां सीधे लागू होता है
    • Tor जैसे darknet browse करते समय यह तबाही बुलाने वाला combination लगता है
  • अब तक पढ़े गए CVE analysis posts में इसे सबसे अच्छा कहा जा सकता है। हमारे दौर के core software में से एक बनाने वाले व्यक्ति होने के बावजूद, पूरे लेख में उनका विनम्र रवैया भी तारीफ के काबिल है। सच में बहुत सम्माननीय

  • if(!socks5_resolve_local && hostname_len > 255) {
    socks5_resolve_local = TRUE;
    }
    यह सच में बहुत खराब idea है। censorship bypass tools से अपनी privacy बचाने वाले लोगों के लिए DNS के जरिए identity leak हो सकती है

    • “अगर user ने remote resolution मांगा है, तो curl को उसे मानना चाहिए या fail होना चाहिए; इस तरह mode बदलना साफ तौर पर गलत है। सामान्य परिस्थिति में भी सिर्फ switch कर देने से सही तरह काम करने की संभावना कम है।”
      लेखक भी यही सोचते हैं
  • https://hackerone.com/reports/2187833

  • कहा गया है कि “अगर curl C के बजाय memory-safe language में लिखा गया होता, तो इस तरह की flaws असंभव होतीं”, लेकिन बस इतना कहा जा सकता है कि शायद असंभव होतीं। हमें हमेशा नहीं पता होता कि language की virtual machine barrier से बाहर निकलने का तरीका है या नहीं। हालांकि लेखक ने RFC1123 में बताई गई DNS host name limit को स्पष्ट रूप से ignore किया, और यह limit Java libraries में भी hardcoded है
    https://www.rfc-editor.org/rfc/rfc1123

    • यह “host name length” section में covered है
      “URL के host name पर कोई practical size limit नहीं है, लेकिन libcurl का URL parser 65535 bytes से लंबे names को reject करता है। DNS अधिकतम 253 bytes वाले host names ही allow करता है। इसलिए 253 bytes से लंबे legal names दुर्लभ हैं। 1024 bytes से लंबे वास्तविक names के बारे में तो लगभग सुना ही नहीं गया।”
      आज DNS 99.9% मामलों में इस्तेमाल होता है, लेकिन यह host name को address में resolve करने वाला एकमात्र mechanism नहीं है
    • क्या आप इसे और specific बता सकते हैं? मुझे सिर्फ यह दिखा कि “host software को 63 characters तक के host names जरूर handle करने चाहिए, और 255 characters तक के host names handle करना अच्छा है”
      RFC host name size की upper limit कहां तय करता है, यह नहीं मिला
    • Memory-safe language का मतलब जरूरी नहीं कि virtual machine हो
      इसका मतलब यह भी हो सकता है कि compiler यह prove करने की कोशिश करता है कि memory को bounds के बाहर access नहीं किया जा रहा, clear ownership के बिना access नहीं किया जा रहा, और base object की lifetime के भीतर ही access किया जा रहा है। उदाहरण के लिए Rust ऐसा करता है
      बेशक compiler महत्वपूर्ण जगहों पर internal failure checks और guards भी जोड़ सकता है। Rust ऐसा नहीं करता, लेकिन उन systems में यह अच्छा हो सकता है जहां register के अंदर bit flip जैसी चीजों की चिंता करनी पड़े। जैसे X-ray scanners जैसे high-radiation environments, जहां ECC memory से पकड़े नहीं जाने वाले cases हो सकते हैं
    • RFC की wording के हिसाब से 255 bytes से लंबे host names को accept करना allowed है, लेकिन ऐसे names बनाना allowed नहीं है
  • exploit करने के लिए बेहद खास conditions चाहिए होने के बावजूद इसमें बढ़ा-चढ़ाकर पेश करने और drama की मात्रा काफी ज़्यादा है

    • curl ने CVE से जुड़ी समस्याओं का कई बार सामना किया है, इसलिए लगता है कि वे दिखाना चाहते हैं कि वे वास्तविक security issues को बहुत गंभीरता से लेते हैं। उदाहरण के लिए https://daniel.haxx.se/blog/2023/08/26/cve-2020-19909-is-eve... देखें
    • और यह अरबों devices पर install है। उस पैमाने पर deploy होने पर, मुझे लगता है कि इधर-उधर ऐसी बेहद खास conditions जल्दी बन सकती हैं
  • कल आए Windows 10 security update में नया curl version शामिल नहीं था। Windows में शामिल curl अभी भी 8.0.1 है

  • लंबा और दिलचस्प लेख है, लेकिन इसे इस तरह संक्षेप में कहा जा सकता है: “इसलिए system libraries को safe languages में लिखा जाना चाहिए या उनकी correctness prove होनी चाहिए”
    अगर हमारे समय के सबसे अच्छे, सबसे दयालु और पारदर्शी C programmers में से एक ऐसा लेख लिख रहा है, तो हमें ध्यान देना चाहिए

    • अगर वही programmer लिखता है कि “इस तरह का development फिलहाल लगभग glacier जैसी धीमी गति से आगे बढ़ रहा है और संबंधित कठिन समस्याओं को दर्दनाक रूप से साफ़ दिखाता है। curl निकट भविष्य में भी C में ही रहेगा”, तो मुझे हैरानी है कि हमें आखिर कौन-सा निष्कर्ष निकालना चाहिए