From fb43a92cc2aaffab42efebf025b6a12c01af8fde Mon Sep 17 00:00:00 2001 From: Shauren Date: Thu, 7 Feb 2013 16:15:23 +0100 Subject: [PATCH] Core/Accounts: sessionkey field in account table is only a temporary storage to pass data from authserver to worldserver and should only be used as such. Clearing sessionkey from database after a successful login to prevent possible exploits. --- sql/base/auth_database.sql | 2 +- .../auth/2013_02_07_00_auth_account.sql | 3 ++ src/server/game/Accounts/AccountMgr.cpp | 8 +++++ src/server/game/Server/WorldSocket.cpp | 35 +++++++------------ .../Database/Implementation/LoginDatabase.cpp | 3 +- .../Database/Implementation/LoginDatabase.h | 1 + 6 files changed, 28 insertions(+), 24 deletions(-) create mode 100644 sql/updates/auth/2013_02_07_00_auth_account.sql diff --git a/sql/base/auth_database.sql b/sql/base/auth_database.sql index 9aaadcb55d5da..cdff87c245a1d 100644 --- a/sql/base/auth_database.sql +++ b/sql/base/auth_database.sql @@ -26,7 +26,7 @@ CREATE TABLE `account` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Identifier', `username` varchar(32) NOT NULL DEFAULT '', `sha_pass_hash` varchar(40) NOT NULL DEFAULT '', - `sessionkey` varchar(80) NOT NULL DEFAULT '', + `sessionkey` varchar(80) NOT NULL DEFAULT '' COMMENT 'Temporary storage of session key used to pass data from authserver to worldserver', `v` varchar(64) NOT NULL DEFAULT '', `s` varchar(64) NOT NULL DEFAULT '', `email` varchar(254) NOT NULL DEFAULT '', diff --git a/sql/updates/auth/2013_02_07_00_auth_account.sql b/sql/updates/auth/2013_02_07_00_auth_account.sql new file mode 100644 index 0000000000000..03bdf8cdcd533 --- /dev/null +++ b/sql/updates/auth/2013_02_07_00_auth_account.sql @@ -0,0 +1,3 @@ +UPDATE `account` SET `sessionkey`=''; +ALTER TABLE `account` +CHANGE `sessionkey` `sessionkey` varchar(80) NOT NULL DEFAULT '' COMMENT 'Temporary storage of session key used to pass data from authserver to worldserver' AFTER `sha_pass_hash`; diff --git a/src/server/game/Accounts/AccountMgr.cpp b/src/server/game/Accounts/AccountMgr.cpp index ce382342de851..b1d0087c32c9e 100644 --- a/src/server/game/Accounts/AccountMgr.cpp +++ b/src/server/game/Accounts/AccountMgr.cpp @@ -187,6 +187,14 @@ AccountOpResult AccountMgr::ChangePassword(uint32 accountId, std::string newPass LoginDatabase.Execute(stmt); + stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_VS); + + stmt->setString(0, ""); + stmt->setString(1, ""); + stmt->setString(2, username); + + LoginDatabase.Execute(stmt); + return AOR_OK; } diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index 8b102518e84b1..5260b5f77a982 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -750,7 +750,6 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) uint32 clientBuild; uint32 unk2, unk3, unk5, unk6, unk7; uint64 unk4; - BigNumber v, s, g, N; WorldPacket packet, SendAddonPacked; BigNumber k; @@ -779,6 +778,8 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) clientSeed); // Get the account information from the realmd database + // 0 1 2 3 4 5 6 7 8 + // SELECT id, sessionkey, last_ip, locked, expansion, mutetime, locale, recruiter, os FROM account WHERE username = ? PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME); stmt->setString(0, account); @@ -795,27 +796,11 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) Field* fields = result->Fetch(); - uint8 expansion = fields[6].GetUInt8(); + uint8 expansion = fields[4].GetUInt8(); uint32 world_expansion = sWorld->getIntConfig(CONFIG_EXPANSION); if (expansion > world_expansion) expansion = world_expansion; - N.SetHexStr ("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7"); - g.SetDword (7); - - v.SetHexStr(fields[4].GetCString()); - s.SetHexStr (fields[5].GetCString()); - - const char* sStr = s.AsHexStr(); // Must be freed by OPENSSL_free() - const char* vStr = v.AsHexStr(); // Must be freed by OPENSSL_free() - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WorldSocket::HandleAuthSession: (s, v) check s: %s v: %s", - sStr, - vStr); - - OPENSSL_free((void*)sStr); - OPENSSL_free((void*)vStr); - ///- Re-check ip locking (same check as in realmd). if (fields[3].GetUInt8() == 1) // if ip is locked { @@ -831,7 +816,7 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) k.SetHexStr(fields[1].GetCString()); - int64 mutetime = fields[7].GetInt64(); + int64 mutetime = fields[5].GetInt64(); //! Negative mutetime indicates amount of seconds to be muted effective on next login - which is now. if (mutetime < 0) { @@ -845,12 +830,12 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) LoginDatabase.Execute(stmt); } - locale = LocaleConstant (fields[8].GetUInt8()); + locale = LocaleConstant (fields[6].GetUInt8()); if (locale >= TOTAL_LOCALES) locale = LOCALE_enUS; - uint32 recruiter = fields[9].GetUInt32(); - std::string os = fields[10].GetString(); + uint32 recruiter = fields[7].GetUInt32(); + std::string os = fields[8].GetString(); // Must be done before WorldSession is created if (sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED) && os != "Win" && os != "OSX") @@ -948,6 +933,12 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) // NOTE ATM the socket is single-threaded, have this in mind ... ACE_NEW_RETURN(m_Session, WorldSession(id, this, AccountTypes(security), expansion, mutetime, locale, recruiter, isRecruiter), -1); + stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_CLEAR_SESSIONKEY); + + stmt->setUInt32(0, id); + + LoginDatabase.Execute(stmt); + m_Crypt.Init(&k); m_Session->LoadGlobalAccountData(); diff --git a/src/server/shared/Database/Implementation/LoginDatabase.cpp b/src/server/shared/Database/Implementation/LoginDatabase.cpp index bbb51cfbde6c4..747f3ef1dc6b2 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.cpp +++ b/src/server/shared/Database/Implementation/LoginDatabase.cpp @@ -35,6 +35,7 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_INS_ACCOUNT_AUTO_BANNED, "INSERT INTO account_banned VALUES (?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+?, 'Trinity realmd', 'Failed login autoban', 1)", CONNECTION_ASYNC); PrepareStatement(LOGIN_DEL_ACCOUNT_BANNED, "DELETE FROM account_banned WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_SESSIONKEY, "SELECT a.sessionkey, a.id, aa.gmlevel FROM account a LEFT JOIN account_access aa ON (a.id = aa.id) WHERE username = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_UPD_CLEAR_SESSIONKEY, "UPDATE account SET sessionkey = '' WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_VS, "UPDATE account SET v = ?, s = ? WHERE username = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_LOGONPROOF, "UPDATE account SET sessionkey = ?, last_ip = ?, last_login = NOW(), locale = ?, failed_logins = 0, os = ? WHERE username = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_LOGONCHALLENGE, "SELECT a.sha_pass_hash, a.id, a.locked, a.last_ip, aa.gmlevel, a.v, a.s FROM account a LEFT JOIN account_access aa ON (a.id = aa.id) WHERE a.username = ?", CONNECTION_SYNCH); @@ -42,7 +43,7 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_SEL_FAILEDLOGINS, "SELECT id, failed_logins FROM account WHERE username = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_ID_BY_NAME, "SELECT id FROM account WHERE username = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_LIST_BY_NAME, "SELECT id, username FROM account WHERE username = ?", CONNECTION_SYNCH); - PrepareStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME, "SELECT id, sessionkey, last_ip, locked, v, s, expansion, mutetime, locale, recruiter, os FROM account WHERE username = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME, "SELECT id, sessionkey, last_ip, locked, expansion, mutetime, locale, recruiter, os FROM account WHERE username = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_LIST_BY_EMAIL, "SELECT id, username FROM account WHERE email = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_NUM_CHARS_ON_REALM, "SELECT numchars FROM realmcharacters WHERE realmid = ? AND acctid= ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_BY_IP, "SELECT id, username FROM account WHERE last_ip = ?", CONNECTION_SYNCH); diff --git a/src/server/shared/Database/Implementation/LoginDatabase.h b/src/server/shared/Database/Implementation/LoginDatabase.h index 939cc4b4790f1..6cd4ec99b79f0 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.h +++ b/src/server/shared/Database/Implementation/LoginDatabase.h @@ -53,6 +53,7 @@ enum LoginDatabaseStatements LOGIN_INS_ACCOUNT_AUTO_BANNED, LOGIN_DEL_ACCOUNT_BANNED, LOGIN_SEL_SESSIONKEY, + LOGIN_UPD_CLEAR_SESSIONKEY, LOGIN_UPD_VS, LOGIN_UPD_LOGONPROOF, LOGIN_SEL_LOGONCHALLENGE,