Skip to content

Instantly share code, notes, and snippets.

@Raydor
Created March 17, 2017 14:03
Show Gist options
  • Save Raydor/a32613a34565c478fe971246899901e0 to your computer and use it in GitHub Desktop.
Save Raydor/a32613a34565c478fe971246899901e0 to your computer and use it in GitHub Desktop.
Fix authentication bypass for old TC servers
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