Skip to content

Commit 55b890f

Browse files
committed
HTTP: Ensure url path expansion only works inside of plugins
This prevents reading of files that are not part of the plugin directory by specifically crafted paths.
1 parent 6226914 commit 55b890f

File tree

3 files changed

+34
-5
lines changed

3 files changed

+34
-5
lines changed

src/main/java/org/elasticsearch/http/HttpServer.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -174,10 +174,11 @@ void handlePluginSite(HttpRequest request, HttpChannel channel) {
174174
// this is a plugin provided site, serve it as static files from the plugin location
175175
File siteFile = new File(new File(environment.pluginsFile(), pluginName), "_site");
176176
File file = new File(siteFile, sitePath);
177-
if (!file.exists() || file.isHidden()) {
177+
if (!file.exists() || file.isHidden() || !file.getAbsoluteFile().toPath().normalize().startsWith(siteFile.getAbsoluteFile().toPath())) {
178178
channel.sendResponse(new BytesRestResponse(NOT_FOUND));
179179
return;
180180
}
181+
181182
if (!file.isFile()) {
182183
// If it's not a dir, we send a 403
183184
if (!file.isDirectory()) {
@@ -191,10 +192,7 @@ void handlePluginSite(HttpRequest request, HttpChannel channel) {
191192
return;
192193
}
193194
}
194-
if (!file.getAbsolutePath().startsWith(siteFile.getAbsolutePath())) {
195-
channel.sendResponse(new BytesRestResponse(FORBIDDEN));
196-
return;
197-
}
195+
198196
try {
199197
byte[] data = Streams.copyToByteArray(file);
200198
channel.sendResponse(new BytesRestResponse(OK, guessMimeType(sitePath), data));

src/test/java/org/elasticsearch/plugins/SitePluginTests.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@
3232

3333
import java.io.File;
3434
import java.net.URISyntaxException;
35+
import java.util.ArrayList;
36+
import java.util.List;
37+
import java.util.Locale;
3538

3639
import static org.elasticsearch.common.settings.ImmutableSettings.settingsBuilder;
3740
import static org.elasticsearch.test.ElasticsearchIntegrationTest.Scope;
@@ -88,6 +91,34 @@ public void testAnyPage() throws Exception {
8891
assertThat(response.getBody(), containsString("<title>Dummy Site Plugin</title>"));
8992
}
9093

94+
/**
95+
* Test normalizing of path
96+
*/
97+
@Test
98+
public void testThatPathsAreNormalized() throws Exception {
99+
// more info: https://www.owasp.org/index.php/Path_Traversal
100+
List<String> notFoundUris = new ArrayList<>();
101+
notFoundUris.add("/_plugin/dummy/../../../../../log4j.properties");
102+
notFoundUris.add("/_plugin/dummy/../../../../../%00log4j.properties");
103+
notFoundUris.add("/_plugin/dummy/..%c0%af..%c0%af..%c0%af..%c0%af..%c0%aflog4j.properties");
104+
notFoundUris.add("/_plugin/dummy/%2E%2E/%2E%2E/%2E%2E/%2E%2E/index.html");
105+
notFoundUris.add("/_plugin/dummy/%2e%2e/%2e%2e/%2e%2e/%2e%2e/index.html");
106+
notFoundUris.add("/_plugin/dummy/%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2findex.html");
107+
notFoundUris.add("/_plugin/dummy/%2E%2E/%2E%2E/%2E%2E/%2E%2E/index.html");
108+
notFoundUris.add("/_plugin/dummy/..\\..\\..\\..\\..\\log4j.properties");
109+
110+
for (String uri : notFoundUris) {
111+
HttpResponse response = httpClient().path(uri).execute();
112+
String message = String.format(Locale.ROOT, "URI [%s] expected to be not found", uri);
113+
assertThat(message, response.getStatusCode(), equalTo(RestStatus.NOT_FOUND.getStatus()));
114+
}
115+
116+
// using relative path inside of the plugin should work
117+
HttpResponse response = httpClient().path("/_plugin/dummy/dir1/../dir1/../index.html").execute();
118+
assertThat(response.getStatusCode(), equalTo(RestStatus.OK.getStatus()));
119+
assertThat(response.getBody(), containsString("<title>Dummy Site Plugin</title>"));
120+
}
121+
91122
/**
92123
* Test case for #4845: https://github.com/elasticsearch/elasticsearch/issues/4845
93124
* Serving _site plugins do not pick up on index.html for sub directories

src/test/resources/org/elasticsearch/plugins/dummy/_site/dir1/.empty

Whitespace-only changes.

0 commit comments

Comments
 (0)