3
0
Mirror von https://github.com/PaperMC/Velocity.git synchronisiert 2024-11-16 21:10:30 +01:00

Add upfront size checks for some packets.

This is simply a further protection against certain attacks which send malformed packets to the proxy.
Dieser Commit ist enthalten in:
Andrew Steinborn 2021-01-26 12:33:35 -05:00
Ursprung 959e75d16d
Commit 5ceac16a82
6 geänderte Dateien mit 73 neuen und 5 gelöschten Zeilen

Datei anzeigen

@ -11,4 +11,12 @@ public interface MinecraftPacket {
void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion); void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion);
boolean handle(MinecraftSessionHandler handler); boolean handle(MinecraftSessionHandler handler);
default int expectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
return -1;
}
default int expectedMinLength(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
return 0;
}
} }

Datei anzeigen

@ -58,6 +58,8 @@ public class MinecraftDecoder extends ChannelInboundHandlerAdapter {
ctx.fireChannelRead(buf); ctx.fireChannelRead(buf);
} else { } else {
try { try {
doLengthSanityChecks(buf, packet);
try { try {
packet.decode(buf, direction, registry.version); packet.decode(buf, direction, registry.version);
} catch (Exception e) { } catch (Exception e) {
@ -65,7 +67,7 @@ public class MinecraftDecoder extends ChannelInboundHandlerAdapter {
} }
if (buf.isReadable()) { if (buf.isReadable()) {
throw handleNotReadEnough(packet, packetId); throw handleOverflow(packet, buf.readerIndex(), buf.writerIndex());
} }
ctx.fireChannelRead(packet); ctx.fireChannelRead(packet);
} finally { } finally {
@ -74,10 +76,30 @@ public class MinecraftDecoder extends ChannelInboundHandlerAdapter {
} }
} }
private Exception handleNotReadEnough(MinecraftPacket packet, int packetId) { private void doLengthSanityChecks(ByteBuf buf, MinecraftPacket packet) throws Exception {
int expectedMinLen = packet.expectedMinLength(buf, direction, registry.version);
int expectedMaxLen = packet.expectedMaxLength(buf, direction, registry.version);
if (expectedMaxLen != -1 && buf.readableBytes() > expectedMaxLen) {
throw handleOverflow(packet, expectedMaxLen, buf.readableBytes());
}
if (buf.readableBytes() < expectedMinLen) {
throw handleUnderflow(packet, expectedMaxLen, buf.readableBytes());
}
}
private Exception handleOverflow(MinecraftPacket packet, int expected, int actual) {
if (DEBUG) { if (DEBUG) {
return new CorruptedFrameException("Did not read full packet for " + packet.getClass() + " " return new CorruptedFrameException("Packet sent for " + packet.getClass() + " was too "
+ getExtraConnectionDetail(packetId)); + "big (expected " + expected + " bytes, got " + actual + " bytes)");
} else {
return DECODE_FAILED;
}
}
private Exception handleUnderflow(MinecraftPacket packet, int expected, int actual) {
if (DEBUG) {
return new CorruptedFrameException("Packet sent for " + packet.getClass() + " was too "
+ "small (expected " + expected + " bytes, got " + actual + " bytes)");
} else { } else {
return DECODE_FAILED; return DECODE_FAILED;
} }

Datei anzeigen

@ -6,6 +6,7 @@ import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.ProtocolUtils;
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import java.util.Arrays; import java.util.Arrays;
@ -33,7 +34,7 @@ public class EncryptionResponse implements MinecraftPacket {
@Override @Override
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
if (version.compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) { if (version.compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) {
this.sharedSecret = ProtocolUtils.readByteArray(buf, 256); this.sharedSecret = ProtocolUtils.readByteArray(buf, 128);
this.verifyToken = ProtocolUtils.readByteArray(buf, 128); this.verifyToken = ProtocolUtils.readByteArray(buf, 128);
} else { } else {
this.sharedSecret = ProtocolUtils.readByteArray17(buf); this.sharedSecret = ProtocolUtils.readByteArray17(buf);
@ -56,4 +57,16 @@ public class EncryptionResponse implements MinecraftPacket {
public boolean handle(MinecraftSessionHandler handler) { public boolean handle(MinecraftSessionHandler handler) {
return handler.handle(this); return handler.handle(this);
} }
@Override
public int expectedMaxLength(ByteBuf buf, Direction direction, ProtocolVersion version) {
// It turns out these come out to the same length, whether we're talking >=1.8 or not.
// The length prefix always winds up being 2 bytes.
return 260;
}
@Override
public int expectedMinLength(ByteBuf buf, Direction direction, ProtocolVersion version) {
return expectedMaxLength(buf, direction, version);
}
} }

Datei anzeigen

@ -5,6 +5,7 @@ import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.ProtocolUtils;
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
import com.velocitypowered.proxy.util.except.QuietDecoderException; import com.velocitypowered.proxy.util.except.QuietDecoderException;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
@ -52,6 +53,13 @@ public class ServerLogin implements MinecraftPacket {
ProtocolUtils.writeString(buf, username); ProtocolUtils.writeString(buf, username);
} }
@Override
public int expectedMaxLength(ByteBuf buf, Direction direction, ProtocolVersion version) {
// Accommodate the rare (but likely malicious) use of UTF-8 usernames, since it is technically
// legal on the protocol level.
return 1 + (16 * 4);
}
@Override @Override
public boolean handle(MinecraftSessionHandler handler) { public boolean handle(MinecraftSessionHandler handler) {
return handler.handle(this); return handler.handle(this);

Datei anzeigen

@ -4,6 +4,7 @@ import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.ProtocolUtils;
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
public class StatusPing implements MinecraftPacket { public class StatusPing implements MinecraftPacket {
@ -24,4 +25,14 @@ public class StatusPing implements MinecraftPacket {
public boolean handle(MinecraftSessionHandler handler) { public boolean handle(MinecraftSessionHandler handler) {
return handler.handle(this); return handler.handle(this);
} }
@Override
public int expectedMaxLength(ByteBuf buf, Direction direction, ProtocolVersion version) {
return 8;
}
@Override
public int expectedMinLength(ByteBuf buf, Direction direction, ProtocolVersion version) {
return 8;
}
} }

Datei anzeigen

@ -4,6 +4,7 @@ import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.ProtocolUtils;
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
public class StatusRequest implements MinecraftPacket { public class StatusRequest implements MinecraftPacket {
@ -33,4 +34,9 @@ public class StatusRequest implements MinecraftPacket {
public boolean handle(MinecraftSessionHandler handler) { public boolean handle(MinecraftSessionHandler handler) {
return handler.handle(this); return handler.handle(this);
} }
@Override
public int expectedMaxLength(ByteBuf buf, Direction direction, ProtocolVersion version) {
return 0;
}
} }