The Endergetic Expansion

The Endergetic Expansion

25M Downloads

Arbitrary Item Creation via Client Trust Exploitation

pau101 opened this issue ยท 14 comments

commented

As it stands, the Boolfo Vest performs its "Boof" action though client commanded item stack manipulation, entity knockback, and particle creation with respective network messages SUpdateNBTTagMessage, SBoofEntityMessage, and MessageC2S2CSpawnParticle. These can be exploited with specially crafted packets to give the player arbitrary items, apply unrestricted entity knockback, and produce arbitrary particle effects.

In addition, a malicious client may control the "Inflate", "Boost", and "Slam" of any booflo regardless of player riding and intended restrictions, as per messages in package network/entity/booflo.

The common thread of these vulnerable packets is exploitable client trust. For each key binding triggered action the client should signal the user wishes to perform such to the server, for which the server determines if permissible and to carry out only if so. Information which the server may infer should not be controlled by the client, such as the booflo which the player is currently riding, as the player should not have authority over other player's booflos.

I can provide further exploit explanation and mitigation assistance as needed.

commented

I had a feeling these packets could be exploitable in some ways. I'll get into mitigating/fixing these issues as soon as possible.
There are some ways of mitigation I can think of for these exploits already, and some of them are pretty simple. But I'm also interested in any ideas you have for reducing these exploits.

commented

In my third paragraph I give the outline of how I envision the fix, the packets need to be largely removed and replaced, as none of the vulnerabilities are a matter of logical errors alone in the server packet handlers, it is simply the design of the packet/surrounding implementation that is wrong.

commented

The root of the first three exploits is this code here which is client side, which should be sever side but instead currently relying on client trust:

public static void onKeyPressed(KeyInputEvent event) {
if (Minecraft.getInstance().currentScreen != null) return;
PlayerEntity player = Minecraft.getInstance().player;
if (player == null) return;
if (BOOF_VEST.isPressed()) {
Random rand = player.getRNG();
ItemStack stack = player.inventory.armorItemInSlot(2);
if (!stack.isEmpty() && stack.getItem() == EEItems.BOOFLO_VEST.get() && !player.isOnGround() && !player.isSpectator()) {
BoofloVestItem vest = (BoofloVestItem) stack.getItem();
if (vest.canBoof(stack, player)) {
CompoundNBT tag = stack.getTag();
tag.putBoolean(BoofloVestItem.BOOFED_TAG, true);
tag.putInt(BoofloVestItem.TIMES_BOOFED_TAG, tag.getInt(BoofloVestItem.TIMES_BOOFED_TAG) + 1);
vest.setDelayForBoofedAmount(stack, player);
EndergeticNetworkUtil.updateSItemNBT(stack);
EntityMotionHelper.knockbackEntity(player, 4.0F, 0.75F, true, true);
for (Entity entity : player.getEntityWorld().getEntitiesWithinAABB(Entity.class, player.getBoundingBox().grow(2.0D))) {
if (entity != player && !EETags.EntityTypes.BOOF_BLOCK_RESISTANT.contains(entity.getType())) {
boolean reverse = player.getRidingEntity() == entity;
EntityMotionHelper.knockbackEntity(entity, 4.0F, 0.75F, reverse, false);
}
}
for (int i = 0; i < 8; i++) {
double x = player.getPosX() + MathUtils.makeNegativeRandomly(rand.nextFloat() * 0.15F, rand);
double y = player.getPosY() + (rand.nextFloat() * 0.05F) + 1.25F;
double z = player.getPosZ() + MathUtils.makeNegativeRandomly(rand.nextFloat() * 0.15F, rand);
NetworkUtil.spawnParticleC2S2C("endergetic:short_poise_bubble", x, y, z, MathUtils.makeNegativeRandomly((rand.nextFloat() * 0.3F), rand) + 0.025F, (rand.nextFloat() * 0.15F) + 0.1F, MathUtils.makeNegativeRandomly((rand.nextFloat() * 0.3F), rand) + 0.025F);
}
player.playSound(EESounds.BOOFLO_VEST_INFLATE.get(), 1.0F, MathHelper.clamp(1.3F - (tag.getInt(BoofloVestItem.TIMES_BOOFED_TAG) * 0.15F), 0.25F, 1.0F));
EndergeticNetworkUtil.SBoofEntity(4.0F, 0.75F, 2);
}
}
}
if (BOOFLO_INFLATE.isKeyDown()) {
Entity ridingEntity = player.getRidingEntity();
if (KeybindHandler.isRidingBooflo(player) && !((BoofloEntity) ridingEntity).isOnGround()) {
BoofloEntity booflo = (BoofloEntity) ridingEntity;
if (booflo.isBoofed() && booflo.canPassengerSteer()) {
if (!booflo.isDelayDecrementing() && !booflo.isDelayExpanding() && booflo.getRideControlDelay() <= 182) {
if (booflo.getRideControlDelay() >= 182) {
EndergeticNetworkUtil.setPlayerNotBoosting(booflo.getEntityId());
} else {
EndergeticNetworkUtil.incrementBoofloBoostTimer(booflo.getEntityId());
}
}
} else if (!booflo.isBoofed() && booflo.canPassengerSteer()) {
if (booflo.getRideControlDelay() <= 0) {
EndergeticNetworkUtil.inflateBooflo(booflo.getEntityId());
}
}
}
} else {
if (KeybindHandler.isRidingBooflo(player)) {
Entity ridingEntity = player.getRidingEntity();
BoofloEntity booflo = (BoofloEntity) ridingEntity;
if (booflo.isBoofed()) {
if (!booflo.isDelayDecrementing() && !booflo.isDelayExpanding() && booflo.wasPlayerBoosting()) {
EndergeticNetworkUtil.setPlayerNotBoosting(booflo.getEntityId());
}
}
}
}
if (BOOFLO_SLAM.isPressed()) {
Entity ridingEntity = player.getRidingEntity();
if (KeybindHandler.isRidingBooflo(player)) {
BoofloEntity booflo = (BoofloEntity) ridingEntity;
if (booflo.isBoofed() && booflo.getRideControlDelay() <= 0 && booflo.isNoEndimationPlaying()) {
EndergeticNetworkUtil.slamBooflo(booflo.getEntityId());
}
}
}
}

commented

Right, I noticed that.

commented

Looks good so far.

commented

Commit e268ed1 should resolve exploitation issues related to the Booflo Vest.

commented

The same case now in commit 523ce84, but for the Booflo riding packets.

commented

All appears to be in order, and I did verify team-abnormals/blueprint@c97c49c covers packet over there.

commented

That should be all the packet exploits fixed now. Let me know if you still see any.

commented

Can we expect a 1.15 patch as well?

commented

Unfortunately not, we don't release new builds for 1.15.2 anymore.

commented

I strongly encourage security patches for at least one major version behind current. There are public servers vulnerable to this issue, one of which is what led me to discovering this issue.

commented

That's a fair point, and I will make an exception for releasing a new 1.15.2 build for this.
But we are not focusing on versions before 1.16.1, so a patch for this would not likely come from us anytime soon.
If you need this 1.15.2 patch fast, I am happy to review and merge a PR to the 1.15.2 branch from you that fixes these exploits.

commented

Alright a PR is in the works.