
Struts2の脆弱性S2-045, S2-055 および Jackson の脆弱性 CVE-2017-7525, CVE-2017-15095 の調査報告
केवल मुख्य बिंदुओं को संक्षेप में, पढ़ने में आसान सारांश लेख प्रकाशित किया गया है। पहले सामान्य जानकारी जानने वालों या समय की कमी वालों के लिए अनुशंसित।
2017年12月1日 को Struts2 का सुरक्षा अपडेट जारी किया गया था। जारी होने से पहले ही मेलिंग सूची में यह बात फैल गई थी कि Jackson (जावा में लोकप्रिय JSON लाइब्रेरी) की कमज़ोरी इससे संबंधित है, और कंपनी के आंतरिक सिस्टम और टूल्स में Jackson का उपयोग करने वाले लेखक को भी इस बात की चिंता थी कि वास्तव में इसका स्वरूप क्या है।
वास्तव में जारी की गई सामग्री के अनुसार, निम्नलिखित दो सुरक्षा समस्याओं को ठीक किया गया था। Jackson के घटक jackson-databind की कमज़ोरी केवल S2-055 को प्रभावित करती है।
REST प्लगइन में पहले से JSON-lib का उपयोग करने वाला हैंडलर और Jackson का उपयोग करने वाला हैंडलर शामिल था, जिसे उपयोगकर्ता चुन सकता था। S2-054 में डिफ़ॉल्ट हैंडलर को Jackson में स्विच किया गया, और S2-055 में Jackson के पुराने संस्करण को नवीनतम में अपडेट किया गया, यही इस सुधार का पूरा चित्र प्रतीत होता है।
तो आखिर CVE-2017-7525 कैसी कमज़ोरी है? लेखक स्वयं आमतौर पर जावा में JSON प्रसंस्करण के दौरान Jackson का उपयोग करता है, इसलिए 2, 3 दिसंबर के सप्ताहांत में इस समस्या की जांच की, यही इस लेख का विषय है।
नमूना कोड सत्यापन के लिए लेखक का वातावरण:
Adam Caudill के ब्लॉग पर CVE-2017-7525 की व्याख्या प्रकाशित की गई है।
लेखक अपने शब्दों में संक्षेप में बताए तो, jackson-databind JSON को Java ऑब्जेक्ट में मैप करने की सुविधा (ObjectMapper वर्ग) प्रदान करता है।
यहाँ ObjectMapper.enableDefaultTyping() को कॉल करके JSON में स्वतंत्र रूप से एम्बेड किए गए क्लास नाम से मैप करना संभव हो जाता है।
"इनपुट JSON में क्लास नाम निर्दिष्ट करना संभव" - यह सुनते ही कुछ लोगों को बुरा पूर्वाभास हुआ होगा, लेकिन वही बुरा पूर्वाभास CVE-2017-7525 के रूप में सच हुआ।
कमज़ोरी की व्याख्या में जाने से पहले, आइए समझें कि आखिर ऐसी सुविधा क्यों लागू की गई।
jackson-databind द्वारा deserialize के बुनियादी उपयोग के लिए कृपया निम्नलिखित नमूना कोड देखें। (इस लेख में Jackson के नमूना कोड में Groovy का उपयोग किया गया है। @Grab का उपयोग करके jackson-databind के संस्करण को आसानी से स्विच करना सुविधाजनक है।)
उपरोक्त नमूना कोड में सरलता से "animal" कुंजी सीधे Animal वर्ग में मैप हो सकती है। ठीक है, निम्नलिखित स्थितियों में क्या होगा?```java class Zoo { Animal animal; }
abstract class Animal { String name; protected Animal() { } }
class Dog extends Animal { double barkVolume; Dog() { } }
class Cat extends Animal { boolean likesCream; int lives; Cat() { } }
इस कॉन्फ़िगरेशन में, "animal" की की-वैल्यू Dog क्लास को इंगित करने वाली और Cat क्लास को इंगित करने वाली दो तरह की स्थितियाँ उत्पन्न होती हैं। इसलिए, यह तय करने के लिए अतिरिक्त जानकारी की आवश्यकता है कि किस क्लास से मैपिंग की जाए।
इसे हल करने के लिए, jackson-databind ने एक कस्टम प्रक्रिया को शामिल किया है जो JSON में मैप किए जाने वाले क्लास के नाम को एम्बेड करने की अनुमति देती है। उदाहरण के लिए, नीचे दिए गए तरीके से, "animal" की को एक ऐरे में बदल दिया जाता है और पहले एलिमेंट में क्लास का नाम निर्दिष्ट किया जाता है।```
{"animal":["Dog",{"name":"dog1","barkVolume":1.2}]}
इसके परिणामस्वरूप ObjectMapper.readValue() "animal" कुंजी की सामग्री को Dog वर्ग के रूप में पहचानता है और मैपिंग करता है।
बेशक, इस रूप में, यह निर्धारित नहीं किया जा सकता कि "animal" कुंजी की सामग्री मूल रूप से एक सरणी थी या इसमें jackson-databind का अद्वितीय वर्ग नाम जानकारी शामिल थी।
इसे स्विच करने का तरीका ObjectMapper.enableDefaultTyping() विधि है।
इसके अलावा वर्ग पर @JsonTypeInfo एनोटेशन को परिभाषित करने का भी एक तरीका है। विस्तृत जानकारी के लिए नीचे दिए गए Jackson दस्तावेज़ देखें।
वास्तव में ObjectMapper.enableDefaultTyping() विधि का उपयोग करने वाला एक नमूना कोड नीचे दिखाया गया है।
जैसा कि ऊपर देखा गया है, वर्ग नाम के बाद उसके गुणों को JSON में देकर, कुछ सीमाओं के बावजूद, किसी भी वर्ग को किसी भी गुण के साथ उत्पन्न करना संभव हो जाता है। इसका दुरुपयोग CVE-2017-7525 की कमजोरी में किया गया था, और इसका कारण संभवतः निम्नलिखित रिपोर्ट थी:
Jackson जैसे Java में सामान्यतः उपयोग किए जाने वाले serialize/deserialize लाइब्रेरीज़ के बारे में, वर्ग नामों आदि के संचालन से मनमाना कोड निष्पादन की ओर ले जाने वाले खतरे की रिपोर्ट की गई है, और वास्तव में कौन से वर्ग खतरनाक हैं, इसकी विशिष्ट वर्ग नामों की सूची दी गई है।
यह इसके जवाब में था या नहीं, यह स्पष्ट नहीं है, लेकिन तिथि के अनुसार, उपरोक्त रिपोर्ट के पहले कमिट के तुरंत बाद, jackson-databind में निम्नलिखित Issue खोला गया और समाधान शुरू हुआ।
वास्तव में इस कमजोरी का शोषण करने वाला JSON डेटा और Java कोड कैसा होगा? इस Issue में संबोधित jackson-databind 2.8.9 के परीक्षण कोड में एक संकेत है:
इस परीक्षण कोड के आधार पर, कार्यशील सत्यापन के लिए समायोजित एक नमूना कोड नीचे दिया गया है।
@Grab में 2.8.9 निर्दिष्ट करके चलाने पर your jackson version IS SAFE to CVE-2017-7525 प्रदर्शित होता है। यह इसलिए है क्योंकि 2.8.9 के संशोधन ने इंस्टेंटिएट होने वाले वर्ग नाम निर्दिष्टीकरण में ब्लैकलिस्ट जाँच जोड़ दी।
यहाँ @Grab में 2.8.8 निर्दिष्ट करके चलाने पर, निम्नानुसार आउटपुट होता है:```
your jackson version MAY NOT BE SAFE to CVE-2017-7525
com.fasterxml.jackson.databind.JsonMappingException: N/A
at [Source:
{
"id" : 124,
"obj" : [
"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl",
{
"transletBytecodes" : [ "AAIAZQ==" ],
"transletName" : "a.b",
"outputProperties" : { }
}
]
}
; line: 9, column: 28] (through reference chain: Bean1599["obj"]->com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl["outputProperties"])
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:277)
(...)
at org.codehaus.groovy.tools.GroovyStarter.main(GroovyStarter.java:128)
Caused by: java.lang.NullPointerException
at com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl$1.run(TemplatesImpl.java:401)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.defineTransletClasses(TemplatesImpl.java:399)
at com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.getTransletInstance(TemplatesImpl.java:451)
at com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.newTransformer(TemplatesImpl.java:486)
at com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.getOutputProperties(TemplatesImpl.java:507)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.fasterxml.jackson.databind.deser.impl.SetterlessProperty.deserializeAndSet(SetterlessProperty.java:116)
... 30 more
null
आउटपुट परिणाम में `at com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl$1.run(TemplatesImpl.java:401)` पंक्ति है।
इस नमूना कोड में NullPointerException फेंका गया है, लेकिन मेथड नाम से स्पष्ट है कि इसमें कुछ साइड इफेक्ट वाली प्रक्रिया हो रही है।
वास्तव में कोड निष्पादन को सफल बनाने वाला JSON बनाने के लिए और अधिक जांच आवश्यक प्रतीत होती है।
इस लेख में हम फिलहाल यहीं तक परिचय दे रहे हैं, लेकिन यदि अन्य साइटों पर आगे के शोध लेख प्रकाशित होते हैं, तो हम यहां भी जोड़ेंगे।
वैसे, महत्वपूर्ण black list कहाँ लागू की गई है? यह निम्नलिखित क्लास में है:
* https://github.com/FasterXML/jackson-databind/blob/jackson-databind-2.8.9/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerFactory.java#L51
दरअसल, 2.8.9 के समय इस black list में कमी थी। वह समस्या CVE-2017-15095 है।
### black list में सुधार: CVE-2017-15095 का समाधान
black list की कमी को सुधारने के लिए, पहले https://github.com/FasterXML/jackson-databind/issues/1680 में `s.add("com.sun.rowset.JdbcRowSetImpl");` जोड़ा गया।
इसके साथ 2.9.0 रिलीज़ होने के बाद, आगे https://github.com/FasterXML/jackson-databind/issues/1737 में निम्नलिखित black list जांच जोड़ी गई।```java
// [databind#1737]; JDK provided
s.add("java.util.logging.FileHandler");
s.add("java.rmi.server.UnicastRemoteObject");
// [databind#1737]; 3rd party
s.add("org.springframework.aop.support.AbstractBeanFactoryPointcutAdvisor");
s.add("org.springframework.beans.factory.config.PropertyPathFactoryBean");
s.add("com.mchange.v2.c3p0.JndiRefForwardingDataSource");
s.add("com.mchange.v2.c3p0.WrapperConnectionPoolDataSource");
इसके साथ ही 2.8.10 / 2.9.1 जारी कर दिए गए हैं, और CVE-2017-15095 के लिए समाधान पूरा हो गया है।
2.8.10 में black list व्यवहार की जाँच के लिए परीक्षण कोड:
इस परीक्षण कोड के आधार पर, संचालन सत्यापन के लिए समायोजित एक नमूना कोड नीचे दिखाया गया है।
जब समाधान पूर्ण माने जाने वाले 2.8.10 को @Grab के साथ निर्दिष्ट करके चलाया जाता है, तो your jackson version IS SAFE to CVE-2017-15095 प्रदर्शित होता है।
इसके बाद, black list सुधार से पहले के 2.8.9 को @Grab के साथ निर्दिष्ट करके चलाने पर, निम्न आउटपुट होता है।```
your jackson version MAY NOT BE SAFE to CVE-2017-15095
com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of java.util.logging.FileHandler, problem: \tmp\foobar.txt.lck
at [Source:
{
"v" : [
"java.util.logging.FileHandler",
"/tmp/foobar.txt"
]
}
; line: 5, column: 5] (through reference chain: PolyWrapper["v"])
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:277)
(...)
Caused by: java.nio.file.NoSuchFileException: \tmp\foobar.txt.lck
(...)
at java.util.logging.FileHandler.openFiles(FileHandler.java:459)
at java.util.logging.FileHandler.(FileHandler.java:292)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at com.fasterxml.jackson.databind.introspect.AnnotatedConstructor.call1(AnnotatedConstructor.java:129)
at com.fasterxml.jackson.databind.deser.std.StdValueInstantiator.createFromString(StdValueInstantiator.java:318)
... 31 more
null
対応前のバージョンでは `java.util.logging.FileHandler` क्लास का नाम ब्लैकलिस्ट जांच को पार कर जाता था, और इंस्टेंसिएशन के माध्यम से वास्तव में फ़ाइल खोलने का प्रयास किया जा रहा था।
संस्करण के बाद में, ब्लैकलिस्ट जांच इसे पकड़ लेती है और `JsonMappingException` अपवाद फेंका जाता है।
इसके अलावा, 2.8.10 संस्करण में ब्लैकलिस्ट इस प्रकार है। `[databind#1737]` टिप्पणी से शुरू होने वाला भाग CVE-2017-15095 के लिए अतिरिक्त ब्लैकलिस्ट है।
* https://github.com/FasterXML/jackson-databind/blob/jackson-databind-2.8.10/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerFactory.java#L52
### भेद्यता से प्रभावित होने की शर्तें, हमले की संभावना और एप्लिकेशन स्तर पर उपाय
उपरोक्त परिणामों को सारांशित करते हुए, jackson-databind भेद्यता से प्रभावित होने के लिए निम्नलिखित शर्तें आवश्यक हैं:
1. jackson-databind 2.8.9 / 2.9.0 या उससे पुराने संस्करण का उपयोग करना
2. अविश्वसनीय स्रोत से प्राप्त JSON पर निम्नलिखित में से कोई एक कार्रवाई करना:
* `ObjectMapper.enableDefaultTyping()` को कॉल करके deserialize करना।
* `ObjectMapper.enableDefaultTyping()` को कॉल नहीं करना, लेकिन क्लास घोषणा में `@JsonTypeInfo` एनोटेशन का उपयोग करके मैपिंग को सक्षम करना और deserialize करना।
* भले ही एप्लिकेशन कोड में उपयोग न किया गया हो, फ्रेमवर्क साइड पर `Accept` अनुरोध हेडर या URL के एक्सटेंशन के अनुसार स्वचालित रूप से deserialize हो सकता है।
3. क्लासपाथ में ऐसी क्लास ("Gadget") शामिल है जो Java serialize/deserialize भेद्यता में दुरुपयोग की जा सकती है।
4. मैपिंग लक्ष्य Java क्लास के सदस्य फ़ील्ड में Object प्रकार जैसे Gadget क्लास को स्वीकार करने वाले प्रकार का उपयोग किया गया है।
* यदि फ़ील्ड का प्रकार Gadget क्लास के साथ असंगत एप्लिकेशन-विशिष्ट Bean क्लास है, तो वास्तव में इंस्टेंस बनाने से पहले प्रकार जांच त्रुटि द्वारा इसे रोका जा सकता है (जब तक कि एप्लिकेशन-विशिष्ट Bean क्लास में स्वयं deserialize भेद्यता न हो)।
क्या वास्तव में प्रभावित होना है, यह `ObjectMapper` के उपयोग/कॉन्फ़िगरेशन स्थिति, `@JsonTypeInfo` एनोटेशन के संयोजन, और मैपिंग लक्ष्य क्लास के सदस्य फ़ील्ड आदि पर निर्भर करता है, जो एप्लिकेशन साइड कोड पर काफी हद तक निर्भर करता है।
इसके अलावा, यदि JSON में एक कुंजी नाम deserialize लक्ष्य Java क्लास में मौजूद नहीं है, तो Jackson इसे अनदेखा कर देता है।
इसलिए, हमले को सफल बनाने के लिए प्रत्येक एप्लिकेशन के JSON के अनुसार अनुकूलन की आवश्यकता होगी, और एक ही हमला कोड को कई एप्लिकेशनों में पुन: उपयोग करना अत्यंत कठिन माना जाता है।
इसके अलावा शर्त 4 के बारे में, सामान्य लेखन में, कोई शायद ही कभी Java क्लास के फ़ील्ड को Object प्रकार बनाता है।
मनमाना कोड निष्पादन में सक्षम क्लासें भी, अधिकांश मामलों में एप्लिकेशन द्वारा बनाए गए Bean क्लासों के साथ असंगत होती हैं।
उपरोक्त से, बड़े पैमाने पर हमले होने या वास्तव में इस भेद्यता का दुरुपयोग करके नुकसान पहुंचाने (= हमला सफल होने) की संभावना कम मानी जाती है।
एप्लिकेशन साइड के उपाय के बारे में, शर्त 3 के लिए JDK में शामिल क्लास का भी दुरुपयोग किया जा सकता है, इसलिए वास्तव में इसका कोई उपाय नहीं किया जा सकता।
इसलिए, मूल रूप से jackson-databind को नवीनतम संस्करण में अपडेट करना ही उपाय है।
यदि jackson-databind को नवीनतम संस्करण में अपडेट नहीं किया जा सकता है, तो `ObjectMapper.enableDefaultTyping()` और `@JsonTypeInfo` एनोटेशन को हटाकर, उन पर निर्भर न रहने वाले डिज़ाइन में सुधार करना होगा। उदाहरण के लिए, कस्टम सीरियलाइज़र बनाना आदि।
फिर भी, यदि पहले से ही रिमोट कॉल करने योग्य API के रूप में उपयोग शुरू किया गया है, तो JSON प्रारूप को आसानी से नहीं बदला जा सकता।
`@JsonTypeInfo` एनोटेशन के बारे में, सेटिंग के अनुसार उपवर्गों को सीमित किया जा सकता है, ताकि प्रोग्रामर द्वारा अपेक्षित क्लास नाम ही स्वीकार किए जा सकें।
कृपया निम्नलिखित दस्तावेज़ देखें।
* JacksonPolymorphicDeserialization
* https://github.com/FasterXML/jackson-docs/wiki/JacksonPolymorphicDeserialization
#### ब्लैकलिस्ट उपाय की उपयुक्तता और कस्टम डीसीरियलाइज़र बनाना
jackson-databind 2.8.10 / 2.9.1 ने ब्लैकलिस्ट उपाय के माध्यम से CVE-2017-7525 और CVE-2017-15095 को संबोधित किया।
हालांकि, जैसा कि Struts2 की OGNL-संबंधित समस्या से स्पष्ट है, ब्लैकलिस्ट उपाय पूर्णतः सुरक्षित नहीं है।
(लेखक का व्यक्तिगत मत: स्कैन टूल का उपयोग करने वाले तथाकथित "स्क्रिप्ट किडी" स्तर के लिए, यह कुछ हद तक प्रभावी उपाय है।)
इसलिए, यदि वास्तव में मौलिक उपाय किया जाए, तो `ObjectMapper.enableDefaultTyping()` जैसी JSON में क्लास जानकारी एम्बेड करने वाली सुविधाओं को ही अक्षम/उपयोग न करना महत्वपूर्ण मानता है लेखक।
तो, मूल समस्या जो `ObjectMapper.enableDefaultTyping()` हल करने का प्रयास कर रही थी, उसे कैसे हल किया जाए?
इसके लिए, लेखक के पास भी कोई निश्चित विकल्प नहीं है।
समस्या का मूल यह है: "जब मैपिंग करने वाली Java क्लास अस्पष्ट हो, तो अविश्वसनीय JSON पर निर्भर हुए बिना मैपिंग करना।"
इसे संभव बनाने के लिए, संभवतः कस्टम डीसीरियलाइज़र बनाने का दृष्टिकोण हो सकता है, ऐसा लेखक मानता है।
कस्टम डीसीरियलाइज़र प्रोग्राम कोड द्वारा deserialize के दौरान JSON प्राप्त करने और उत्पन्न Object को स्वयं नियंत्रित करने की अनुमति देता है।
उदाहरण के लिए, यदि `{"animal":{"name":"dog1","barkVolume":1.2}}` आता है, तो "`barkVolume` कुंजी है, इसलिए इसे Dog क्लास के रूप में इंस्टेंसिएट करें" का निर्णय लिया जा सकता है,
और यदि `{"animal":{"name":"cat1","likesCream":true,"lives":10}}` आता है, तो "`likesCream` कुंजी और `lives` कुंजी है, इसलिए इसे Cat क्लास के रूप में इंस्टेंसिएट करें" का निर्णय प्रोग्राम द्वारा लिया जा सकता है।
इसका उपयोग करके, JSON में क्लास नाम एम्बेड करने की आवश्यकता नहीं रहती।
व्यक्तिगत रूप से, क्लास नाम एम्बेड करने वाला JSON प्रारूप अन्य भाषाओं/लाइब्रेरीज़ के साथ अंतर-संचालन में बाधा उत्पन्न करता प्रतीत हुआ (यदि किसी अन्य भाषा या लाइब्रेरी में समान एक्सटेंशन संभव हो, तो कृपया बताएं)।
यदि अंतर-संचालन की बात है, तो Jackson की सुविधा के लिए क्लास नाम एम्बेड करवाने के बजाय, Jackson की ओर से कस्टम डीसीरियलाइज़र बनाकर संबोधित करना अधिक उपयुक्त लगता है।
इसके अलावा कुछ अन्य समाधान भी हो सकते हैं, यदि पाठकों के पास "यह भी एक समाधान हो सकता है" जैसा कोई सुझाव हो, तो कृपया अपनी राय साझा करें।
(एक चरम उदाहरण के रूप में, व्यक्तिगत क्लासों में मैपिंग किए बिना, सभी को `Map<String, Object>` या `List<String, Object>` प्रारूप में deserialize करने का तरीका भी हो सकता है।)
कस्टम डीसीरियलाइज़र बनाने के लिए कुछ संदर्भ लेख मिले हैं, जो अंग्रेजी में हैं, लिंक नीचे दिए गए हैं।
* Jackson: create a custom JSON deserializer with StdDeserializer and JsonToken classes | Dede Blog
* http://www.davismol.net/2015/05/20/jackson-create-a-custom-json-deserializer-with-stddeserializer-and-jsontoken-classes/
* Getting Started with Deserialization in Jackson | Baeldung
* http://www.baeldung.com/jackson-deserialization
* Custom JSON Deserialization with Jackson - DZone Integration
* https://dzone.com/articles/custom-json-deserialization-with-jackson
* Building a Custom Jackson Deserializer - The Boy Wonders
* http://www.robinhowlett.com/blog/2015/01/01/building-a-custom-jackson-deserializer/
jackson-databind के JavaDoc (2.8 श्रृंखला, 2.9 श्रृंखला):
* https://fasterxml.github.io/jackson-databind/javadoc/2.8/
* https://fasterxml.github.io/jackson-databind/javadoc/2.9/
लेखक ने भी कस्टम डीसीरियलाइज़र का नमूना कोड बनाया है, उम्मीद है कि यह सहायक होगा।
* [custom-deserializer-demo.groovy](https://github.com/SecureSkyTechnology/study-struts2-s2-054_055-jackson-cve-2017-7525_cve-2017-15095/blob/master/custom-deserializer-demo.groovy)
## S2-055 के बारे में
अब तक हमने Jackson की भेद्यता के बारे में देखा। अब, यह वास्तव में Struts2 के REST plugin को कैसे प्रभावित करती है? Struts2 के साथ आने वाले struts2-rest-showcase का उपयोग करके जाँच की गई।
Struts REST plugin के उपयोग के लिए निम्नलिखित संदर्भ लिया गया:
* http://struts.apache.org/plugins/rest/
### Struts2 REST plugin में ObjectMapper.enableDefaultTyping() कॉल नहीं किया जाता
वैसे, CVE-2017-7525 में वास्तव में भेद्य होने की शर्तों में निम्नलिखित थीं:
* अविश्वसनीय स्रोत से प्राप्त JSON पर, निम्नलिखित में से कोई एक कार्रवाई करना:
* `ObjectMapper.enableDefaultTyping()` को कॉल करके deserialize करना।
* `ObjectMapper.enableDefaultTyping()` को कॉल नहीं करना, लेकिन क्लास घोषणा में `@JsonTypeInfo` एनोटेशन का उपयोग करके मैपिंग सक्षम करना और deserialize करना।
जब हमने Struts2 REST plugin में इन शर्तों को पूरा करने वाला कोड खोजा, तो पाया कि दोनों में से कोई भी शामिल नहीं है।
वास्तव में, संस्करण 2.5.14 में, `ObjectMapper.enableDefaultTyping()` और `@JsonTypeInfo` दोनों का उपयोग REST plugin या पूरे Struts2 स्रोत ट्री में grep करने पर कहीं नहीं मिला।
* https://github.com/apache/struts/tree/STRUTS_2_5_14
Struts2 के पूरे स्रोत ट्री में, Jackson ObjectMapper का उपयोग केवल org.apache.struts2.rest.handler.JacksonLibHandler क्लास में होता है। स्रोत कोड की जाँच करने पर, 2.5.14 में पुष्टि हुई कि `ObjectMapper.enableDefaultTyping()` का उपयोग नहीं किया गया।
* https://github.com/apache/struts/blob/STRUTS_2_5_14/plugins/rest/src/main/java/org/apache/struts2/rest/handler/JacksonLibHandler.java
* यह Java फ़ाइल 2.5.14.1 में भी अपरिवर्तित है।
इसलिए, CVE-2017-7525 के लिए REST plugin स्वयं 2.5.14 संस्करण में भी समस्यामुक्त था।
भेद्य तब होता है जब एप्लिकेशन साइड पर JSON में मैपिंग करने वाली क्लास के फ़ील्ड में `@JsonTypeInfo` सेट किया जाता है।
इसलिए, नीचे struts2-rest-showcase का उपयोग करके सत्यापन में, एप्लिकेशन साइड पर जोड़े गए मैपिंग लक्ष्य फ़ील्ड पर `@JsonTypeInfo` सेट किया गया और सत्यापित किया गया।
वैसे, Struts2 में JSON plugin भी है।
* http://struts.apache.org/plugins/json/
* JSON plugin के स्रोत को देखने पर, pom.xml में कोई अन्य JSON लाइब्रेरी निर्भरता नहीं है।
* ऐसा प्रतीत होता है कि यह स्वयं JSON प्रसंस्करण लागू करता है।
* https://github.com/apache/struts/tree/STRUTS_2_5_14/plugins/json
* इसलिए, jackson-databind भेद्यता JSON plugin को प्रभावित नहीं करेगी।
### struts2-rest-showcase को Jackson-सक्षम बनाना
struts2-rest-showcase REST plugin का उपयोग करके Order क्लास का CRUD लागू करने वाला नमूना है। इसमें Jackson भेद्यता नमूना कोड में उपयोग की गई Zoo / Animal / Cat / Dog क्लास और उनके JSON प्रसंस्करण के लिए ZooController जोड़ा गया।
पूरा स्रोत कोड नीचे देखें (इस लेख में JDK8 पर बिल्ड और निष्पादन की पुष्टि की गई):
* [rest-showcase](https://github.com/SecureSkyTechnology/study-struts2-s2-054_055-jackson-cve-2017-7525_cve-2017-15095/tree/master/rest-showcase)
मुख्य संशोधन:
* jetty-maven-plugin के लिए listening पोर्ट 18088 में बदला गया। (`mvn jetty:run`)
* jackson-core, jackson-databind को निर्भरता में जोड़ा गया।
* Zoo, Animal(abstract), Dog, Cat क्लास जोड़े गए। सेवा स्तर के रूप में ZooService क्लास जोड़ी गई।
* न्यूनतम CRUD वाला ZooController जोड़ा गया (View के लिए JSP हटा दिया गया)।
* struts.xml में JSON हैंडलर को JacksonLibHandler में बदला गया।
* maven-wrapper शामिल किया गया, ताकि केवल JDK इंस्टॉल होने पर mvnw / mvnw.bat से सीधे बिल्ड और निष्पादन किया जा सके।
बिल्ड और निष्पादन:
1. रिपॉजिटरी क्लोन करने के बाद, rest-showcase निर्देशिका में cd करें और `mvnw jetty:run` चलाएँ। (पहली बार चलाने पर maven डाउनलोड होगा, जिसमें कुछ मिनट या 10 मिनट से अधिक समय लग सकता है।)
2. http://localhost:18088/struts2-rest-showcase/ पर जाएँ, Order की सूची दिखे तो सफल।
3. निष्पादन समाप्त करने के लिए Ctrl-C दबाएँ।
4. Java फ़ाइलों में संशोधन के बाद, Ctrl-C से रोकें और फिर `mvnw jetty:run` चलाएँ।
curl कमांड से कार्य सत्यापन: (स्थानीय http प्रॉक्सी localhost:8080 के माध्यम से मान लिया गया)```
一覧取得:
curl -v -x localhost:8080 -H "Accept: application/json" "http://localhost:18088/struts2-rest-showcase/zoo"
ID指定:
curl -v -x localhost:8080 -H "Accept: application/json" "http://localhost:18088/struts2-rest-showcase/zoo/1"
curl -v -x localhost:8080 -H "Accept: application/json" "http://localhost:18088/struts2-rest-showcase/zoo/2"
削除:
curl -v -x localhost:8080 -H "Accept: application/json" "http://localhost:18088/struts2-rest-showcase/zoo/2" -X DELETE
रिपॉजिटरी के Zoo.java में animal फ़ील्ड निम्नानुसार है जहाँ @JsonTypeInfo को कमेंट आउट कर दिया गया है और यह abstract class के Animal प्रकार का है।```java
//@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.WRAPPER_ARRAY)
public Animal animal;
//public Object animal;
यहाँ, POST विधि से JSON अनुरोध भेजें और ZooController.create() विधि को कॉल करने का प्रयास करें।```
curl -v -x localhost:8080 -H "Accept: application/json" "http://localhost:18088/struts2-rest-showcase/zoo" -X POST -H "Content-Type: application/json" -d '{"id":"3","animal":{"name":"dog2","barkVolume":2.3}}'
तब निम्नलिखित त्रुटि संदेश वाला एक अपवाद उत्पन्न हुआ। Animal वर्ग abstract होने के कारण, इसका उदाहरण उत्पन्न नहीं किया जा सका।``` Can not construct instance of org.demo.rest.example.Animal: abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
तो `animal` फ़ील्ड के `@JsonTypeInfo` को अनकमेंट करके सक्रिय करें। Ctrl-C से वेब एप्लिकेशन को रोकें और फिर से `mvnw jetty:run` चलाएँ।```java
// 次のimportを忘れずに追加
import com.fasterxml.jackson.annotation.JsonTypeInfo;
//...
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.WRAPPER_ARRAY)
public Animal animal;
//public Object animal;
इससे JSON में क्लास नाम एम्बेड करना संभव हो जाता है। नीचे दिए गए curl कमांड से, क्लास नाम एम्बेड किए गए JSON को POST करने का प्रयास करें।``` curl -v -x localhost:8080 -H "Accept: application/json" "http://localhost:18088/struts2-rest-showcase/zoo" -X POST -H "Content-Type: application/json" -d '{"id":"3","animal":["org.demo.rest.example.Dog",{"name":"dog2","barkVolume":2.3}]}'
→ `HTTP/1.1 201 Created` वापस आता है। सूची प्राप्त करने पर यह सुनिश्चित किया जा सकता है कि जोड़ा गया है।
### Struts2 REST plugin 2.5.14 में CVE-2017-7525 की पुष्टि करें
रिपॉजिटरी के pom.xml में `<parent>` के struts artifact में संस्करण 2.5.14 निर्दिष्ट किया गया है, इसलिए यह सीधे CVE-2017-7525 के प्रति संवेदनशील है। इसकी पुष्टि के लिए, निम्नलिखित curl कमांड चलाएँ। क्लास का नाम और उसकी सामग्री cve-2017-7525-check.groovy पर आधारित है, इसलिए यदि jackson-databind 2.8.8 के समान प्रतिक्रिया प्राप्त होती है, तो इसे संवेदनशील माना जा सकता है।```
curl -v -x localhost:8080 -H "Accept: application/json" "http://localhost:18088/struts2-rest-showcase/zoo" -X POST -H "Content-Type: application/json" -d '{"id":"3","animal":["com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl",{"transletBytecodes":["AAIAZQ=="],"transletName":"a.b","outputProperties":{}}]}'
→ 以下のレラーメッセージを含む例外がthrowされました。``` java.lang.IllegalArgumentException: Class com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl not subtype of [simple type, class org.demo.rest.example.Animal]
`animal` 字段的类型是 `com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl` 类的子类型不是 `Animal` 类,因此似乎触发了 `IllegalArgumentException`。
那么,我们把 Zoo.java 中的 `animal` 字段修改为 `Object` 类型,然后再次用 `mvnw jetty:run` 运行试试。```java
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.WRAPPER_ARRAY)
//public Animal animal;
public Object animal;
इसके साथ, जब आप पिछले curl कमांड को फिर से चलाते हैं, तो निम्नलिखित stack trace सहित एक अपवाद उत्पन्न हुआ।``` Caused by: java.lang.NullPointerException at com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl$1.run(TemplatesImpl.java:401) ~[?:1.8.0_92]
यह वही अपवाद है जो cve-2017-7525-check.groovy के साथ सत्यापित करने पर होता है, कमजोर स्थिति में।
इस प्रकार, Struts2 REST प्लगइन 2.5.14 में, jackson-databind में CVE-2017-7525 कमजोरी की उपस्थिति की पुष्टि की जा सकती है।
इसके अलावा, यह भी स्पष्ट हो गया कि `@JsonTypeInfo` के अलावा Object प्रकार का उपयोग करना आवश्यक है।
निम्नलिखित लेखक का व्यक्तिगत मत है, लेकिन REST API बनाते समय डेटा क्लासेज में, फ़ील्ड के प्रकार के रूप में जानबूझकर Object क्लास या java deserialize की कमजोरी में Gadget के रूप में उपयोग किए जा सकने वाले क्लास के साथ संगत क्लास निर्दिष्ट करना सामान्य नहीं लगता। इसलिए, मुझे लगता है कि वास्तव में हमले को सफल बनाना कठिन है।
### Struts2 REST प्लगइन 2.5.14.1 में समाधान की पुष्टि
अब देखते हैं कि संस्करण 2.5.14.1 में कमजोरी को ठीक किया गया है या नहीं।
pom.xml में `<parent>` आर्टिफैक्ट के संस्करण को 2.5.14.1 में संशोधित करें, `mvnw jetty:run` के साथ पुनरारंभ करें, और पहले जैसा ही curl कमांड चलाएं।```
curl -v -x localhost:8080 -H "Accept: application/json" "http://localhost:18088/struts2-rest-showcase/zoo" -X POST -H "Content-Type: application/json" -d '{"id":"3","animal":["com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl",{"transletBytecodes":["AAIAZQ=="],"transletName":"a.b","outputProperties":{}}]}'
→ 以下のエラーメッセージを含む例外が発生しました。```
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Invalid type definition for type com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl: Illegal type (com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl) to deserialize: prevented for security reasons
यह cve-2017-7525-check.groovy में सत्यापित किए जाने के समान, कमजोरी ठीक होने के बाद का अपवाद है।
Eclipse आदि जैसे Maven-संगत IDE में खोलकर, निर्भरताओं को हल करने के बाद jackson-databind का संस्करण देखने पर, निश्चित रूप से यह 2.9.2 होने की पुष्टि की जा सकती है। यदि IDE नहीं है, तो `mvnw help:effective-pom` से अंतिम pom आउटपुट किया जा सकता है, वहाँ jackson-databind खोजने पर version 2.9.2 का उपयोग होने की पुष्टि हो सकती है।
CVE-2017-15095 के बारे में संक्षेप में छोड़ते हुए, उपरोक्त से यह पुष्टि हुई कि 2.5.14.1 में jackson-databind की कमजोरी को संबोधित किया गया।
### S2-055 का PoC
※ 2017-12-08 परिशिष्ट
S2-055 पर शोध लेख और PoC रिपोर्ट प्रकाशित की गई है।
* S2-055漏洞环境搭建与分析 | 绿盟科技博客
* http://blog.nsfocus.net/s2-055/
Google अनुवाद की सहायता से पढ़ने पर, घटना की स्थिति और हमले की वास्तविकता के बारे में समान राय प्रतीत होती है।
वास्तव में rest-showcase को संशोधित करके, कैलकुलेटर शुरू होने वाले HTTP संचार का PoC भी दिखाया गया है।
केवल JSON भाग उधार लेकर, पहले Jackson अकेले में प्रयास करने का नमूना कोड निम्नलिखित है।
* [cve-2017-7525-poc.groovy](https://github.com/SecureSkyTechnology/study-struts2-s2-054_055-jackson-cve-2017-7525_cve-2017-15095/blob/master/cve-2017-7525-poc.groovy)
यहाँ 2.8.8 का उपयोग करते हुए संस्करण निर्दिष्ट करके चलाने पर, लेखक के वातावरण में निम्नानुसार आउटपुट हुआ।```
your jackson version MAY NOT BE SAFE to CVE-2017-7525
(...)
Caused by: java.lang.NullPointerException
at com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl$1.run(TemplatesImpl.java:401)
(...)
cve-2017-7525-check.groovy की तरह, run() मेथड चली और NullPointerException हुआ। हालाँकि, कैलकुलेटर चालू नहीं हुआ।
यह अनुमान है, लेकिन xalan का TemplatesImpl Java के अंदर एक क्लास है, इसलिए संभव है कि Java की ओर से कुछ संशोधन किया गया हो। या फिर, वास्तविक आक्रमण सफल होने के लिए अधिक सरल शर्तों की आवश्यकता हो सकती है।
PoC लेख में उपयोग किए गए Java के संस्करण का उल्लेख नहीं किया गया था, और हम कैलकुलेटर चलाने तक नहीं पहुँच पाए। यदि अतिरिक्त जानकारी मिलती है, तो हम फिर से परीक्षण करेंगे।
अब तक, S2-055 से शुरू करके हमने मुख्य रूप से Jackson की कमजोरियों CVE-2017-7525 और CVE-2017-15095 का परिचय दिया है। अब, दूसरी कमजोरी S2-054 की स्थिति के बारे में एक मोटी जाँच के नतीजों का सारांश प्रस्तुत करूँगा।
निष्कर्ष के तौर पर, इस लेख को लिखने के समय (2017-12-03) तक कोई विशिष्ट जानकारी नहीं मिली। कमजोरी की उपस्थिति का परीक्षण करने वाला कोई PoC भी नहीं मिला।
S2-054 की सूचना पृष्ठ में बताया गया है कि REST plugin में पुरानी JSON-lib लाइब्रेरी का उपयोग किया जाता है, और छेड़छाड़ किए गए JSON द्वारा DoS आक्रमण संभव है।
The REST Plugin is using an outdated JSON-lib library which is vulnerable and allow perform a DoS attack using malicious request with specially crafted JSON payload.
इस समस्या के समाधान के रूप में जारी किए गए 2.5.14.1 पृष्ठ पर, इसके अनुरूप JIRA टिकट के रूप में WW-4892 जुड़ा हुआ है।
WW-4892 की जाँच की, लेकिन कहीं भी DoS या JSON-lib कमजोरी का उल्लेख नहीं मिला। "Description" पढ़ने पर भी ऐसा लगता है कि केवल यह लिखा है कि JSON-lib पुरानी और अनुरक्षित नहीं है, इसलिए डिफ़ॉल्ट हैंडलर Jackson में बदल दिया गया है।
GitHub की pullreq निम्नलिखित है, लेकिन इसमें भी JSON-lib की विशिष्ट समस्या का कोई उल्लेख नहीं है।
इसलिए, हमने JSON-lib की ओर देखने का निर्णय लिया। आधिकारिक वेबसाइट निम्नलिखित है।
साथ ही, 2017 के वर्तमान में, ऐसा प्रतीत होता है कि इसे GitHub पर प्रबंधित किया जा रहा है।
कौन-सा नवीनतम है? इस लेख को लिखने के समय तक GitHub ओर कोई रिलीज़ नहीं हुई है। इसलिए, Maven Central रिपॉजिटरी की पंजीकरण स्थिति देखी। "json-lib" खोजने पर कई groupId मिलते हैं।
कौन-सा groupId सही है, यह जानने के लिए Struts2 2.5.14.1 के REST plugin के pom.xml की जाँच की।
groupId = net.sf.json-lib, artifactId = json-lib के रिलीज़ संस्करणों को देखने पर, दिसंबर 2010 का संस्करण 2.4 अंतिम रिलीज़ है।
sourceforge पृष्ठ की जाँच करने पर, यहाँ भी दिसंबर 2012 का संस्करण 2.4 अंतिम रिलीज़ है।
वास्तव में, GitHub ओर कोई रिलीज़ टैग नहीं है, लेकिन कमिट लॉग पर जाने पर दिसंबर 2010 में संस्करण 2.4 रिलीज़ का कमिट मिलता है। इसके अलावा, pullreq मर्ज तो हो रहे हैं, लेकिन रिलीज़ की कोई गतिविधि नहीं रही है।
GitHub पर closed सहित Issue देखने पर, DoS से संबंधित कोई शीर्षक नहीं मिला।
sourceforge के टिकट देखने पर, अंततः memory leak समस्या के टिकट मिले। ऐसा प्रतीत होता है कि इनमें से किसी को भी ठीक नहीं किया गया है।
अंततः मैं इस बिंदु तक पहुँच पाया कि memory leak समस्या शेष प्रतीत होती है, लेकिन लेखक की क्षमता और समय की कमी के कारण, इससे आगे की जाँच नहीं कर सका।
यदि वास्तव में इस पैटर्न के JSON से memory leak या DoS हुआ हो, ऐसी विशिष्ट जानकारी हो, तो कृपया बताएँ, बहुत सहायता होगी।
Jackson का उपयोग करने वाले बहुत से OSS हैं, इसलिए इस कमजोरी से प्रभावित अन्य लाइब्रेरी और फ्रेमवर्क भी मौजूद हैं। उदाहरण के तौर पर, Pivotal उत्पादों का Spring Security प्रभावित हुआ, और जून 2017 में सूचना प्रकाशित की गई।
उसके अलावा, उदाहरण के लिए Spring Framework मुख्य भाग के बारे में, कम से कम https://pivotal.io/security/ पर Jackson-उत्पन्न अद्यतन जानकारी प्रकाशित नहीं हुई है।
लेकिन इससे निश्चिंत नहीं हुआ जा सकता। मूल रूप से, Spring Framework में Jackson काफी अनुकूलन योग्य डिज़ाइन का है, और एप्लिकेशन-विशिष्ट ObjectMapper बनाना भी संभव है। क्या आप एप्लिकेशन पक्ष पर Jackson सेटिंग्स/फीचर्स को अनुकूलित कर रहे हैं? क्या @JsonTypeInfo का उपयोग कर रहे हैं? आदि की जाँच करना उचित होगा।
jackson-databind के GitHub Issue/रिलीज़ जानकारी और RedHat के bugzilla जैसे संदर्भ लिंक को कालक्रमानुसार व्यवस्थित किया गया है। यदि कोई गलती हो, तो कृपया बेझिझक लेखक को बताएँ या संपर्क करें।
उस समय के black-list की सूची निम्नलिखित थी।```java s.add("org.apache.commons.collections.functors.InvokerTransformer"); s.add("org.apache.commons.collections.functors.InstantiateTransformer"); s.add("org.apache.commons.collections4.functors.InvokerTransformer"); s.add("org.apache.commons.collections4.functors.InstantiateTransformer"); s.add("org.codehaus.groovy.runtime.ConvertedClosure"); s.add("org.codehaus.groovy.runtime.MethodClosure"); s.add("org.springframework.beans.factory.ObjectFactory"); s.add("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl"); s.add("org.apache.xalan.xsltc.trax.TemplatesImpl");
यहाँ, उसी महीने के भीतर black-list उपाय के अतिरिक्त सुधार के रूप में 2.9.0 जारी किया गया।
* https://github.com/FasterXML/jackson-databind/issues/1680
यह जोड़ा गया:```java
s.add("com.sun.rowset.JdbcRowSetImpl");
उसी महीने में, निम्नलिखित Issue खोला गया।
→black-list में निम्नलिखित जोड़ा गया, और यह 2.8.10 / 2.9.1 में शामिल किया गया।```java // [databind#1737]; JDK provided s.add("java.util.logging.FileHandler"); s.add("java.rmi.server.UnicastRemoteObject"); // [databind#1737]; 3rd party s.add("org.springframework.aop.support.AbstractBeanFactoryPointcutAdvisor"); s.add("org.springframework.beans.factory.config.PropertyPathFactoryBean"); s.add("com.mchange.v2.c3p0.JndiRefForwardingDataSource"); s.add("com.mchange.v2.c3p0.WrapperConnectionPoolDataSource");
### 2017-08
* #1680, #1737 के समाधान के साथ 2.8.10 जारी किया गया।
* इसके अलावा, अगस्त में निम्नलिखित Issue खोला गया, और CVE-2017-7525 के रूप में समाधान पर व्यापक चर्चा हुई।
* https://github.com/FasterXML/jackson-databind/issues/1723
* Adam Caudill के ब्लॉग पर CVE-2017-7525 के exploit का विवरण प्रकाशित हुआ।
* https://adamcaudill.com/2017/10/04/exploiting-jackson-rce-cve-2017-7525/
### 2017-09
* #1737 के समाधान के साथ 2.9.1 जारी किया गया।
### 2017-10
निम्नलिखित bugzilla में, CVE-2017-7525 के सुधार के समय 2.8.9 / 2.9.0 में अपर्याप्त समाधान पाया गया, और नए CVE-2017-15095 के रूप में नवीनतम 2.8.10 / 2.9.1 की black-list लागू करने का काम शुरू हुआ।
* https://bugzilla.redhat.com/show_bug.cgi?id=1506612
### 2017-11
* RedHat से CVE-2017-15095 की जानकारी प्रकाशित हुई।
* https://access.redhat.com/security/cve/cve-2017-15095
* jackson-databind के Issue में भी, नीचे CVE-2017-15095 के समाधान की स्थिति पर प्रश्नोत्तर हुआ।
* https://github.com/FasterXML/jackson-databind/issues/1847
* 2.8.10 / 2.9.1 में समाधान किया गया है, ऐसा उत्तर दिया गया।
### 2017-12
* क्लाउड साइड WAF Scutum के डेवलपर ब्लॉग पर व्याख्यात्मक लेख प्रकाशित हुआ।
* https://www.scutum.jp/information/waf_tech_blog/2017/12/waf-blog-052.html
* इस लेख में बताया गया कि 2.9.3 की black list में Spring के क्लास में कमी है, जो तत्काल समस्या नहीं है, लेकिन संभवतः भविष्य में अपडेट की आवश्यकता हो सकती है।
* साथ ही, इस कमजोरी की जिम्मेदारी मूल रूप से लाइब्रेरी पक्ष पर थी या एप्लिकेशन पक्ष पर? इस बिंदु पर भी चर्चा की गई।
## भविष्य में Java serialize/deserialize संबंधित कमजोरियों की प्रवृत्ति
पिछले दो वर्षों से Java serialize/deserialize से संबंधित कमजोरियों की जानकारी बढ़ती हुई प्रतीत होती है।
उदाहरण के रूप में, Spring सहित Pivotal उत्पादों की कमजोरियों की जानकारी https://pivotal.io/security/ पर प्रकाशित होती है, और वास्तव में, 2017 में CVE-2017-4995 के अलावा निम्नलिखित कमजोरियां प्रकाशित हुईं।
* https://pivotal.io/security/cve-2017-8045
* Spring AMQP में `org.springframework.amqp.core.Message` के deserialize समस्या के कारण RCE
* https://pivotal.io/security/cve-2017-8046
* Spring Data REST में PATCH विधि में JSON के प्रबंधन में कमी, जिससे RCE
यह RCE की ओर ले जाने वाली कमजोरी है, इसलिए ऐसा प्रतीत होता है कि हमलावर/कमजोरी शोधकर्ता दोनों ही Java serialize/deserialize पर ध्यान केंद्रित कर रहे हैं।
आने वाले कुछ वर्षों में serialize/deserialize प्रसंस्करण से संबंधित कमजोरियों की रिपोर्ट जारी रहेगी।
हालांकि, Jackson की तरह, विकास को कुशल बनाने और रिमोट API द्वारा डेटा आदान-प्रदान सामान्य हो जाने के कारण, वर्तमान विकास में serialize/deserialize का बिल्कुल उपयोग न करना या शून्य से स्वयं बनाना वास्तविक रूप से असंभव है, ऐसे कई स्थान हैं।
महत्वपूर्ण बात यह है कि कमजोरी प्रकाशित होने पर जितनी जल्दी हो सके लाइब्रेरी को अपडेट करने में सक्षम हल्के विकास ढांचे और संस्कृति का निर्माण करना है, ऐसा लेखक व्यक्तिगत रूप से सोचता है।
आश्रित मिडलवेयर/लाइब्रेरी/फ्रेमवर्क की कमजोरियों का सामना कैसे करें, इस बारे में मानसिक रूप से कुछ सोचा, इसलिए नीचे एक भावना के रूप में लिखा।
## भावना
जब S2-054, 055 प्रकाशित हुए, और इसमें Jackson की कमजोरी का प्रभाव है, यह जानकारी देखकर लेखक को काफी झटका लगा।
क्योंकि कुछ दिन पहले एक सहकर्मी ने पूछा था "Java में JSON पार्स करने के लिए कोई अनुशंसित लाइब्रेरी?" और मैंने गर्व से कहा था "Jackson OSS में व्यापक रूप से उपयोग किया जाता है और सिद्ध है, गूगल करने पर कई लेख और QA मिलते हैं, इसलिए अनुशंसित है।"
लेखक स्वयं कंपनी के टूल विकास आदि में Jackson का उपयोग करता था और सुविधा महसूस करता था।
हालांकि, उस समय लेखक CVE-2017-7525 से अवगत नहीं था, और Jackson के OSS में व्यापक उपयोग और अनेक उपयोगकर्ताओं के कारण पूरी तरह से आश्वस्त था।
वहां एक अन्य सहकर्मी ने Adam Caudill का ब्लॉग ढूंढा और CVE-2017-7525 के अस्तित्व के बारे में बताया, लेकिन Jackson का उपयोग करने वाले के रूप में गर्व से अनुशंसा करने के कुछ दिनों बाद Jackson की कमजोरी के कारण Struts2 ने अपडेट जारी किया, और Jackson की कमजोरी स्वयं कुछ महीने पहले से संबोधित थी, तो सुरक्षा उद्योग में कार्यरत एक इंजीनियर के रूप में, यदि यह बताया जाए कि मैंने उपयोग कर रहे लाइब्रेरी की कमजोरियों की जानकारी एकत्र करने में लापरवाही की, तो इससे बच नहीं सकता (वास्तव में ऐसा ही था)।
इसलिए पिछले कुछ दिनों में लेखक की मानसिक स्थिति बहुत खराब थी (रक्तचाप/नाड़ी में वृद्धि, हाथ कांपना, बिना दुखी हुए आँसू आना, धड़कन न रुकना, आदि), और इसे संभालने के लिए, पहले यह जानने का प्रयास किया कि CVE-2017-7525 क्या है और Jackson की स्थिति क्या है, और सप्ताहांत बिताकर इस लेख की जांच और लेखन में लग गया।
इस बिंदु पर पीछे मुड़कर देखने पर, यह स्पष्ट है कि विकास पर ध्यान केंद्रित करने पर निर्भर लाइब्रेरी के अपडेट की जानकारी पर ध्यान देना कठिन है।
लगातार आने वाले विकास कार्यों में, उपयोग की जाने वाली सभी लाइब्रेरी के कार्यों और कमजोरियों जैसी गुणवत्ता की पूरी जांच वास्तविक रूप से असंभव है।
दूसरी ओर, विकास में आवश्यक कार्य बढ़ते जा रहे हैं, और उन सभी को स्वयं बनाना भी वास्तविक रूप से असंभव है।
कहीं न कहीं उपयोग की जाने वाली लाइब्रेरी पर "भरोसा" करना और विकास को कुशल बनाना आवश्यक है।
फिर भी, दैनिक विकास कार्यों में उपयोग किए जाने वाले टूल/लाइब्रेरी के सभी अपडेट जानकारी को ट्रेस करना और सुरक्षा समस्याओं के सुधार के लिए नजर रखना भी बहुत कठिन है।
बेशक, इस समस्या को हल करने के लिए हाल ही में ऐसी सेवाएं हैं जो उपयोग किए जाने वाले टूल/लाइब्रेरी को पंजीकृत करके उनके अपडेट की जानकारी प्रदान करती हैं, यह मैं जानता हूं।
इस बार मानसिक स्थिति के बिगड़ने से मैंने महसूस किया कि अपने अंदर "जो नहीं किया, उसके लिए आत्म-दोष और अपराधबोध" बहुत मजबूत है।
"सुरक्षा इंजीनियर होने के बावजूद, स्वयं द्वारा उपयोग की जा रही लाइब्रेरी की कमजोरियों की जानकारी नहीं रखना..." जैसा नकारात्मक लेबल स्वयं पर लगा रहा था।
सुरक्षा उद्योग से संबंधित न होने वाले सामान्य डेवलपर भी,
"उस समय Struts2 का सुझाव न दिया होता..." या "लाइब्रेरी/फ्रेमवर्क के जीवनचक्र प्रबंधन को और मजबूत करना चाहिए (= वर्तमान स्थिति/स्वयं को न कर पाने पर चिंता)"
जैसे पछतावे या चिंता मन में रखने वाले कई लोग हो सकते हैं।
यदि इन्हें "समस्या" मानकर सीधे "हल" करने का प्रयास किया जाए, तो कमजोरियों की जानकारी एक-एक करके एकत्र करनी होगी, उपयोग की जाने वाली लाइब्रेरी और फ्रेमवर्क के सोर्स कोड और कार्यों की जांच करनी होगी, डिफैक्टो स्टैंडर्ड होने की पुष्टि करनी होगी, और संचालन शुरू होने के बाद जीवनचक्र प्रबंधन सख्ती से करना होगा।
लेकिन, क्या ऐसा "पत्थर के पुल को थपथपाकर पार करने" का तरीका आज के विविध विकास स्थानों में संभव है?
इस लेख को लिखने के बाद मैंने सोचा कि "जो नहीं किया/नहीं कर सका/महसूस नहीं कर पाया" को कारण या दोषी मानकर, उसे हटाना = "करने योग्य बनाना" को ही "समस्या का समाधान" मानने का समय शायद समाप्त हो गया है।
ऐसी संस्कृति में, जब तक इंसान पूर्ण न हो, डेवलपर को अपने "न कर पाने, न करने, न समझ पाने" का सामना लगातार करना होगा।
पूर्ण इंसान न होने के कारण, जब तक मानसिक रूप से बहुत मजबूत न हो, यह टिक नहीं पाएगा।
सॉफ्टवेयर सुरक्षा समस्या में, वास्तविक नुकसान पहुंचाने वाला अपराधी हमलावर है। स्थिति को नकारात्मक बनाने वाला, कमजोरी का दुरुपयोग करने वाला हमलावर है।
अधिकांश डेवलपर मूल रूप से सद्भावना से और गंभीरता से विकास करते हैं। उस समय, वे पहले से ही सकारात्मक स्थिति में हैं।
"लाइब्रेरी/फ्रेमवर्क का जीवनचक्र प्रबंधन न करना" या "उपयोग की जा रही लाइब्रेरी की कमजोरियों की जानकारी एकत्र/निगरानी न करना" केवल न करना है, यह न तो सकारात्मक है और न ही नकारात्मक।
फिर भी, हमलावर के अस्तित्व के कारण, "न करना" को "न कर पाना/न समझ पाना" के रूप में नकारात्मक बना दिया जाता है, क्या यह बहुत दुखद स्थिति नहीं है?
"पत्थर के पुल को थपथपाकर पार करने" के मूल्यों पर आधुनिक जापानी समाज और कॉर्पोरेट संस्कृति का प्रभाव नकारा नहीं जा सकता।
वास्तव में, SQL इंजेक्शन जैसी कमजोरियां बन जाने और हमलावरों द्वारा नुकसान के मामले लगातार हो रहे हैं, और डेवलपमेंट कंपनी की जिम्मेदारी पर मुकदमे भी हुए हैं।
कार्य में लापरवाही से बड़ी दुर्घटनाएं भी होती हैं।
हालांकि, यदि इन सबको "डेवलपमेंट कंपनी/डेवलपर" की समस्या मान लिया जाए, तो समग्र IT विकास सिकुड़ जाएगा।
वास्तव में बुरा, कमजोरी का दुरुपयोग करने वाला हमलावर है।
इस प्रकार सोचने पर, "न करने/न कर पाने/न समझ पाने" वाले डेवलपर या डेवलपमेंट कंपनी, अपराधी से अधिक पीड़ित कहलाएंगे?
तो, पीड़ित से यह कहने के बजाय कि "तुमने नहीं किया/नहीं कर पाए/नहीं समझे, यह तुम्हारी गलती है", बल्कि "इस तरह अधिक सुरक्षित हो सकते हैं, सुधार कर सकते हैं, साथ मिलकर प्रयास करें" कहकर, एक साथ चलने के उद्देश्य से गर्म हाथ बढ़ाना और एक-दूसरे के विशेष क्षेत्रों में प्रतिस्पर्धा करना और लाभ उठाना महत्वपूर्ण है, ऐसा मैं दृढ़ता से मानता हूं।
ऐसा होने पर, डेवलपमेंट कंपनी/डेवलपर भी आराम से कमजोरी के समाधान में लग सकेंगे, और उसके बाद भी आराम के आधार पर सक्रिय विकास करना आसान होगा।
विकास स्थलों में आरामदायक और उज्ज्वल, सक्रिय विकास बढ़ने से, परिणामस्वरूप नवीन परिणाम बढ़ेंगे और जापानी समाज अधिक समृद्ध होगा।
लेखक की व्यक्तिगत इच्छा यह है कि भविष्य में निम्नलिखित सोच फैले:
* क्षेत्र के डेवलपर
* "कमजोरी वाली लाइब्रेरी का उपयोग कर लिया", यह स्वयं नकारात्मक नहीं है।
* नकारात्मक बनाने वाला, कमजोरी का दुरुपयोग करने वाला हमलावर है, और वह संस्कृति जो इसे नकारात्मक मानती है।
* प्रतिदिन गंभीरता से काम करना और विकास करना पहले से ही पर्याप्त सकारात्मक है।
* कमजोरी का समाधान, नकारात्मक को शून्य पर लौटाने का काम नहीं, बल्कि दैनिक विकास परिणामों को अधिक सुरक्षित बनाने के लिए सकारात्मक कार्य है।
* डेवलपरों का प्रबंधन करने वाले मैनेजर/लीडर, प्रबंधन स्तर
* "न करने/न कर पाने/न समझ पाने" को नकारात्मक मूल्यांकन न दें। ऐसी मानसिकता धीरे-धीरे फीकी पड़ जाएगी।
* "न करने/न कर पाने/न समझ पाने" वाले सदस्यों को दोषी न मानें। वे, और हम सभी, कमजोरी का दुरुपयोग करने वाले हमलावर के पीड़ित हैं, इस दृष्टिकोण से हम समान हैं।
* "पूर्ण उपाय" से हल करने के दृष्टिकोण को रोकें।
यह डेवलपर, मैनेजर/लीडर और प्रबंधन स्तर तक को शामिल करते हुए "चीजों को देखने और समझने के तरीके को बदलने" का संदर्भ बन जाता है, लेकिन यह बहुत कठिन है।
आखिर, कैसे बदलें?
लेखक स्वयं सही उत्तर नहीं दे सकता, लेकिन इसमें एक संकेत है।
अर्थात, सही उत्तर की खोज करना ही छोड़ देना चाहिए?
किसी भी सॉफ्टवेयर विकास का कोई न कोई उद्देश्य होता है। उसे सुरक्षित तरीके से प्राप्त करने का "सही उत्तर" ढूंढना अब लगभग असंभव है, सॉफ्टवेयर की दुनिया इतनी जटिल हो गई है।
शायद वहां एक विकास प्रतिमान है जहां कई खिलाड़ी अपने-अपने तरीके से प्रयास करते हैं, फीडबैक प्राप्त करते हैं, परस्पर जानकारी का आदान-प्रदान करते हैं, और उससे स्वतंत्र रूप से शाखाबद्ध और बदलते रहते हैं, जो "बदलने" को आधार मानता है।
सिस्टम विकास में एक बार बनाए गए सॉफ्टवेयर संसाधनों का उपयोग कई वर्षों, कभी-कभी दशकों तक किया जाता है।
हालांकि, वेब विकास सहित इंटरनेट से जुड़े सॉफ्टवेयर, कुछ महीनों से लेकर कुछ वर्षों में बदलते वातावरण के संपर्क में आते हैं।
5 साल पहले विकास में उपयोग की गई लाइब्रेरी या फ्रेमवर्क अब उपयोगी नहीं रह सकती है।
ऐसा होने पर, पहले बनाई गई लाइब्रेरी/फ्रेमवर्क को "सही उत्तर" मानकर संस्करण को "स्थिर" करने वाले विकास प्रतिमान में नुकसान अधिक होते हैं।
बाहरी दुनिया लगातार बदल रही है, इसलिए उपयोग की जा रही लाइब्रेरी/फ्रेमवर्क में कमजोरी पाए जाना सामान्य है।
संस्करण को स्थिर करने पर ऐसे परिवर्तनों का पालन नहीं किया जा सकेगा, और परिणामस्वरूप कमजोरी के समाधान में भारी मानसिक/भौतिक लागत चुकानी पड़ेगी।
इसलिए, अब से "परिवर्तन और परिवर्तन का पालन करने में सक्षम होने" को आधार मानने वाले विकास प्रतिमान में बदलाव, दीर्घकालिक रूप से बेहतर परिणाम देगा, ऐसा मैं दृढ़ता से महसूस करता हूं।
लंबा हो गया, लेकिन इतना ही।
----
लेखक: मासाहिको सकामोटो (अनुसंधान और विकास विभाग से संबंधित, कंपनी में उपयोग किए जाने वाले वेब एप्लिकेशन डायग्नोस्टिक टूल के विकास आदि में लगे)
* मेल: [email protected]
* ट्विटर: https://twitter.com/msakamoto_sf
* फेसबुक: https://www.facebook.com/masahiko.sakamoto.75
* गिटहब: https://github.com/msakamoto-sf
इस लेख से संबंधित राय/पूछताछ कृपया सकामोटो से करें।