flawopen.com/Incidents/equifax-struts-ognl-rce-july-2017
Equifax: करीब 15 करोड़ लोगों का डेटा प्रभावित
CVE-2017-5638 ने Equifax के बिना पैच वाले Struts पोर्टल में Content-Type हेडर के ज़रिए OGNL injection संभव बनाया। हमला लगभग 76 दिन चला और करीब 15 करोड़ लोगों का डेटा प्रभावित हुआ।[1], [4]
कल्पना करें कि डाक-प्रणाली अस्वीकृत शिपिंग लेबल को त्रुटि-संदेश में जोड़ देती है। यदि संदेश लेबल को चलने वाले निर्देश-टेम्पलेट की तरह समझे, तो भेजने वाला केवल गलत पते की सूचना देने के बजाय प्रणाली से निर्देश चलवा सकता है। Struts का पैच पहले से उपलब्ध था, लेकिन Equifax की सूचना प्रशासकों की पुरानी सूची पर भेजी गई और नेटवर्क स्कैन पोर्टल की कमज़ोरी का पता नहीं लगा पाया।[1], [4]
इस पेज के मुख्य शब्द
OGNL- Object-Graph Navigation Language, वह एक्सप्रेशन भाषा जिससे Struts Java ऑब्जेक्ट की प्रॉपर्टी पढ़ता और बदलता है। हमलावर के टेक्स्ट को OGNL की तरह चलाना, हमलावर का कोड चलाने जैसा है।[1], [6]
Jakarta मल्टीपार्ट पार्सर- Struts का वह घटक जो फ़ाइल अपलोड संभालता है। ग़लत Content-Type अस्वीकार करते समय वह एक त्रुटि संदेश बनाता था, जिसे बाद में चलाया जाता था।[1], [3], [2]
एक्सप्रेशन इंजेक्शन (CWE-917)- अविश्वसनीय इनपुट ऐसे एक्सप्रेशन के भीतर पहुँच जाता है जिसे कोई इंटरप्रेटर चलाता है, और डेटा निर्देश बन जाता है।[6]
एसेट इन्वेंटरी- किस सिस्टम पर कौन-सा सॉफ़्टवेयर और कौन-सा संस्करण चल रहा है, इसका रिकॉर्ड। इसके बिना पैच की सूचना को उन मशीनों से नहीं जोड़ा जा सकता जिन्हें उसकी ज़रूरत है।[4]
फ्रेमवर्क मैपिंग
- इस गाइड में बताई गई कमजोरी के लिए CWE संदर्भ: CWE-20 CWE-917
- CISA KEV — जोड़ा गया 2021-11-03 — CVE-2017-5638
घटना का समयक्रम (Timeline)
Apache सुरक्षा बुलेटिन S2-045 और सुधरे हुए Struts संस्करण 2.3.32 व 2.5.10.1 जारी करता है।[1]
Equifax ने बाद में GAO को बताया कि 13 मई को एक अलग घुसपैठ शुरू हुई और हमलावरों ने तब व्यक्तिगत डेटा निकालना शुरू किया; इससे पहले अनधिकृत पहुँच हुई थी, लेकिन उस समय डेटा नहीं लिया गया था।[4]
ट्रैफ़िक जाँचने वाले उपकरण पर एक्सपायर हो चुका सर्टिफ़िकेट नवीनीकृत करने के बाद Equifax को संदिग्ध ट्रैफ़िक दिखता है।[4]
Equifax सार्वजनिक रूप से सेंधमारी की घोषणा करता है। GAO ने बाद में बताया कि अमेरिका में कम-से-कम 14.55 करोड़ और देश के बाहर लगभग 10 लाख लोगों का डेटा प्रभावित हुआ।[4]
हमले का चरण-दर-चरण प्रवाह
गढ़ा हुआ Content-Type हेडर
हमलावर एक अपलोड अनुरोध भेजता है जिसके Content-Type हेडर में मीडिया टाइप की जगह OGNL एक्सप्रेशन होता है।[1]
धीमा, चुपचाप डेटा बाहर जाना
हमलावरों ने डेटा भंडार में मिले क्रेडेंशियल से पोर्टल के तीन संबंधित डेटाबेस से आगे 48 अन्य असंबद्ध डेटाबेस तक पहुँच बनाई। GAO के अनुसार उन्होंने लगभग 9,000 क्वेरी चलाईं और हमला करीब 76 दिन चला; एक्सपायर प्रमाणपत्र के कारण एन्क्रिप्टेड ट्रैफ़िक की जाँच नहीं हो सकी।[4]
सोर्स कोड: कमज़ोर बनाम सुरक्षित कार्यान्वयन
यह उदाहरण के लिए Java कोड है, Struts का सोर्स कोड नहीं; 2.3.32 और 2.5.10.1 में असली सुधार ने मल्टीपार्ट त्रुटि बनाने का तरीक़ा बदला था। मज़बूत संस्करण एक तय संदेश कुंजी इस्तेमाल करता है और हेडर को केवल स्थितीय तर्क के रूप में देता है, इसलिए वह टेक्स्ट की तरह फ़ॉर्मेट होता है और कभी एक्सप्रेशन का हिस्सा नहीं बनता। यह मीडिया टाइप जैसा न दिखने वाले किसी भी मान को प्लेसहोल्डर से बदल देता है, ताकि भविष्य में संदेश बदलने पर भी हेडर किसी चलाई जाने वाली स्ट्रिंग में न लौट सके।[3], [2], [6]
import com.opensymphony.xwork2.TextProvider;
import javax.servlet.http.HttpServletRequest;
public final class UploadErrors {
private final TextProvider text; // resolves messages and evaluates expressions in them
public UploadErrors(TextProvider text) {
this.text = text;
}
public String describe(HttpServletRequest request) {
String contentType = request.getHeader("Content-Type");
// कच्चा header evaluate होने वाले message का हिस्सा बन जाता है।
return text.getText("Invalid content type: " + contentType);
}
}import com.opensymphony.xwork2.TextProvider;
import java.util.Locale;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
public final class UploadErrors {
private static final Pattern MEDIA_TYPE = Pattern.compile(
"^[a-z]+/[a-z0-9.+-]+(;\\s*[a-z0-9-]+=[a-z0-9._-]+)*$");
private final TextProvider text;
public UploadErrors(TextProvider text) {
this.text = text;
}
public String describe(HttpServletRequest request) {
String contentType = request.getHeader("Content-Type");
boolean wellFormed = contentType != null && contentType.length() <= 256
&& MEDIA_TYPE.matcher(contentType.toLowerCase(Locale.ROOT)).matches();
// एक fixed message key रखें; header केवल positional argument के रूप में दिया जाए,
// और वह भी तभी जब उसका रूप media type जैसा हो।
return text.getText("upload.invalid.content.type",
new String[] { wellFormed ? contentType : "(malformed)" });
}
}इंजीनियरिंग और सिस्टम सुरक्षा चेकलिस्ट
- ✓हर तैनात एप्लिकेशन का SBOM रखें और S2-045 जैसी सलाह के कुछ ही घंटों में "हम Struts 2.3.x कहाँ चला रहे हैं?" का जवाब दे सकें।[4]
- ✓वल्नरेबिलिटी स्कैनर के लक्ष्यों को एसेट इन्वेंटरी से मिलाएँ; जो होस्ट कभी दायरे में था ही नहीं, उसका साफ़ स्कैन पैच का सबूत नहीं है।[4]
- ✓TLS जाँच और निगरानी उपकरणों के सर्टिफ़िकेट एक्सपायर होने से कम से कम 30 दिन पहले अलर्ट करें; यहाँ एक एक्सपायर सर्टिफ़िकेट ने महीनों तक डेटा बाहर जाना छिपाए रखा।[4]
- ✓कोड समीक्षा में हर वह कॉल अस्वीकार करें जो जोड़ा गया अविश्वसनीय टेक्स्ट किसी मैसेज रिज़ॉल्वर, टेम्पलेट इंजन या एक्सप्रेशन इवैल्युएटर को देती है; उसे तर्क के रूप में दें।[6]
- ✓डेटाबेस को इंटरनेट के सामने वाले एप्लिकेशन से अलग रखें, क्रेडेंशियल एप्लिकेशन फ़ाइलों से बाहर रखें और एप्लिकेशन खातों से असामान्य क्वेरी मात्रा पर अलर्ट करें।[4]
स्रोत
- Apache Struts — सुरक्षा बुलेटिन S2-045 (CVE-2017-5638)
- Apache Struts — multipart parser error-message fix (commit 3523064)
- Apache Struts — upstream multipart error-handling fix (commit 6b8272c)
- अमेरिकी GAO — डेटा संरक्षण: 2017 की सेंधमारी के बाद Equifax और संघीय एजेंसियों के क़दम (GAO-18-559)
- CVE-2017-5638 — CVE रिकॉर्ड
- MITRE CWE-917 — एक्सप्रेशन भाषा इंजेक्शन
- Log4Shell: जब लॉग फ़ाइल में लिखना रिमोट कोड निष्पादन बन गया
- कमांड इंजेक्शन — पूरी श्रेणी का संदर्भ