
CVE-2025-68621 का शैक्षिक PoC और विश्लेषण, जो Trilium Notes सिंक लॉगिन पर टाइमिंग अटैक है। नेटवर्क टाइमिंग साइड-चैनल के माध्यम से HMAC हैश रिकवरी को प्रदर्शित करता है, जिसमें मूल कारण, सुधार और शमन विवरण शामिल हैं।
/api/login/sync पर Trilium Notes टाइमिंग अटैकगंभीरता: उच्च (CVSS 7.4) प्रभावित सॉफ्टवेयर: TriliumNext/Trilium < 0.101.0 भेद्यता प्रकार: CWE-208 – अवलोकनीय टाइमिंग विसंगति (Observable Timing Discrepancy) समाधान: Trilium 0.101.0 (PR #8129) प्रकाशित: 2026-02-06 | आरक्षित: 2025-12-19
Trilium Notes एक ओपन-सोर्स, क्रॉस-प्लेटफॉर्म, पदानुक्रमिक नोट लेने वाला एप्लिकेशन है जो बड़े व्यक्तिगत ज्ञानकोष बनाने के लिए डिज़ाइन किया गया है। यह समर्थन करता है:
सिंक सुविधा एक Trilium क्लाइंट को Trilium सर्वर से प्रमाणित करने की अनुमति देती है ताकि नोट डिवाइसों में सिंक रहें। यह सिंक एंडपॉइंट CVE-2025-68621 का प्रवेश बिंदु है।
टाइमिंग अटैक एक साइड-चैनल अटैक है जिसमें हमलावर विभिन्न इनपुट को संसाधित करने में सिस्टम द्वारा लिए गए समय को मापकर गुप्त जानकारी प्राप्त करता है।
क्लासिक उदाहरण स्ट्रिंग तुलना है:
"correct_password" !== "aorrect_password" → स्थिति 0 पर विफल → तेज़
"correct_password" !== "cXrrect_password" → स्थिति 1 पर विफल → थोड़ा धीमा
"correct_password" !== "correct_password" → पूरी तरह मेल → सबसे धीमा
अधिकांश प्रोग्रामिंग भाषाएँ वर्ण-दर-वर्ण स्ट्रिंग तुलना करती हैं और जैसे ही कोई अंतर मिलता है, रुक जाती हैं (जल्दी निकास - early exit)। इसका मतलब है:
समाधान स्थिर-समय तुलना (constant-time comparison) फ़ंक्शन का उपयोग करना है जो अंतर कहीं भी हो, प्रत्येक बाइट का हमेशा निरीक्षण करता है।
भेद्यता Trilium के प्रमाणीकरण तर्क की मैन्युअल कोड समीक्षा के माध्यम से खोजी गई। शोधकर्ता ने apps/server/src/routes/api/login.ts में सिंक लॉगिन प्रवाह की जांच की और loginSync() फ़ंक्शन (लगभग पंक्ति 111) में निम्नलिखित पैटर्न देखा:
const documentSecret = options.getOption("documentSecret");
const expectedHash = utils.hmac(documentSecret, timestampStr);
const givenHash = req.body.hash;
if (expectedHash !== givenHash) { // ← कमजोर पंक्ति
return [400, { message: "Sync login credentials are incorrect..." }];
}
लाल झंडा HMAC हैश की तुलना के लिए JavaScript के बिल्ट-इन !== ऑपरेटर का उपयोग है। !== ऑपरेटर स्थिर-समय नहीं है — यह जैसे ही कोई भिन्न वर्ण पाता है, बाहर निकल जाता है। चूँकि तुलना सादे स्ट्रिंग्स पर की जाती है (क्रिप्टोग्राफ़िक रूप से सुरक्षित तुलना फ़ंक्शन का उपयोग नहीं करके), प्रतिक्रिया समय में यह जानकारी लीक होती है कि हमलावर के अनुमान के कितने अग्रणी बाइट्स सही हैं।
शोधकर्ता ने तब पूछा:
"क्या इस छोटे से टाइमिंग अंतर को नेटवर्क पर इतना बढ़ाया जा सकता है कि पूरे 44-वर्ण वाले Base64-एन्कोडेड HMAC हैश को पुनर्प्राप्त किया जा सके?"
उत्तर हाँ निकला — पर्याप्त दोहराए गए माप और कुछ सांख्यिकीय विश्लेषण के साथ, संकेत शोर से ऊपर उठ जाता है।
जब कोई Trilium क्लाइंट सिंक करना चाहता है, तो वह इस तरह के JSON बॉडी के साथ POST /api/login/sync को कॉल करता है:
{
"timestamp": "2025-12-19T10:00:00.000Z",
"syncVersion": 34,
"hash": "<documentSecret + टाइमस्टैम्प का HMAC-SHA256, Base64-एन्कोडेड>"
}
बाइट-दर-बाइट पुनर्प्राप्ति इस प्रकार काम करती है:
स्थिति = 0 से 43 तक:
वर्ण सेट (A-Z, a-z, 0-9, +, /, =) में प्रत्येक उम्मीदवार वर्ण c के लिए:
hash = ज्ञात_उपसर्ग + c + पैडिंग के साथ नमूने भेजें
औसत प्रतिक्रिया समय रिकॉर्ड करें
सर्वश्रेष्ठ वर्ण = उच्चतम औसत समय वाला उम्मीदवार
सर्वश्रेष्ठ वर्ण को ज्ञात_उपसर्ग में जोड़ें
44 पुनरावृत्तियों (प्रति Base64 वर्ण) के बाद, पूरा 44-वर्ण HMAC हैश पुनर्प्राप्त हो जाता है।
व्यावहारिक आवश्यकताएँ:
time.perf_counter() Python में नैनोसेकंड रिज़ॉल्यूशन देता है)पूरी तरह से एनोटेटेड Python PoC के लिए poc.py देखें।
PoC क्या करता है इसका त्वरित सारांश:
A–Z, a–z, 0–9, +, /, =) में प्रत्येक वर्ण आज़माता है।/api/login/sync पर 50 HTTP POST अनुरोध भेजता है और माध्यिका प्रतिक्रिया समय मापता है।अस्वीकरण: यह PoC केवल शैक्षिक उद्देश्यों और जिम्मेदार सुरक्षा अनुसंधान के लिए प्रदान किया गया है। उन सिस्टमों के विरुद्ध उपयोग न करें जिनके मालिक नहीं हैं या जिनके परीक्षण के लिए आपके पास स्पष्ट लिखित अनुमति नहीं है।
JavaScript के !== (और ===) ऑपरेटर लेक्सिकोग्राफ़िक, जल्दी-निकास तुलना करते हैं। apps/server/src/routes/api/login.ts में कमजोर पंक्ति:
if (expectedHash !== givenHash) {
return [400, { message: "Sync login credentials are incorrect..." }];
}
जल्दी-निकास व्यवहार प्रति मिलने वाले बाइट में मापने योग्य टाइमिंग अंतर बनाता है:
| अनुमान बनाम अपेक्षित | तुलना किए गए बाइट | समय |
|---|---|---|
| गलत बाइट 0 | 1 | ~T |
| सही बाइट 0, गलत बाइट 1 | 2 | ~T + δ |
| सही बाइट 0–1, गलत बाइट 2 | 3 | ~T + 2δ |
| … | … | … |
| सभी 44 बाइट सही | 44 | ~T + 43δ |
प्रत्येक अतिरिक्त मिलने वाला बाइट थोड़ा अतिरिक्त CPU समय δ खर्च करता है। हज़ारों नमूनों पर, "सही बाइट N" अनुमान के लिए औसत प्रतिक्रिया समय "गलत बाइट N" अनुमान की तुलना में मापने योग्य रूप से अधिक लंबा होता है, जो पूरे HMAC हैश को वर्ण-दर-वर्ण पुनर्प्राप्त करने के लिए पर्याप्त जानकारी लीक करता है।
| मीट्रिक | मान | कारण |
|---|---|---|
| आधार स्कोर | 7.4 उच्च | |
| हमला वेक्टर | नेटवर्क (N) | इंटरनेट पर शोषणीय |
| हमला जटिलता | उच्च (H) | कई अनुरोध + स्थिर टाइमिंग आवश्यक |
| आवश्यक विशेषाधिकार | कोई नहीं (N) | खाते की आवश्यकता नहीं |
| उपयोगकर्ता इंटरैक्शन | कोई नहीं (N) | पीड़ित को कुछ करने की आवश्यकता नहीं |
| दायरा | अपरिवर्तित (U) | केवल Trilium सर्वर प्रभावित |
| गोपनीयता | उच्च (H) | पूर्ण नोट आधार पढ़ने योग्य |
| अखंडता | उच्च (H) | हमलावर नोट लिख/संशोधित/हटा सकता है |
| उपलब्धता | कोई नहीं (N) | सेवा-से-इनकार घटक नहीं |
वेक्टर स्ट्रिंग: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N
एक सफल शोषण हमलावर को देता है:
यह उन उपयोगकर्ताओं के लिए विशेष रूप से गंभीर है जो अपने Trilium ज्ञानकोष में संवेदनशील व्यक्तिगत डेटा (पासवर्ड, निजी दस्तावेज़, जर्नल प्रविष्टियाँ) संग्रहीत करते हैं।
समाधान गैर-स्थिर-समय !== तुलना को Node.js के बिल्ट-इन crypto.timingSafeEqual() से बदल देता है:
पहले (कमजोर):
if (expectedHash !== givenHash) {
return [400, { message: "Sync login credentials are incorrect..." }];
}
बाद में (सुरक्षित):
import * as crypto from "crypto";
const expectedBuffer = Buffer.from(expectedHash);
const givenBuffer = Buffer.from(givenHash ?? "");
if (expectedBuffer.length !== givenBuffer.length ||
!crypto.timingSafeEqual(expectedBuffer, givenBuffer)) {
return [400, { message: "Sync login credentials are incorrect..." }];
}
crypto.timingSafeEqual() हमेशा प्रत्येक बाइट की तुलना करता है, इसलिए निष्पादन समय इस पर निर्भर नहीं करता कि कितने बाइट मेल खाते हैं। टाइमिंग सिग्नल गायब हो जाता है।
साइड-बाय-साइड कोड उदाहरणों के लिए vulnerable.ts और fix.ts देखें।
यदि आप एक स्व-होस्टेड Trilium सर्वर चला रहे हैं, तो तुरंत संस्करण 0.101.0 या बाद के में अपग्रेड करें।
# Docker उदाहरण
docker pull zadam/trilium:0.101.0
रहस्यों की तुलना के लिए कभी भी === / !== का उपयोग न करें। JavaScript के समानता ऑपरेटर स्थिर-समय नहीं हैं। === / !== का उपयोग करके HMAC, टोकन या पासवर्ड की कोई भी तुलना एक संभावित टाइमिंग ओरेकल है।
Node.js में हमेशा crypto.timingSafeEqual() का उपयोग करें (या अपनी भाषा/रनटाइम में इसके समकक्ष) जब क्रिप्टोग्राफ़िक मानों की तुलना करें। यह इस कार्य के लिए मानक, उद्देश्य-निर्मित API है।
नेटवर्क पर टाइमिंग अटैक वास्तविक हैं। हालाँकि नैनोसेकंड अंतर इंटरनेट पर पता लगाने योग्य नहीं लगते, सांख्यिकीय तकनीक और पर्याप्त नमूने शोर माप से स्पष्ट संकेत निकाल सकते हैं — विशेष रूप से कम-जिटर वातावरण में।
अकेले दर-सीमा पर्याप्त शमन नहीं है। प्रति IP दर-सीमा के बावजूद, रोटेटिंग प्रॉक्सी या बॉटनेट तक पहुँच रखने वाला हमलावर टाइमिंग अंतर का शोषण करने के लिए पर्याप्त नमूने एकत्र कर सकता है।
HMAC सत्यापन उसी देखभाल का हकदार है जो पासवर्ड तुलना। HMAC हैश रहस्य हैं। किसी भी गुप्त मान की तुलना को इस प्रकार व्यवहार करें जैसे कि टाइमिंग साइड चैनल का शोषण किया जा सकता है।
क्रिप्टोग्राफ़िक पैटर्न के लिए कोड समीक्षा आवश्यक है। यह भेद्यता मैन्युअल समीक्षा के माध्यम से पाई गई — कोड की एक पंक्ति जो हानिरहित लग रही थी लेकिन गंभीर सुरक्षा निहितार्थ थे। समर्पित क्रिप्टो/सुरक्षा ऑडिट इन मुद्दों को जल्दी पकड़ने में मदद करते हैं।
| तिथि | घटना |
|---|---|
| 2025-12-19 | GitHub Security द्वारा CVE-2025-68621 आरक्षित |
| 2025-12-21 | फिक्स PR #8129 खोला गया |
| 2025-12-25 | PR मर्ज हुआ; Trilium 0.101.0 जारी किया गया |
| 2026-02-06 | CVE सार्वजनिक रूप से प्रकाशित |
| 2026-02-09 | CISA ADP संवर्धन जोड़ा गया |
| संसाधन | लिंक |
|---|---|
| GitHub सुरक्षा सलाहकार | GHSA-hxf6-58cx-qq3x |
| फिक्स पुल रिक्वेस्ट | TriliumNext/Trilium#8129 |
| CVE रिकॉर्ड (CVEProject) | CVE-2025-68621.json |
| CWE-208 | अवलोकनीय टाइमिंग विसंगति |
| Trilium Notes भंडार | TriliumNext/Trilium |
यह भंडार जिम्मेदार प्रकटीकरण सिद्धांतों के तहत शैक्षिक और अनुसंधान उद्देश्यों के लिए बनाए रखा गया है।