PaperMC / PaperMC/Velocity

Decompression attack in `MinecraftCompressDecoder#decode`

Open
#1,742 22 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

type: bug
Dominant language
Java
Stars
2.3k
Forks
959
Avg merge
5d 10h
Merged PRs (30d)
2

Description

Proxies of a large network I'm working for were constantly being restarted due to OOM kills. I highly suspect this is due to a malicious decompression attack.

I had added the following logs in MinecraftCompressDecoder#decode:

if (claimedUncompressedSize > UNCOMPRESSED_CAP * 0.95) {
  LOGGER.warn("Received a packet with a large uncompressed size: {} bytes ({}% of the {} byte cap) from {}",
      claimedUncompressedSize,
      (int) (claimedUncompressedSize * 100.0 / UNCOMPRESSED_CAP),
      UNCOMPRESSED_CAP,
      ctx.channel().remoteAddress());
}

When we were under attack we got spammed by the following logs:

[17:36:45 WARN]: Received a packet with a large uncompressed size: 8380416 bytes (99% of the 8388608 byte cap) from /x.x.x.x:16643

All from the same IP address, all with the same packet size. Moments later the proxy got OOM killed.

When we blacklisted this IP at the firewall level the proxies stayed alive.

I've implemented the following fix on a fork to try to block these kinds of attacks, at least on the short term: https://github.com/GemstoneGG/Velocity-CTD/commit/3fd2f11b3b35d066f2ee064e1f4b7c785b709997
However the limits (0.95 * UNCOMPRESSED_CAP and MAX_COMPRESSION_RATIO = 1024) are not really based on anything. Since we're running the fork with this commit we haven't been attacked again, so I'm not sure if the commit prevents the attack. Luckily, legitimate connections aren't being affected.

-Dvelocity.increased-compression-cap=true is NOT set, so the UNCOMPRESSED_CAP is 8MB.
Decompressing a really small packet to 8MB over and over again ideally shouldn't OOM kill a proxy. I wonder if the proper fix for this is a "rate-limiter" approach like in my temporary-ish fix commit, or to take a closer look at why allocating "just" 8MB constantly gets an OOM kill. Something might be going wrong with (de)allocating this buffer.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with MinecraftCompressDecoder#decode and compare its behavior with the proposed fork commit 3fd2f11b3b35d066f2ee064e1f4b7c785b709997. Investigate repeated small packets claiming near the 8 MB uncompressed cap, including allocation and release behavior. Done means the proxy no longer risks OOM under this attack while legitimate compressed connections remain unaffected.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
networking
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.