idekCTF 2024 minecraft - HACKED WP

Minecraft - HACKED:

By JoshL

You might remember the cat coordinate exploit used to find LiveOverflow. Well, pumpkin steve has captured LiveOverflow, and it is your job to find LiveOverflow again. But this time he left something else behind…

PLEASE TEST YOUR SOLVE LOCALLY BEFORE STARTING AN INSTANCE After starting the instancer, run socat tcp-listen:25565,fork,reuseaddr openssl:<REMOTE_HOST_HERE>:1337 and join the server on localhost:25565

Instancer

minecraft-hacked.tar.gz

这是主要代码

Here is the main code

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
package com.challenge;

import carpet.CarpetExtension;
import carpet.CarpetServer;
import carpet.api.settings.SettingsManager;
import carpet.fakes.ServerPlayerEntityInterface;
import carpet.helpers.EntityPlayerActionPack;
import carpet.utils.Messenger;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.fabricmc.api.ModInitializer;

import net.minecraft.block.BlockState;
import net.minecraft.block.pattern.CachedBlockPosition;
import net.minecraft.command.CommandRegistryAccess;
import net.minecraft.command.argument.BlockPosArgumentType;
import net.minecraft.command.argument.Vec3ArgumentType;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.projectile.ArrowEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.*;
import net.minecraft.world.GameMode;
import net.minecraft.world.GameRules;
import net.minecraft.world.TeleportTarget;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


import java.util.List;

import static net.minecraft.server.command.CommandManager.argument;
import static net.minecraft.server.command.CommandManager.literal;

public class Challenge implements CarpetExtension, ModInitializer {
   // This logger is used to write text to the console and the log file.
   // It is considered best practice to use your mod id as the logger's name.
   // That way, it's clear which mod wrote info, warnings, and errors.
    public static final Logger LOGGER = LoggerFactory.getLogger("Challenge");
   private static SettingsManager mySettingManager;
   private int bowInUse = 0;
   private boolean hasBow = false;
   private ServerPlayerEntity chalCaller;
   static {
      mySettingManager = new SettingsManager("1.0", "Challenge", "Challenge Mod");
      CarpetServer.manageExtension(new Challenge());
   }

   @Override
   public void onInitialize() {
   }

   @Override
   public void onGameStarted() {

   }

   @Override
   public void onServerLoaded(MinecraftServer server) {
   }

   @Override
   public void onTick(MinecraftServer server) {
      if(bowInUse > 0){
         ServerPlayerEntity ctfplayer = server.getPlayerManager().getPlayer("LiveOverflow");
         assert ctfplayer != null;
         if(bowInUse == 1){
            List<ArrowEntity> entities = ctfplayer.getWorld().getEntitiesByType(EntityType.ARROW, new Box(ctfplayer.getBlockPos()).expand(10), e -> e.getOwner().equals(ctfplayer));
            for(ArrowEntity entity: entities){
               entity.teleport(chalCaller.getX(), chalCaller.getY(), chalCaller.getZ());
            }
         }else if(bowInUse == 2){
            ((ServerPlayerEntityInterface)ctfplayer).getActionPack().stopAll();
         }
         bowInUse -= 1;
      }
   }

   public static BlockPos convert(Vec3d vec3d) {
      Vec3i vec = new Vec3i((int)Math.floor(vec3d.x), (int)Math.floor(vec3d.y), (int)Math.floor(vec3d.z));
      return new BlockPos(vec);
   }

   private int executeClone(CommandContext<ServerCommandSource> ctx) throws CommandSyntaxException {
      ServerWorld world = ctx.getSource().getWorld();
      BlockPos src1 = BlockPosArgumentType.getBlockPos(ctx, "src1");
      BlockPos src2 = BlockPosArgumentType.getBlockPos(ctx, "src2");
      BlockPos dst = BlockPosArgumentType.getBlockPos(ctx, "dst");
      BlockBox blockBox = BlockBox.create(src1, src2);
      BlockBox blockBox2 = BlockBox.create(dst, dst.add(blockBox.getDimensions()));
      if (blockBox.intersects(blockBox2)) {
         Messenger.m(ctx.getSource(), "r Boxes intersect");
         return 0;
      }

      int sz = blockBox.getBlockCountX() * blockBox.getBlockCountY() * blockBox.getBlockCountZ();
      if (sz > 32768) {
         Messenger.m(ctx.getSource(), "r Clone volume is too large");
         return 0;
      }

      BlockPos offset = new BlockPos(
            blockBox2.getMinX() - blockBox.getMinX(),
            blockBox2.getMinY() - blockBox.getMinY(),
            blockBox2.getMinZ() - blockBox.getMinZ()
      );
      for (int i = blockBox.getMinZ(); i <= blockBox.getMaxZ(); i++) {
         for (int j = blockBox.getMinY(); j <= blockBox.getMaxY(); j++) {
            for (int k = blockBox.getMinX(); k <= blockBox.getMaxX(); k++) {
               BlockPos srcBlock = new BlockPos(k, j, i);
               BlockPos dstBlock = srcBlock.add(offset);
               CachedBlockPosition cachedBlockPosition = new CachedBlockPosition(world, srcBlock, false);
               BlockState blockState = cachedBlockPosition.getBlockState();
               if(blockState == null) {
                  Messenger.m(ctx.getSource(), "r Region is unloaded");
                  return 0;
               }
               world.setBlockState(dstBlock, blockState, 2);
            }
         }
      }
      return 1;
   }

