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:
ronancpl
2018-04-22 20:58:56 -03:00
parent a1fcf21ac9
commit b7a259e2c4
25 changed files with 1223 additions and 44 deletions

View File

@@ -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();

View File

@@ -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());

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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));
}
}

View File

@@ -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

View File

@@ -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));