Minecraft is a survival game published by Mojang, owned by Microsoft. When you start playing, you don’t have anything and you must break blocks (”mine”) and build structures and craft objects to progress. We usually call this genre “sandboxing game”, but ironically we can’t say the same when it comes to security.

Minecraft can be played in Singleplayer, Multiplayer and on Realms. Realms is the multiplayer version hosted by Mojang. The flaw we describe only targets Multiplayer, where servers are controlled by third parties.

The 1.8 version, released on September 2, 2014, introduces Resource packs, custom images and sounds to use when rendering the world. Two packets were introduced in the Minecraft protocol: Resource Pack Send and Resource Pack Status.

The associated code looks like this:

public void handle(S48PacketResourcePackSend packet) {
  String url = packet.getUrl();
  String hash = packet.getHash();
  
  if (url.startsWith("level://")) {
    String urlWithoutPrefix = url.substring("level://".length());
    File savesDirectory = new File(gameController.mcDataDir, "saves");
    File resourceFile = new File(savesDirectory, urlWithoutPrefix);
    
    if (resourceFile.isFile()) {
    	netManager.sendPacket(new C19PacketResourcePackStatus(hash, Action.ACCEPTED));
	// snip, loading the resource.
    } else {
    	this.netManager.sendPacket(new C19PacketResourcePackStatus(hash, Action.FAILED_DOWNLOAD));
    }
  } else {
    // snip, handling URLs.
  }
}

To trigger the exploit, servers simply need to send a Resource Pack Send packet using a URL that starts with level://. The game will try to load that file from the saves directory. If the file exists, a packet with status ACCEPTED is sent. If not, a packet FAILED_DOWNLOAD is sent instead.

Traversing directories is also possible using ../, putting the whole computer’s data at risk. Servers can check if a file exists on the player’s computer, enumerate users names … but maybe even worse. See PHP’s issue with file_exists and phar files.

This exploit is invisible from the player’s perspective and can be triggered at any time while playing on a server. This exploit can be automated and accelerated by sending the packet in batch, the server knows that the responses will follow the same order. Even better, the client is generous enough to send back the hash – which is conveniently sent by the server, and can just be the checked path itself.

As pointed out by SirUnkn0wn, the launcher_log.txt contains the successful exploit attempts: [0913/140810:INFO:GameCallbacks.cpp(199)] game/bns (Client thread) warn Unable to parse metadata section of resourcepack: servers.dat java.util.zip.ZipException: error in opening zip file.

In the 1.9 version, released on February 29 (2016), a condition was added to make sure this exploit is prevented: the level:// protocol can’t use .. to go up in directories, and the /resources.zip suffix must be used. The status packet was also evolved to only send the status, and not the hash, making it a bit harder to parallelize the attack.

private boolean validateResourcePackUrl(String url) {
  try {
    URI uri = new URI(url);
    String scheme = uri.getScheme();
    boolean isLevelProtocol = "level".equals(scheme);
    boolean isHttpProtocol = "http".equals(scheme);
    boolean isHttpsProtocol = "https".equals(scheme);

    if (!isHttpProtocol && !isHttpsProtocol && !isLevelProtocol) {
      throw new URISyntaxException(url, "Wrong protocol");
    }
    
    if (isLevelProtocol && (url.contains("..") || !url.endsWith("/resources.zip"))) {
      throw new URISyntaxException(url, "Invalid levelstorage resourcepack path");
    }
    
    return true;
  } catch (URISyntaxException e) {
    netManager.sendPacket(new CPacketResourcePackStatus(Action.FAILED_DOWNLOAD));
    return false;
  }
}

This security issue was fixed silently by Mojang, and no patches were made to the 1.8 version of the game. 4 years later, thousands of players still use the 1.8 version of the game - or a fork of it - and could suffer from this exploit. I haven’t seen any publicly available code taking advantage of this exploit.

Mojang once replied to the Minecraft Java Edition Skins Issue outlined by Avast, but missed the chance to communicate about the Resource Pack flaw, sadly.

PS: This also allows servers to check if cheats or mods are installed on the player’s computer, but I advise you not to. Doing so would be illegal!


Summary
Affected product: Minecraft by Mojang.
Affected platforms: Windows, Linux, macOS.
Affected versions: 1.8 - 1.8.9, 1.9 and above are not affected.
Security issue: In multiplayer mode, servers can check if given files exist on the player’s computer without them knowing.

Solutions:
Update Minecraft.
If you really want to play 1.8, only play on servers you trust, or install the Forge mod made by Sk1er (thanks!): download it and place it in your mods/ directory. The source code is available here.

Source for the protocol: wiki.vg