   private int executeChal(CommandContext<ServerCommandSource> ctx) {
      if(bowInUse != 0){
         Messenger.m(ctx.getSource(), "r Challenge currently running");
         return 0;
      }
      ServerPlayerEntity player = ctx.getSource().getPlayer();
      chalCaller = player;
      assert player != null;
      Vec3d pos = player.getPos();
      ServerWorld world = ctx.getSource().getWorld();
      MinecraftServer server = ctx.getSource().getServer();
      ServerPlayerEntity ctfplayer = server.getPlayerManager().getPlayer("LiveOverflow");
      assert ctfplayer != null;
      if(!hasBow) {
         ctfplayer.giveItemStack(new ItemStack(Items.BOW));
         ctfplayer.giveItemStack(new ItemStack(Items.ARROW));
         hasBow = true;
      }
      ((ServerPlayerEntityInterface)ctfplayer).getActionPack().start(EntityPlayerActionPack.ActionType.USE, EntityPlayerActionPack.Action.continuous());
      bowInUse = 20;
      return 1;
   }

   @Override
   public void registerCommands(CommandDispatcher<ServerCommandSource> dispatcher, final CommandRegistryAccess commandBuildContext) {
      LiteralArgumentBuilder<ServerCommandSource> cmd;
      cmd = literal("tp2"). // Create a tp command
            requires(ServerCommandSource::isExecutedByPlayer).
            then(argument("position", Vec3ArgumentType.vec3()).
            executes( (ctx) -> {
               ServerPlayerEntity player = ctx.getSource().getPlayer();
                    assert player != null;
               Vec3d pos = Vec3ArgumentType.getVec3(ctx, "position");
               player.teleport(player.getWorld(), pos.x, pos.y, pos.z, player.getYaw(), player.getPitch());
               return 1;
            }));
      dispatcher.register(cmd);

      cmd = literal("gmc").
            requires(ServerCommandSource::isExecutedByPlayer).
            executes( (ctx) -> {
               ServerPlayerEntity player = ctx.getSource().getPlayer();
                    assert player != null;
                    player.changeGameMode(GameMode.CREATIVE);
               return 1;
            });
      dispatcher.register(cmd);

      cmd = literal("gms").
            requires(ServerCommandSource::isExecutedByPlayer).
            executes( (ctx) -> {
               ServerPlayerEntity player = ctx.getSource().getPlayer();
               assert player != null;
               player.changeGameMode(GameMode.SURVIVAL);
               return 1;
            });
      dispatcher.register(cmd);

      cmd = literal("clone2").
            requires(ServerCommandSource::isExecutedByPlayer).
            then(argument("src1", BlockPosArgumentType.blockPos()).
            then(argument("src2", BlockPosArgumentType.blockPos()).
            then(argument("dst", BlockPosArgumentType.blockPos()).
            executes(this::executeClone))));
      dispatcher.register(cmd);

      cmd = literal("chal").
            requires(ServerCommandSource::isExecutedByPlayer).
            executes(this::executeChal);
      dispatcher.register(cmd);
   }

   @Override
   public SettingsManager extensionSettingsManager() {
      // this will ensure that our settings are loaded properly when world loads
      return mySettingManager;
   }

   @Override
   public void onPlayerLoggedIn(ServerPlayerEntity player) {
      LOGGER.info("Hello Carpet Mod. Someone joined!");
   }

   @Override
   public void onPlayerLoggedOut(ServerPlayerEntity player) {
      //
   }
}

简单看一下

Take a look.

