Created
March 17, 2017 14:03
-
-
Save Raydor/a32613a34565c478fe971246899901e0 to your computer and use it in GitHub Desktop.
Fix authentication bypass for old TC servers
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From cc83d838710d088251de379bdc24a2d6b138e63c Mon Sep 17 00:00:00 2001 | |
From: Raydor <raydor_1993@hotmail.com> | |
Date: Fri, 17 Mar 2017 13:25:58 +0100 | |
Subject: [PATCH] [FIX] Fixeado un exploit de login | |
Commits de Mangos: https://github.com/cmangos/mangos-classic/commit/74d51cf70d67f6d4a47321a4226e7473cb8e2601 + https://github.com/cmangos/mangos-classic/commit/0d2b7e38c886ddd6828cfa75e2daba5121467383 | |
Commits de TrinityCore: https://github.com/TrinityCore/TrinityCore/commit/ed2cd6b34f849f9cc9adb86318457155e47f7314 + https://github.com/TrinityCore/TrinityCore/commit/14abd1f5875d8c8e98ac9c76789d8b439008eba2 | |
--- | |
src/server/authserver/Server/AuthSession.cpp | 101 +++++++++++++++++---------- | |
src/server/authserver/Server/AuthSession.h | 14 +++- | |
2 files changed, 75 insertions(+), 40 deletions(-) | |
diff --git a/src/server/authserver/Server/AuthSession.cpp b/src/server/authserver/Server/AuthSession.cpp | |
index e8241ac4..0fc698d3 100644 | |
--- a/src/server/authserver/Server/AuthSession.cpp | |
+++ b/src/server/authserver/Server/AuthSession.cpp | |
@@ -43,12 +43,6 @@ enum eAuthCmd | |
XFER_CANCEL = 0x34 | |
}; | |
-enum eStatus | |
-{ | |
- STATUS_CONNECTED = 0, | |
- STATUS_AUTHED | |
-}; | |
- | |
#pragma pack(push, 1) | |
typedef struct AUTH_LOGON_CHALLENGE_C | |
@@ -125,14 +119,14 @@ std::unordered_map<uint8, AuthHandler> AuthSession::InitHandlers() | |
{ | |
std::unordered_map<uint8, AuthHandler> handlers; | |
- handlers[AUTH_LOGON_CHALLENGE] = { STATUS_CONNECTED, AUTH_LOGON_CHALLENGE_INITIAL_SIZE, &AuthSession::HandleLogonChallenge }; | |
- handlers[AUTH_LOGON_PROOF] = { STATUS_CONNECTED, sizeof(AUTH_LOGON_PROOF_C), &AuthSession::HandleLogonProof }; | |
- handlers[AUTH_RECONNECT_CHALLENGE] = { STATUS_CONNECTED, AUTH_LOGON_CHALLENGE_INITIAL_SIZE, &AuthSession::HandleReconnectChallenge }; | |
- handlers[AUTH_RECONNECT_PROOF] = { STATUS_CONNECTED, sizeof(AUTH_RECONNECT_PROOF_C), &AuthSession::HandleReconnectProof }; | |
+ handlers[AUTH_LOGON_CHALLENGE] = { STATUS_CHALLENGE, AUTH_LOGON_CHALLENGE_INITIAL_SIZE, &AuthSession::HandleLogonChallenge }; | |
+ handlers[AUTH_LOGON_PROOF] = { STATUS_LOGON_PROOF, sizeof(AUTH_LOGON_PROOF_C), &AuthSession::HandleLogonProof }; | |
+ handlers[AUTH_RECONNECT_CHALLENGE] = { STATUS_CHALLENGE, AUTH_LOGON_CHALLENGE_INITIAL_SIZE, &AuthSession::HandleReconnectChallenge }; | |
+ handlers[AUTH_RECONNECT_PROOF] = { STATUS_RECON_PROOF, sizeof(AUTH_RECONNECT_PROOF_C), &AuthSession::HandleReconnectProof }; | |
handlers[REALM_LIST] = { STATUS_AUTHED, REALM_LIST_PACKET_SIZE, &AuthSession::HandleRealmList }; | |
- handlers[XFER_ACCEPT] = { STATUS_AUTHED, XFER_ACCEPT_SIZE, &AuthSession::HandleXferAccept }; | |
- handlers[XFER_RESUME] = { STATUS_AUTHED, XFER_RESUME_SIZE, &AuthSession::HandleXferResume }; | |
- handlers[XFER_CANCEL] = { STATUS_AUTHED, XFER_CANCEL_SIZE, &AuthSession::HandleXferCancel }; | |
+ handlers[XFER_ACCEPT] = { STATUS_PATCH, XFER_ACCEPT_SIZE, &AuthSession::HandleXferAccept }; | |
+ handlers[XFER_RESUME] = { STATUS_PATCH, XFER_RESUME_SIZE, &AuthSession::HandleXferResume }; | |
+ handlers[XFER_CANCEL] = { STATUS_PATCH, XFER_CANCEL_SIZE, &AuthSession::HandleXferCancel }; | |
return handlers; | |
} | |
@@ -153,6 +147,12 @@ void AuthSession::ReadHandler() | |
break; | |
} | |
+ if (_status != itr->second.status) | |
+ { | |
+ CloseSocket(); | |
+ return; | |
+ } | |
+ | |
uint16 size = uint16(itr->second.packetSize); | |
if (packet.GetActiveSize() < size) | |
break; | |
@@ -196,6 +196,9 @@ void AuthSession::SendPacket(ByteBuffer& packet) | |
bool AuthSession::HandleLogonChallenge() | |
{ | |
+ ///- Session is closed unless overriden | |
+ _status = STATUS_CLOSED; | |
+ | |
sAuthLogonChallenge_C* challenge = reinterpret_cast<sAuthLogonChallenge_C*>(GetReadBuffer().GetReadPointer()); | |
//TC_LOG_DEBUG("server.authserver", "[AuthChallenge] got full packet, %#04x bytes", challenge->size); | |
@@ -347,7 +350,10 @@ bool AuthSession::HandleLogonChallenge() | |
// Fill the response packet with the result | |
if (AuthHelper::IsAcceptedClientBuild(_build)) | |
- pkt << uint8(WOW_SUCCESS); | |
+ { | |
+ pkt << uint8(WOW_SUCCESS); | |
+ _status = STATUS_LOGON_PROOF; | |
+ } | |
else | |
pkt << uint8(WOW_FAIL_VERSION_INVALID); | |
@@ -398,6 +404,9 @@ bool AuthSession::HandleLogonChallenge() | |
challenge->country[3], challenge->country[2], challenge->country[1], challenge->country[0], | |
GetLocaleByName(_localizationName) | |
); | |
+ | |
+ ///- All good, await client's proof | |
+ _status = STATUS_LOGON_PROOF; | |
} | |
} | |
} | |
@@ -412,8 +421,11 @@ bool AuthSession::HandleLogonChallenge() | |
// Logon Proof command handler | |
bool AuthSession::HandleLogonProof() | |
{ | |
- | |
TC_LOG_DEBUG("server.authserver", "Entering _HandleLogonProof"); | |
+ | |
+ ///- Session is closed unless overriden | |
+ _status = STATUS_CLOSED; | |
+ | |
// Read the packet | |
sAuthLogonProof_C *logonProof = reinterpret_cast<sAuthLogonProof_C*>(GetReadBuffer().GetReadPointer()); | |
@@ -432,9 +444,10 @@ bool AuthSession::HandleLogonProof() | |
// SRP safeguard: abort if A == 0 | |
if (A.isZero()) | |
- { | |
return false; | |
- } | |
+ | |
+ if ((A % N).isZero()) | |
+ return false; | |
SHA1Hash sha; | |
sha.UpdateBigNumbers(&A, &B, NULL); | |
@@ -505,25 +518,6 @@ bool AuthSession::HandleLogonProof() | |
{ | |
TC_LOG_DEBUG("server.authserver", "'%s:%d' User '%s' successfully authenticated", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _login.c_str()); | |
- // Update the sessionkey, last_ip, last login time and reset number of failed logins in the account table for this account | |
- // No SQL injection (escaped user name) and IP address as received by socket | |
- const char *K_hex = K.AsHexStr(); | |
- | |
- PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGONPROOF); | |
- stmt->setString(0, K_hex); | |
- stmt->setString(1, GetRemoteIpAddress().to_string().c_str()); | |
- stmt->setUInt32(2, GetLocaleByName(_localizationName)); | |
- stmt->setString(3, _os); | |
- stmt->setString(4, _login); | |
- LoginDatabase.DirectExecute(stmt); | |
- | |
- OPENSSL_free((void*)K_hex); | |
- | |
- // Finish SRP6 and send the final result to the client | |
- sha.Initialize(); | |
- sha.UpdateBigNumbers(&A, &M, &K, NULL); | |
- sha.Finalize(); | |
- | |
// Check auth token | |
if ((logonProof->securityFlags & 0x04) || !_tokenKey.empty()) | |
{ | |
@@ -543,6 +537,25 @@ bool AuthSession::HandleLogonProof() | |
return false; | |
} | |
} | |
+ | |
+ // Update the sessionkey, last_ip, last login time and reset number of failed logins in the account table for this account | |
+ // No SQL injection (escaped user name) and IP address as received by socket | |
+ const char *K_hex = K.AsHexStr(); | |
+ | |
+ PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGONPROOF); | |
+ stmt->setString(0, K_hex); | |
+ stmt->setString(1, GetRemoteIpAddress().to_string().c_str()); | |
+ stmt->setUInt32(2, GetLocaleByName(_localizationName)); | |
+ stmt->setString(3, _os); | |
+ stmt->setString(4, _login); | |
+ LoginDatabase.DirectExecute(stmt); | |
+ | |
+ OPENSSL_free((void*)K_hex); | |
+ | |
+ // Finish SRP6 and send the final result to the client | |
+ sha.Initialize(); | |
+ sha.UpdateBigNumbers(&A, &M, &K, NULL); | |
+ sha.Finalize(); | |
ByteBuffer packet; | |
if (_expversion & POST_BC_EXP_FLAG) // 2.x and 3.x clients | |
@@ -571,7 +584,8 @@ bool AuthSession::HandleLogonProof() | |
} | |
SendPacket(packet); | |
- _isAuthenticated = true; | |
+ ///- Set _status to authed! | |
+ _status = STATUS_AUTHED; | |
} | |
else | |
{ | |
@@ -649,6 +663,10 @@ bool AuthSession::HandleLogonProof() | |
bool AuthSession::HandleReconnectChallenge() | |
{ | |
TC_LOG_DEBUG("server.authserver", "Entering _HandleReconnectChallenge"); | |
+ | |
+ ///- Session is closed unless overriden | |
+ _status = STATUS_CLOSED; | |
+ | |
sAuthLogonChallenge_C* challenge = reinterpret_cast<sAuthLogonChallenge_C*>(GetReadBuffer().GetReadPointer()); | |
//TC_LOG_DEBUG("server.authserver", "[AuthChallenge] got full packet, %#04x bytes", challenge->size); | |
@@ -690,6 +708,8 @@ bool AuthSession::HandleReconnectChallenge() | |
pkt << uint8(AUTH_RECONNECT_CHALLENGE); | |
pkt << uint8(0x00); | |
_reconnectProof.SetRand(16 * 8); | |
+ ///- All good, await client's proof | |
+ _status = STATUS_RECON_PROOF; | |
pkt.append(_reconnectProof.AsByteArray(16).get(), 16); // 16 bytes random | |
pkt << uint64(0x00) << uint64(0x00); // 16 bytes zeros | |
@@ -700,6 +720,10 @@ bool AuthSession::HandleReconnectChallenge() | |
bool AuthSession::HandleReconnectProof() | |
{ | |
TC_LOG_DEBUG("server.authserver", "Entering _HandleReconnectProof"); | |
+ | |
+ ///- Session is closed unless overriden | |
+ _status = STATUS_CLOSED; | |
+ | |
sAuthReconnectProof_C *reconnectProof = reinterpret_cast<sAuthReconnectProof_C*>(GetReadBuffer().GetReadPointer()); | |
if (_login.empty() || !_reconnectProof.GetNumBytes() || !K.GetNumBytes()) | |
@@ -722,7 +746,8 @@ bool AuthSession::HandleReconnectProof() | |
pkt << uint8(0x00); | |
pkt << uint16(0x00); // 2 bytes zeros | |
SendPacket(pkt); | |
- _isAuthenticated = true; | |
+ ///- Set _status to authed! | |
+ _status = STATUS_AUTHED; | |
return true; | |
} | |
else | |
diff --git a/src/server/authserver/Server/AuthSession.h b/src/server/authserver/Server/AuthSession.h | |
index 07af61d9..b0716d33 100644 | |
--- a/src/server/authserver/Server/AuthSession.h | |
+++ b/src/server/authserver/Server/AuthSession.h | |
@@ -36,7 +36,7 @@ public: | |
static std::unordered_map<uint8, AuthHandler> InitHandlers(); | |
AuthSession(tcp::socket&& socket) : Socket(std::move(socket)), | |
- _isAuthenticated(false), _build(0), _expversion(0), _accountSecurityLevel(SEC_PLAYER) | |
+ _status(STATUS_CHALLENGE), _build(0), _expversion(0), _accountSecurityLevel(SEC_PLAYER) | |
{ | |
N.SetHexStr("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7"); | |
g.SetDword(7); | |
@@ -53,6 +53,16 @@ protected: | |
void ReadHandler() override; | |
private: | |
+ enum eStatus | |
+ { | |
+ STATUS_CHALLENGE, | |
+ STATUS_LOGON_PROOF, | |
+ STATUS_RECON_PROOF, | |
+ STATUS_PATCH, | |
+ STATUS_AUTHED, | |
+ STATUS_CLOSED | |
+ }; | |
+ | |
bool HandleLogonChallenge(); | |
bool HandleLogonProof(); | |
bool HandleReconnectChallenge(); | |
@@ -71,7 +81,7 @@ private: | |
BigNumber K; | |
BigNumber _reconnectProof; | |
- bool _isAuthenticated; | |
+ eStatus _status; | |
std::string _tokenKey; | |
std::string _login; | |
std::string _localizationName; | |
-- | |
2.11.0.windows.3 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment