Skip to content

Commit

Permalink
HTTP: Ensure url path expansion only works inside of plugins
Browse files Browse the repository at this point in the history
This prevents reading of files that are not part of the plugin
directory by specifically crafted paths.
  • Loading branch information
spinscale committed Apr 27, 2015
1 parent 9745808 commit 5d8e9e2
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 6 deletions.
11 changes: 5 additions & 6 deletions src/main/java/org/elasticsearch/http/HttpServer.java
Expand Up @@ -177,11 +177,13 @@ void handlePluginSite(HttpRequest request, HttpChannel channel) throws IOExcepti
sitePath = sitePath.replace("/", separator);
// this is a plugin provided site, serve it as static files from the plugin location
Path file = FileSystemUtils.append(siteFile, PathUtils.get(sitePath), 0);
if (!Files.exists(file) || Files.isHidden(file)) {

// return not found instead of forbidden to prevent malicious requests to find out if files exist or dont exist
if (!Files.exists(file) || Files.isHidden(file) || !file.toAbsolutePath().normalize().startsWith(siteFile.toAbsolutePath())) {
channel.sendResponse(new BytesRestResponse(NOT_FOUND));
return;
}

BasicFileAttributes attributes = Files.readAttributes(file, BasicFileAttributes.class);
if (!attributes.isRegularFile()) {
// If it's not a dir, we send a 403
Expand All @@ -196,10 +198,7 @@ void handlePluginSite(HttpRequest request, HttpChannel channel) throws IOExcepti
return;
}
}
if (!file.toAbsolutePath().startsWith(siteFile.toAbsolutePath())) {
channel.sendResponse(new BytesRestResponse(FORBIDDEN));
return;
}

try {
byte[] data = Files.readAllBytes(file);
channel.sendResponse(new BytesRestResponse(OK, guessMimeType(sitePath), data));
Expand Down
31 changes: 31 additions & 0 deletions src/test/java/org/elasticsearch/plugins/SitePluginTests.java
Expand Up @@ -34,6 +34,9 @@
import java.net.URISyntaxException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import static org.elasticsearch.common.settings.ImmutableSettings.settingsBuilder;
import static org.elasticsearch.test.ElasticsearchIntegrationTest.Scope;
Expand Down Expand Up @@ -86,6 +89,34 @@ public void testAnyPage() throws Exception {
assertThat(response.getBody(), containsString("<title>Dummy Site Plugin</title>"));
}

/**
* Test normalizing of path
*/
@Test
public void testThatPathsAreNormalized() throws Exception {
// more info: https://www.owasp.org/index.php/Path_Traversal
List<String> notFoundUris = new ArrayList<>();
notFoundUris.add("/_plugin/dummy/../../../../../log4j.properties");
notFoundUris.add("/_plugin/dummy/../../../../../%00log4j.properties");
notFoundUris.add("/_plugin/dummy/..%c0%af..%c0%af..%c0%af..%c0%af..%c0%aflog4j.properties");
notFoundUris.add("/_plugin/dummy/%2E%2E/%2E%2E/%2E%2E/%2E%2E/index.html");
notFoundUris.add("/_plugin/dummy/%2e%2e/%2e%2e/%2e%2e/%2e%2e/index.html");
notFoundUris.add("/_plugin/dummy/%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2findex.html");
notFoundUris.add("/_plugin/dummy/%2E%2E/%2E%2E/%2E%2E/%2E%2E/index.html");
notFoundUris.add("/_plugin/dummy/..\\..\\..\\..\\..\\log4j.properties");

for (String uri : notFoundUris) {
HttpResponse response = httpClient().path(uri).execute();
String message = String.format(Locale.ROOT, "URI [%s] expected to be not found", uri);
assertThat(message, response.getStatusCode(), equalTo(RestStatus.NOT_FOUND.getStatus()));
}

// using relative path inside of the plugin should work
HttpResponse response = httpClient().path("/_plugin/dummy/dir1/../dir1/../index.html").execute();
assertThat(response.getStatusCode(), equalTo(RestStatus.OK.getStatus()));
assertThat(response.getBody(), containsString("<title>Dummy Site Plugin</title>"));
}

/**
* Test case for #4845: https://github.com/elasticsearch/elasticsearch/issues/4845
* Serving _site plugins do not pick up on index.html for sub directories
Expand Down
Empty file.

0 comments on commit 5d8e9e2

Please sign in to comment.