LiveOverflow会在服务器创建的时候,在[-100000,100000],200,[-100000,100000]随机刷新

flag就生成在他脚下的OAK_SIGN

LiveOverflow will randomly refresh the server at [-100000,100000],200,[-100000,100000] when it is created.

The flag is generated at the foot of OAK_SIGN.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
Random random = new Random();
		int bounds = 100000;
		int x = random.nextInt(-bounds,bounds);
		int y = 200;
		int z = random.nextInt(-bounds,bounds);
		BlockPos goalPos = new BlockPos(x, y, z);
		EntityPlayerMPFake.createFake(
			"LiveOverflow",
			server,
			goalPos.getX(), goalPos.getY(), goalPos.getZ(),
			0, 90,
			server.getOverworld().getRegistryKey(),
			GameMode.CREATIVE,
			true
		);

题目的mod注册几个命令:tp2gmcgmsclone2chal

其中chal命令会让LiveOverflow射出一根箭,并传送到的身上

The mod of the topic registers several commands: tp2, gmc, gms, clone2, chal.

One of these commands, chal, causes LiveOverflow to shoot an arrow and teleport it to me

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
	public void onTick(MinecraftServer server) {
		if(bowInUse > 0){
			ServerPlayerEntity ctfplayer = server.getPlayerManager().getPlayer("LiveOverflow");
			assert ctfplayer != null;
			if(bowInUse == 1){
				List<ArrowEntity> entities = ctfplayer.getWorld().getEntitiesByType(EntityType.ARROW, new Box(ctfplayer.getBlockPos()).expand(10), e -> e.getOwner().equals(ctfplayer));
				for(ArrowEntity entity: entities){
					entity.teleport(chalCaller.getX(), chalCaller.getY(), chalCaller.getZ());
				}
			}else if(bowInUse == 2){
				((ServerPlayerEntityInterface)ctfplayer).getActionPack().stopAll();
			}
			bowInUse -= 1;
		}
	}

但是这个箭搞不懂怎么利用,它又不需要朝向Owner

浪费半天,抓的包用不上

But I can’t figure out how to use this arrow. It doesn’t need to be facing the Owner.

Waste of time. I can’t use the packet I grabbed.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
{
  "entityId": 1022,
  "objectUUID": "b9cb9a83-2c0a-4333-a7e5-0713ee64645b",
  "type": 3,
  "x": 39.43528277374672,
  "y": 317.28868964835226,
  "z": 6.067703714599523,
  "pitch": -64,
  "yaw": -65,
  "headPitch": 0,
  "objectData": 142,
  "velocityX": -46,
  "velocityY": -21170,
  "velocityZ": 0
}

{
  "entityId": 1021,
  "objectUUID": "59fc7ac2-6b18-471a-ab0e-bca7b36ed2ae",
  "type": 3,
  "x": 39.43528277374672,
  "y": 317.28868964835226,
  "z": 6.067703714599523,
  "pitch": -64,
  "yaw": 95,
  "headPitch": 0,
  "objectData": 142,
  "velocityX": 132,
  "velocityY": -21010,
  "velocityZ": -130
}

这是我同一个位置,连续抓的两个箭的数据

yaw ,vx,vy,vz 完全没有规律

This is the data of two arrows I caught in the same position, consecutively

The variation of yaw ,vx,vy,vz is not regular at all.

箭有一个效果,击中实体后,实体会按照反方向弹射

经测试 ,这个效果在远隔上万格的距离,也生效

The arrow has an effect that when it hits an entity, the entity will bounce in the opposite direction.

This effect has been tested to work even at a distance of tens of thousands of frames.

img

img

1
2
3
4
5
6
7
{
  "entityId": 1075,
  "dX": 145,
  "dY": 0,
  "dZ": 53,
  "onGround": true
}

实体收到攻击后,大概是这个值的变化

After the entity receives an attack, roughly this value changes

反正不如直接在游戏里根据实体位置的变化 来计算位置

tp2+二分法去追踪。clone2应该是用于快速的复制一个已经存在的平台用于放实体查看伤害

不过我选了一个不会主动移动的实体:鱿鱼(发光鱿鱼晚上也能看清)

Anyway, it’s better to just calculate the position in the game based on the change in entity position

tp2 + dichotomy to track. clone2 is supposed to be used to quickly duplicate an already existing platform for placing entities to see damage

But I picked an entity that doesn’t actively move: squid (glowing squid can be seen at night)

img

多次tp2就能到达目标了

Multiple tp2’s will get you there.

img

0%