aCis


Beginning of the cycle 380-389. Current focus : exploit fixes, scripts ending. Changeset 380 (1133) is up !

EnterWorld exploit fix - ALL L2J versions

Tryskell · 1 · 2834

Offline Tryskell

  • The cute dwarf
  • *
    • Posts: 3.881
    • Cookies: +34/-2
on: February 25, 2019, 01:15:50 PM
Short version : upon L2PHX (or any packet manipulation tool) use, the manual or automatic send of EnterWorld packet creates issues (for example, if the config spawn protection is activated, it sends anew the spawn protection, making you immune everytime you send back the packet). Simply select EnterWorld packet from "Packet Sniffer" tab, "Add packet to send..." and check "send every 100 ms".


Issue : packet manipulation spam, calling multiple times the same subroutines (spawn protection custom and whatever custom you added in EnterWorld). Potentially fix other exploits based on your spawnMe() content.


Fix : generate a new GameClientState (personally called ENTERING), isolate EnterWorld on it (RequestManorList being called automatically, it must be part of ENTERING too). Any subsequent calls of EnterWorld will call onUnknownPacket, because it will be considered out of ENTERING scope, since we're already at IN_GAME scope once the Player instance is fully loaded (such stuff already exists for all packets : login packets can't be called during ingame state, etc. It's just than EnterWorld is a transition packet between lobby and ingame, but it is considered an ingame packet while it shouldn't).


Since chronicle got different opcodes, you have to adapt using your own chronicle opcodes. I can't and won't deliver a unique version for all chronicles. Since I'm an IL guy, I share for IL. The diff patch can help you to guess what to edit.


Possible improvements :
  • If you know more packets which should be sent only during that translation time between AUTHED and IN_GAME, you can answer here (notably for higher chronicles than IL) with your own version for your own chronicle. I will refresh the initial topic with the different versions.
  • Not sure if RequestManorList  can be called anywhere else (manor panel, etc). I preferred to keep it on IN_GAME. If you know the answer, consider to reply :) !

aCis version, based on latest (GameClient is generally called L2GameClient) :

Code: [Select]
### Eclipse Workspace Patch 1.0
#P aCis_gameserver
Index: java/net/sf/l2j/gameserver/network/clientpackets/CharacterSelected.java
===================================================================
--- java/net/sf/l2j/gameserver/network/clientpackets/CharacterSelected.java (revision 1146)
+++ java/net/sf/l2j/gameserver/network/clientpackets/CharacterSelected.java (working copy)
@@ -62,7 +62,7 @@
 
  sendPacket(SSQInfo.sendSky());
 
- client.setState(GameClientState.IN_GAME);
+ client.setState(GameClientState.ENTERING);
 
  sendPacket(new CharSelected(cha, client.getSessionId().playOkID1));
  }
Index: java/net/sf/l2j/gameserver/network/GameClient.java
===================================================================
--- java/net/sf/l2j/gameserver/network/GameClient.java (revision 1157)
+++ java/net/sf/l2j/gameserver/network/GameClient.java (working copy)
@@ -64,6 +64,7 @@
  {
  CONNECTED, // client has just connected
  AUTHED, // client has authed but doesnt has character attached to it yet
+ ENTERING, // client is currently loading his Player instance, but didn't end
  IN_GAME // client has selected a char and is in game
  }
@@ -168,6 +168,7 @@
  case AUTHED:
  return "[Account: " + getAccountName() + " - IP: " + (address == null ? "disconnected" : address.getHostAddress()) + "]";
 
+ case ENTERING:
  case IN_GAME:
  return "[Character: " + (getPlayer() == null ? "disconnected" : getPlayer().getName()) + " - Account: " + getAccountName() + " - IP: " + (address == null ? "disconnected" : address.getHostAddress()) + "]";
 
Index: java/net/sf/l2j/gameserver/network/L2GamePacketHandler.java
===================================================================
--- java/net/sf/l2j/gameserver/network/L2GamePacketHandler.java (revision 1145)
+++ java/net/sf/l2j/gameserver/network/L2GamePacketHandler.java (working copy)
@@ -51,6 +51,7 @@
  break;
  }
  break;
+
  case AUTHED:
  switch (opcode)
  {
@@ -80,6 +81,43 @@
  break;
  }
  break;
+
+ case ENTERING:
+ switch (opcode)
+ {
+ case 0x03:
+ msg = new EnterWorld();
+ break;
+
+ case 0xd0:
+ int id2 = -1;
+ if (buf.remaining() >= 2)
+ {
+ id2 = buf.getShort() & 0xffff;
+ }
+ else
+ {
+ _log.warning("Client: " + client.toString() + " sent a 0xd0 without the second opcode.");
+ break;
+ }
+
+ switch (id2)
+ {
+ case 8:
+ msg = new RequestManorList();
+ break;
+ default:
+ printDebugDoubleOpcode(opcode, id2, buf, state, client);
+ break;
+ }
+ break;
+
+ default:
+ printDebug(opcode, buf, state, client);
+ break;
+ }
+ break;
+
  case IN_GAME:
  switch (opcode)
  {
@@ -89,9 +127,6 @@
  // case 0x02:
  // // Say ... not used any more ??
  // break;
- case 0x03:
- msg = new EnterWorld();
- break;
  case 0x04:
  msg = new Action();
  break;
Index: java/net/sf/l2j/gameserver/network/clientpackets/EnterWorld.java
===================================================================
--- java/net/sf/l2j/gameserver/network/clientpackets/EnterWorld.java (revision 1150)
+++ java/net/sf/l2j/gameserver/network/clientpackets/EnterWorld.java (working copy)
@@ -35,6 +35,7 @@
 import net.sf.l2j.gameserver.model.pledge.SubPledge;
 import net.sf.l2j.gameserver.model.zone.ZoneId;
 import net.sf.l2j.gameserver.network.SystemMessageId;
+import net.sf.l2j.gameserver.network.GameClient.GameClientState;
 import net.sf.l2j.gameserver.network.serverpackets.ActionFailed;
 import net.sf.l2j.gameserver.network.serverpackets.Die;
 import net.sf.l2j.gameserver.network.serverpackets.EtcStatusUpdate;
@@ -77,6 +78,8 @@
  return;
  }
 
+ getClient().setState(GameClientState.IN_GAME);
+
  final int objectId = player.getObjectId();
 
  if (player.isGM())

WILL BE PART OF REV 381.
« Last Edit: February 26, 2019, 02:16:12 AM by Tryskell »
Code: [Select]
<html><body>Triskel:<br>
Triskel does not speak with foolish fellows who do not know their profession!
</body></html>