From e6f1dd8ead5de97c94f42b41abafcd1f82b29d7f Mon Sep 17 00:00:00 2001 From: Chaosvex Date: Fri, 18 Nov 2016 16:22:51 +0100 Subject: [PATCH 1/2] Core/Auth: Resolved critical vulnerability on auth system bypass --- src/authserver/Server/AuthSocket.cpp | 50 ++++++++++++++++++---------- src/authserver/Server/AuthSocket.h | 12 ++++++- 2 files changed, 43 insertions(+), 19 deletions(-) diff --git a/src/authserver/Server/AuthSocket.cpp b/src/authserver/Server/AuthSocket.cpp index a55612451..b9e935a6d 100644 --- a/src/authserver/Server/AuthSocket.cpp +++ b/src/authserver/Server/AuthSocket.cpp @@ -34,12 +34,6 @@ enum eAuthCmd XFER_CANCEL = 0x34 }; -enum eStatus -{ - STATUS_CONNECTED = 0, - STATUS_AUTHED -}; - // GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push, N), also any gcc version not support it at some paltform #if defined(__GNUC__) #pragma pack(1) @@ -168,14 +162,14 @@ private: const AuthHandler table[] = { - { AUTH_LOGON_CHALLENGE, STATUS_CONNECTED, &AuthSocket::_HandleLogonChallenge }, - { AUTH_LOGON_PROOF, STATUS_CONNECTED, &AuthSocket::_HandleLogonProof }, - { AUTH_RECONNECT_CHALLENGE, STATUS_CONNECTED, &AuthSocket::_HandleReconnectChallenge}, - { AUTH_RECONNECT_PROOF, STATUS_CONNECTED, &AuthSocket::_HandleReconnectProof }, - { REALM_LIST, STATUS_AUTHED, &AuthSocket::_HandleRealmList }, - { XFER_ACCEPT, STATUS_CONNECTED, &AuthSocket::_HandleXferAccept }, - { XFER_RESUME, STATUS_CONNECTED, &AuthSocket::_HandleXferResume }, - { XFER_CANCEL, STATUS_CONNECTED, &AuthSocket::_HandleXferCancel } + { AUTH_LOGON_CHALLENGE, STATUS_CHALLENGE, &AuthSocket::_HandleLogonChallenge }, + { AUTH_LOGON_PROOF, STATUS_LOGON_PROOF, &AuthSocket::_HandleLogonProof }, + { AUTH_RECONNECT_CHALLENGE, STATUS_CHALLENGE, &AuthSocket::_HandleReconnectChallenge }, + { AUTH_RECONNECT_PROOF, STATUS_RECON_PROOF, &AuthSocket::_HandleReconnectProof }, + { REALM_LIST, STATUS_AUTHED, &AuthSocket::_HandleRealmList }, + { XFER_ACCEPT, STATUS_PATCH, &AuthSocket::_HandleXferAccept }, + { XFER_RESUME, STATUS_PATCH, &AuthSocket::_HandleXferResume }, + { XFER_CANCEL, STATUS_PATCH, &AuthSocket::_HandleXferCancel } }; #define AUTH_TOTAL_COMMANDS 8 @@ -185,7 +179,7 @@ Patcher PatchesCache; // Constructor - set the N and g values for SRP6 AuthSocket::AuthSocket(RealmSocket& socket) : - pPatch(NULL), socket_(socket), _authed(false), _build(0), + pPatch(NULL), socket_(socket), _status(STATUS_CHALLENGE), _build(0), _expversion(0), _accountSecurityLevel(SEC_PLAYER) { N.SetHexStr("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7"); @@ -233,7 +227,7 @@ void AuthSocket::OnRead() // Circle through known commands and call the correct command handler for (i = 0; i < AUTH_TOTAL_COMMANDS; ++i) { - if ((uint8)table[i].cmd == _cmd && (table[i].status == STATUS_CONNECTED || (_authed && table[i].status == STATUS_AUTHED))) + if ((uint8)table[i].cmd == _cmd && (table[i].status == _status)) { ;//sLog->outDebug(LOG_FILTER_NETWORKIO, "Got data for cmd %u recv length %u", (uint32)_cmd, (uint32)socket().recv_len()); @@ -306,6 +300,9 @@ bool AuthSocket::_HandleLogonChallenge() if (socket().recv_len() < sizeof(sAuthLogonChallenge_C)) return false; + ///- Session is closed unless overriden + _status = STATUS_CLOSED; + // pussywizard: logon flood protection: { TRINITY_GUARD(ACE_Thread_Mutex, LastLoginAttemptMutex); @@ -519,6 +516,9 @@ bool AuthSocket::_HandleLogonChallenge() ;//sLog->outDebug(LOG_FILTER_NETWORKIO, "'%s:%d' [AuthChallenge] account %s is using '%c%c%c%c' locale (%u)", socket().getRemoteAddress().c_str(), socket().getRemotePort(), // _login.c_str (), ch->country[3], ch->country[2], ch->country[1], ch->country[0], GetLocaleByName(_localizationName) // ); + + ///- All good, await client's proof + _status = STATUS_LOGON_PROOF; } } } @@ -540,6 +540,8 @@ bool AuthSocket::_HandleLogonProof() if (!socket().recv((char *)&lp, sizeof(sAuthLogonProof_C))) return false; + _status = STATUS_CLOSED; + // If the client has no valid version if (_expversion == NO_VALID_EXP_FLAG) { @@ -670,7 +672,8 @@ bool AuthSocket::_HandleLogonProof() socket().send((char *)&proof, sizeof(proof)); } - _authed = true; + ///- Set _status to authed! + _status = STATUS_AUTHED; } else { @@ -749,6 +752,9 @@ bool AuthSocket::_HandleReconnectChallenge() if ((remaining < sizeof(sAuthLogonChallenge_C) - buf.size()) || (socket().recv_len() < remaining)) return false; + ///- Session is closed unless overriden + _status = STATUS_CLOSED; + // No big fear of memory outage (size is int16, i.e. < 65536) buf.resize(remaining + buf.size() + 1); buf[buf.size() - 1] = 0; @@ -790,6 +796,9 @@ bool AuthSocket::_HandleReconnectChallenge() K.SetHexStr ((*result)[0].GetCString()); + ///- All good, await client's proof + _status = STATUS_RECON_PROOF; + // Sending response ByteBuffer pkt; pkt << uint8(AUTH_RECONNECT_CHALLENGE); @@ -810,6 +819,8 @@ bool AuthSocket::_HandleReconnectProof() if (!socket().recv((char *)&lp, sizeof(sAuthReconnectProof_C))) return false; + _status = STATUS_CLOSED; + if (_login.empty() || !_reconnectProof.GetNumBytes() || !K.GetNumBytes()) return false; @@ -830,7 +841,10 @@ bool AuthSocket::_HandleReconnectProof() pkt << uint8(0x00); pkt << uint16(0x00); // 2 bytes zeros socket().send((char const*)pkt.contents(), pkt.size()); - _authed = true; + + ///- Set _status to authed! + _status = STATUS_AUTHED; + return true; } else diff --git a/src/authserver/Server/AuthSocket.h b/src/authserver/Server/AuthSocket.h index db7f3d9a3..ac00528b4 100644 --- a/src/authserver/Server/AuthSocket.h +++ b/src/authserver/Server/AuthSocket.h @@ -14,6 +14,16 @@ class ACE_INET_Addr; struct Realm; +enum eStatus +{ + STATUS_CHALLENGE, + STATUS_LOGON_PROOF, + STATUS_RECON_PROOF, + STATUS_PATCH, // unused in CMaNGOS + STATUS_AUTHED, + STATUS_CLOSED +}; + // Handle login commands class AuthSocket: public RealmSocket::Session { @@ -54,7 +64,7 @@ private: BigNumber K; BigNumber _reconnectProof; - bool _authed; + eStatus _status; std::string _login; From 7e56f3f1fcd690f1c55f9b06ddcaf1fbd37d53f0 Mon Sep 17 00:00:00 2001 From: Yehonal Date: Sat, 19 Nov 2016 00:18:44 +0100 Subject: [PATCH 2/2] Implemented hook for Player::MoveItemFromInventory --- src/game/Entities/Player/Player.cpp | 2 ++ src/game/Scripting/ScriptMgr.cpp | 5 +++++ src/game/Scripting/ScriptMgr.h | 6 +++++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/game/Entities/Player/Player.cpp b/src/game/Entities/Player/Player.cpp index 81efbb048..06d293073 100644 --- a/src/game/Entities/Player/Player.cpp +++ b/src/game/Entities/Player/Player.cpp @@ -12820,6 +12820,8 @@ void Player::MoveItemFromInventory(uint8 bag, uint8 slot, bool update) it->RemoveFromWorld(); it->DestroyForPlayer(this); } + + sScriptMgr->OnAfterPlayerMoveItemFromInventory(this,it,bag,slot,update); } } diff --git a/src/game/Scripting/ScriptMgr.cpp b/src/game/Scripting/ScriptMgr.cpp index 730ce93aa..d717649c6 100644 --- a/src/game/Scripting/ScriptMgr.cpp +++ b/src/game/Scripting/ScriptMgr.cpp @@ -1328,6 +1328,11 @@ void ScriptMgr::OnAfterPlayerSetVisibleItemSlot(Player* player, uint8 slot, Item FOREACH_SCRIPT(PlayerScript)->OnAfterSetVisibleItemSlot(player, slot,item); } +void ScriptMgr::OnAfterPlayerMoveItemFromInventory(Player* player, Item* it, uint8 bag, uint8 slot, bool update) +{ + FOREACH_SCRIPT(PlayerScript)->OnAfterMoveItemFromInventory(player, it, bag, slot, update); +} + // Guild void ScriptMgr::OnGuildAddMember(Guild* guild, Player* player, uint8& plRank) { diff --git a/src/game/Scripting/ScriptMgr.h b/src/game/Scripting/ScriptMgr.h index 98eb5e9fe..0059fb4dd 100644 --- a/src/game/Scripting/ScriptMgr.h +++ b/src/game/Scripting/ScriptMgr.h @@ -788,6 +788,9 @@ class PlayerScript : public ScriptObject // To change behaviour of set visible item slot virtual void OnAfterSetVisibleItemSlot(Player* /*player*/, uint8 /*slot*/, Item* /*item*/) { } + + // After an item has been moved from inventory + virtual void OnAfterMoveItemFromInventory(Player* /*player*/, Item* /*it*/,uint8 /*bag*/, uint8 /*slot*/, bool /*update*/) { } }; class GuildScript : public ScriptObject @@ -1084,7 +1087,8 @@ class ScriptMgr void OnGossipSelect(Player* player, uint32 menu_id, uint32 sender, uint32 action); void OnGossipSelectCode(Player* player, uint32 menu_id, uint32 sender, uint32 action, const char* code); void OnPlayerBeingCharmed(Player* player, Unit* charmer, uint32 oldFactionId, uint32 newFactionId); - void OnAfterPlayerSetVisibleItemSlot(Player* player, uint8 /*slot*/, Item *item); + void OnAfterPlayerSetVisibleItemSlot(Player* player, uint8 slot, Item *item); + void OnAfterPlayerMoveItemFromInventory(Player* player, Item* it, uint8 bag, uint8 slot, bool update); public: /* GuildScript */