Login bypass + MapleQuestlineFetcher
Solved an exploit where anyone (via packet editing) could be able to login as any registered character after authenticating and selecting a character. New tool: MapleQuestlineFetcher. It reports ids from quests which quest script files were not found on the scripts folder.
This commit is contained in:
@@ -1716,27 +1716,26 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
||||
}
|
||||
|
||||
public static boolean deleteCharFromDB(MapleCharacter player, int senderAccId) {
|
||||
int cid = player.getId(), accId = -1, world = 0;
|
||||
int cid = player.getId();
|
||||
if(!Server.getInstance().haveCharacterid(senderAccId, cid)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int accId = senderAccId, world = 0;
|
||||
Connection con = null;
|
||||
try {
|
||||
con = DatabaseConnection.getConnection();
|
||||
|
||||
try (PreparedStatement ps = con.prepareStatement("SELECT accountid, world FROM characters WHERE id = ?")) {
|
||||
try (PreparedStatement ps = con.prepareStatement("SELECT world FROM characters WHERE id = ?")) {
|
||||
ps.setInt(1, cid);
|
||||
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
if(rs.next()) {
|
||||
accId = rs.getInt("accountid");
|
||||
world = rs.getInt("world");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(senderAccId != accId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try (PreparedStatement ps = con.prepareStatement("SELECT buddyid FROM buddies WHERE characterid = ?")) {
|
||||
ps.setInt(1, cid);
|
||||
|
||||
@@ -1896,6 +1895,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
||||
}
|
||||
|
||||
con.close();
|
||||
Server.getInstance().deleteCharacterid(accId, cid);
|
||||
return true;
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
|
||||
@@ -470,7 +470,7 @@ public class Equip extends Item {
|
||||
lvupStr += "+UPGSLOT ";
|
||||
}
|
||||
|
||||
showLevelupMessage(showStr, c); // thx to polaris devs !
|
||||
showLevelupMessage(showStr, c); // thx to Polaris dev team !
|
||||
c.getPlayer().dropMessage(6, lvupStr);
|
||||
|
||||
c.announce(MaplePacketCreator.showEquipmentLevelUp());
|
||||
|
||||
@@ -42,7 +42,6 @@ import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import tools.locks.MonitoredReentrantLock;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
|
||||
import net.MapleServerHandler;
|
||||
import net.mina.MapleCodecFactory;
|
||||
@@ -88,10 +87,13 @@ public class Server implements Runnable {
|
||||
private List<World> worlds = new ArrayList<>();
|
||||
private final Properties subnetInfo = new Properties();
|
||||
private static Server instance = null;
|
||||
private final Map<Integer, Set<Integer>> accountChars = new HashMap<>();
|
||||
private final Map<String, Integer> transitioningChars = new HashMap<>();
|
||||
private List<Pair<Integer, String>> worldRecommendedList = new LinkedList<>();
|
||||
private final Map<Integer, MapleGuild> guilds = new HashMap<>(100);
|
||||
private final Map<MapleClient, Long> inLoginState = new HashMap<>(100);
|
||||
private final Lock srvLock = new MonitoredReentrantLock(MonitoredLockType.SERVER);
|
||||
private final Lock lgnLock = new MonitoredReentrantLock(MonitoredLockType.SERVER);
|
||||
private final PlayerBuffStorage buffStorage = new PlayerBuffStorage();
|
||||
private final Map<Integer, MapleAlliance> alliances = new HashMap<>(100);
|
||||
private final Map<Integer, NewYearCardRecord> newyears = new HashMap<>();
|
||||
@@ -751,6 +753,106 @@ public class Server implements Runnable {
|
||||
return worlds;
|
||||
}
|
||||
|
||||
private static void loadCharacteridsFromDb(Integer accountid, Set<Integer> accChars) {
|
||||
try {
|
||||
try (Connection con = DatabaseConnection.getConnection()) {
|
||||
try (PreparedStatement ps = con.prepareStatement("SELECT id FROM characters WHERE accountid = ?")) {
|
||||
ps.setInt(1, accountid);
|
||||
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
while(rs.next()) {
|
||||
accChars.add(rs.getInt("id"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (SQLException sqle) {
|
||||
sqle.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean haveCharacterid(Integer accountid, Integer chrid) {
|
||||
lgnLock.lock();
|
||||
try {
|
||||
Set<Integer> accChars = accountChars.get(accountid);
|
||||
if(accChars == null) {
|
||||
accChars = new HashSet<>(5);
|
||||
loadCharacteridsFromDb(accountid, accChars);
|
||||
|
||||
accountChars.put(accountid, accChars);
|
||||
}
|
||||
|
||||
return accChars.contains(chrid);
|
||||
} finally {
|
||||
lgnLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void createCharacterid(Integer accountid, Integer chrid) {
|
||||
lgnLock.lock();
|
||||
try {
|
||||
Set<Integer> accChars = accountChars.get(accountid);
|
||||
if(accChars == null) {
|
||||
accChars = new HashSet<>(5);
|
||||
accountChars.put(accountid, accChars);
|
||||
}
|
||||
|
||||
accChars.add(chrid);
|
||||
} finally {
|
||||
lgnLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteCharacterid(Integer accountid, Integer chrid) {
|
||||
lgnLock.lock();
|
||||
try {
|
||||
Set<Integer> accChars = accountChars.get(accountid);
|
||||
if(accChars != null) {
|
||||
accChars.remove(chrid);
|
||||
}
|
||||
} finally {
|
||||
lgnLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
public void deleteAccount(Integer accountid) { is this even a thing?
|
||||
lgnLock.lock();
|
||||
try {
|
||||
accountChars.remove(accountid);
|
||||
} finally {
|
||||
lgnLock.unlock();
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
private static String getRemoteIp(InetSocketAddress isa) {
|
||||
return isa.getAddress().getHostAddress();
|
||||
}
|
||||
|
||||
public void setCharacteridInTransition(InetSocketAddress isa, int charId) {
|
||||
String remoteIp = getRemoteIp(isa);
|
||||
|
||||
lgnLock.lock();
|
||||
try {
|
||||
transitioningChars.put(remoteIp, charId);
|
||||
} finally {
|
||||
lgnLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean validateCharacteridInTransition(InetSocketAddress isa, int charId) {
|
||||
String remoteIp = getRemoteIp(isa);
|
||||
|
||||
lgnLock.lock();
|
||||
try {
|
||||
Integer cid = transitioningChars.remove(remoteIp);
|
||||
return cid != null && cid.equals(charId);
|
||||
} finally {
|
||||
lgnLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void registerLoginState(MapleClient c) {
|
||||
srvLock.lock();
|
||||
try {
|
||||
|
||||
@@ -53,6 +53,7 @@ import client.inventory.MapleInventoryType;
|
||||
import client.inventory.MaplePet;
|
||||
import constants.GameConstants;
|
||||
import constants.ServerConstants;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
@@ -71,6 +72,11 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
|
||||
MapleCharacter player = c.getWorldServer().getPlayerStorage().getCharacterById(cid);
|
||||
boolean newcomer = false;
|
||||
if (player == null) {
|
||||
if(!server.validateCharacteridInTransition((InetSocketAddress) c.getSession().getRemoteAddress(), cid)) {
|
||||
c.disconnect(true, false);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
player = MapleCharacter.loadCharFromDB(cid, c, true);
|
||||
newcomer = true;
|
||||
|
||||
@@ -23,6 +23,7 @@ package net.server.handlers.login;
|
||||
|
||||
import client.MapleClient;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import net.AbstractMaplePacketHandler;
|
||||
import net.server.Server;
|
||||
@@ -35,16 +36,26 @@ public final class CharSelectedHandler extends AbstractMaplePacketHandler {
|
||||
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
|
||||
int charId = slea.readInt();
|
||||
String macs = slea.readMapleAsciiString();
|
||||
String hwid = slea.readMapleAsciiString();
|
||||
c.updateMacs(macs);
|
||||
if (c.hasBannedMac()) {
|
||||
c.updateHWID(hwid);
|
||||
|
||||
if (c.hasBannedMac() || c.hasBannedHWID()) {
|
||||
c.getSession().close(true);
|
||||
return;
|
||||
}
|
||||
|
||||
Server.getInstance().unregisterLoginState(c);
|
||||
c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION);
|
||||
Server server = Server.getInstance();
|
||||
if(!server.haveCharacterid(c.getAccID(), charId)) {
|
||||
c.getSession().close(true);
|
||||
return;
|
||||
}
|
||||
|
||||
String[] socket = Server.getInstance().getIP(c.getWorld(), c.getChannel()).split(":");
|
||||
server.unregisterLoginState(c);
|
||||
c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION);
|
||||
server.setCharacteridInTransition((InetSocketAddress) c.getSession().getRemoteAddress(), charId);
|
||||
|
||||
String[] socket = server.getIP(c.getWorld(), c.getChannel()).split(":");
|
||||
try {
|
||||
c.announce(MaplePacketCreator.getServerIP(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1]), charId));
|
||||
} catch (UnknownHostException | NumberFormatException e) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package net.server.handlers.login;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import net.AbstractMaplePacketHandler;
|
||||
@@ -13,7 +14,6 @@ public class CharSelectedWithPicHandler extends AbstractMaplePacketHandler {
|
||||
|
||||
@Override
|
||||
public void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
|
||||
|
||||
String pic = slea.readMapleAsciiString();
|
||||
int charId = slea.readInt();
|
||||
String macs = slea.readMapleAsciiString();
|
||||
@@ -25,11 +25,19 @@ public class CharSelectedWithPicHandler extends AbstractMaplePacketHandler {
|
||||
c.getSession().close(true);
|
||||
return;
|
||||
}
|
||||
|
||||
Server server = Server.getInstance();
|
||||
if(!server.haveCharacterid(c.getAccID(), charId)) {
|
||||
c.getSession().close(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (c.checkPic(pic)) {
|
||||
Server.getInstance().unregisterLoginState(c);
|
||||
server.unregisterLoginState(c);
|
||||
c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION);
|
||||
server.setCharacteridInTransition((InetSocketAddress) c.getSession().getRemoteAddress(), charId);
|
||||
|
||||
String[] socket = Server.getInstance().getIP(c.getWorld(), c.getChannel()).split(":");
|
||||
String[] socket = server.getIP(c.getWorld(), c.getChannel()).split(":");
|
||||
try {
|
||||
c.announce(MaplePacketCreator.getServerIP(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1]), charId));
|
||||
} catch (UnknownHostException | NumberFormatException e) {
|
||||
|
||||
@@ -112,17 +112,21 @@ public final class CreateCharHandler extends AbstractMaplePacketHandler {
|
||||
}
|
||||
|
||||
MapleInventory equipped = newchar.getInventory(MapleInventoryType.EQUIPPED);
|
||||
|
||||
Item eq_top = MapleItemInformationProvider.getInstance().getEquipById(top);
|
||||
MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
|
||||
|
||||
Item eq_top = ii.getEquipById(top);
|
||||
eq_top.setPosition((byte) -5);
|
||||
equipped.addFromDB(eq_top);
|
||||
Item eq_bottom = MapleItemInformationProvider.getInstance().getEquipById(bottom);
|
||||
|
||||
Item eq_bottom = ii.getEquipById(bottom);
|
||||
eq_bottom.setPosition((byte) -6);
|
||||
equipped.addFromDB(eq_bottom);
|
||||
Item eq_shoes = MapleItemInformationProvider.getInstance().getEquipById(shoes);
|
||||
|
||||
Item eq_shoes = ii.getEquipById(shoes);
|
||||
eq_shoes.setPosition((byte) -7);
|
||||
equipped.addFromDB(eq_shoes);
|
||||
Item eq_weapon = MapleItemInformationProvider.getInstance().getEquipById(weapon);
|
||||
|
||||
Item eq_weapon = ii.getEquipById(weapon);
|
||||
eq_weapon.setPosition((byte) -11);
|
||||
equipped.addFromDB(eq_weapon.copy());
|
||||
|
||||
@@ -131,6 +135,8 @@ public final class CreateCharHandler extends AbstractMaplePacketHandler {
|
||||
return;
|
||||
}
|
||||
c.announce(MaplePacketCreator.addNewCharEntry(newchar));
|
||||
Server.getInstance().broadcastGMMessage(c.getWorld(), MaplePacketCreator.sendYellowTip("[NEW CHAR]: " + c.getAccountName() + " has created a new character with IGN " + name));
|
||||
|
||||
Server.getInstance().createCharacterid(newchar.getAccountID(), newchar.getId());
|
||||
Server.getInstance().broadcastGMMessage(c.getWorld(), MaplePacketCreator.sendYellowTip("[NEW CHAR]: " + c.getAccountName() + " has created a new character with IGN " + name));
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import java.security.Permission;
|
||||
import java.security.PermissionCollection;
|
||||
import java.util.Map;
|
||||
|
||||
public class AutoJCE{ // AutoJCE into server source thanks to Kradi-a
|
||||
public class AutoJCE{ // AutoJCE into server source thanks to Acernis dev team
|
||||
|
||||
/**
|
||||
* Credits: ntoskrnl of StackOverflow
|
||||
|
||||
@@ -63,7 +63,7 @@ public class MapleAESOFB {
|
||||
} catch (NoSuchPaddingException e) {
|
||||
System.out.println("ERROR " + e);
|
||||
} catch (InvalidKeyException e) {
|
||||
System.out.println("Error initalizing the encryption cipher. Make sure you're using the Unlimited Strength cryptography jar files.");
|
||||
System.out.println("Error initializing the encryption cipher. Make sure you're using the Unlimited Strength cryptography jar files.");
|
||||
}
|
||||
this.setIv(iv);
|
||||
this.mapleVersion = (short) (((mapleVersion >> 8) & 0xFF) | ((mapleVersion << 8) & 0xFF00));
|
||||
|
||||
Reference in New Issue
Block a user