diff options
-rw-r--r-- | src/server/authserver/Authentication/AuthCodes.cpp | 38 | ||||
-rw-r--r-- | src/server/authserver/Authentication/AuthCodes.h | 5 | ||||
-rw-r--r-- | src/server/authserver/Server/AuthSession.cpp | 76 | ||||
-rw-r--r-- | src/server/authserver/Server/AuthSession.h | 2 | ||||
-rw-r--r-- | src/server/authserver/authserver.conf.dist | 9 |
5 files changed, 102 insertions, 28 deletions
diff --git a/src/server/authserver/Authentication/AuthCodes.cpp b/src/server/authserver/Authentication/AuthCodes.cpp index cd49e74fe33..2453241bf65 100644 --- a/src/server/authserver/Authentication/AuthCodes.cpp +++ b/src/server/authserver/Authentication/AuthCodes.cpp @@ -16,31 +16,39 @@ */ #include "AuthCodes.h" -#include <cstddef> namespace AuthHelper { static RealmBuildInfo const PostBcAcceptedClientBuilds[] = { - {15595, 4, 3, 4, ' '}, - {14545, 4, 2, 2, ' '}, - {13623, 4, 0, 6, 'a'}, - {13930, 3, 3, 5, 'a'}, // 3.3.5a China Mainland build - {12340, 3, 3, 5, 'a'}, - {11723, 3, 3, 3, 'a'}, - {11403, 3, 3, 2, ' '}, - {11159, 3, 3, 0, 'a'}, - {10505, 3, 2, 2, 'a'}, - {9947, 3, 1, 3, ' '}, - {8606, 2, 4, 3, ' '}, + {15595, 4, 3, 4, ' ', {{}}, {{}}}, + {14545, 4, 2, 2, ' ', {{}}, {{}}}, + {13623, 4, 0, 6, 'a', {{}}, {{}}}, + {13930, 3, 3, 5, 'a', {{}}, {{}}}, // 3.3.5a China Mainland build + {12340, 3, 3, 5, 'a', + {{ 0xCD, 0xCB, 0xBD, 0x51, 0x88, 0x31, 0x5E, 0x6B, 0x4D, 0x19, 0x44, 0x9D, 0x49, 0x2D, 0xBC, 0xFA, 0xF1, 0x56, 0xA3, 0x47 }}, + {{ 0xB7, 0x06, 0xD1, 0x3F, 0xF2, 0xF4, 0x01, 0x88, 0x39, 0x72, 0x94, 0x61, 0xE3, 0xF8, 0xA0, 0xE2, 0xB5, 0xFD, 0xC0, 0x34 }}, + }, + {11723, 3, 3, 3, 'a', {{}}, {{}}}, + {11403, 3, 3, 2, ' ', {{}}, {{}}}, + {11159, 3, 3, 0, 'a', {{}}, {{}}}, + {10505, 3, 2, 2, 'a', {{}}, {{}}}, + {9947, 3, 1, 3, ' ', {{}}, {{}}}, + {8606, 2, 4, 3, ' ', + {{ 0x31, 0x9A, 0xFA, 0xA3, 0xF2, 0x55, 0x96, 0x82, 0xF9, 0xFF, 0x65, 0x8B, 0xE0, 0x14, 0x56, 0x25, 0x5F, 0x45, 0x6F, 0xB1 }}, + {{}}, + }, {0, 0, 0, 0, ' '} // terminator }; static RealmBuildInfo const PreBcAcceptedClientBuilds[] = { - {6141, 1, 12, 3, ' '}, - {6005, 1, 12, 2, ' '}, - {5875, 1, 12, 1, ' '}, + {6141, 1, 12, 3, ' ', {{}}, {{}}}, + {6005, 1, 12, 2, ' ', {{}}, {{}}}, + {5875, 1, 12, 1, ' ', + {{}}, + {{ 0x8D, 0x17, 0x3C, 0xC3, 0x81, 0x96, 0x1E, 0xEB, 0xAB, 0xF3, 0x36, 0xF5, 0xE6, 0x67, 0x5B, 0x10, 0x1B, 0xB5, 0x13, 0xE5 }}, + }, {0, 0, 0, 0, ' '} // terminator }; diff --git a/src/server/authserver/Authentication/AuthCodes.h b/src/server/authserver/Authentication/AuthCodes.h index df5a2d6c538..c734a87968f 100644 --- a/src/server/authserver/Authentication/AuthCodes.h +++ b/src/server/authserver/Authentication/AuthCodes.h @@ -19,6 +19,9 @@ #ifndef _AUTHCODES_H #define _AUTHCODES_H +#include "Define.h" +#include <array> + enum AuthResult { WOW_SUCCESS = 0x00, @@ -84,6 +87,8 @@ struct RealmBuildInfo int MinorVersion; int BugfixVersion; int HotfixVersion; + std::array<uint8, 20> WindowsHash; + std::array<uint8, 20> MacHash; }; namespace AuthHelper diff --git a/src/server/authserver/Server/AuthSession.cpp b/src/server/authserver/Server/AuthSession.cpp index 5cc94a292fa..4c6464751a8 100644 --- a/src/server/authserver/Server/AuthSession.cpp +++ b/src/server/authserver/Server/AuthSession.cpp @@ -84,7 +84,7 @@ typedef struct AUTH_LOGON_PROOF_S uint8 M2[20]; uint32 AccountFlags; uint32 SurveyId; - uint16 unk3; + uint16 LoginFlags; } sAuthLogonProof_S; typedef struct AUTH_LOGON_PROOF_S_OLD @@ -106,6 +106,8 @@ typedef struct AUTH_RECONNECT_PROOF_C #pragma pack(pop) +std::array<uint8, 16> VersionChallenge = { { 0xBA, 0xA3, 0x1E, 0x99, 0xA0, 0x0B, 0x21, 0x57, 0xFC, 0x37, 0x3F, 0xB3, 0x69, 0xCD, 0xD2, 0xF1 } }; + enum class BufferSizes : uint32 { SRP_6_V = 0x20, @@ -402,9 +404,6 @@ void AuthSession::LogonChallengeCallback(PreparedQueryResult result) ASSERT(gmod.GetNumBytes() <= 32); - BigNumber unk3; - unk3.SetRand(16 * 8); - // Fill the response packet with the result if (AuthHelper::IsAcceptedClientBuild(_build)) { @@ -421,7 +420,7 @@ void AuthSession::LogonChallengeCallback(PreparedQueryResult result) pkt << uint8(32); pkt.append(N.AsByteArray(32).get(), 32); pkt.append(s.AsByteArray(int32(BufferSizes::SRP_6_S)).get(), size_t(BufferSizes::SRP_6_S)); // 32 bytes - pkt.append(unk3.AsByteArray(16).get(), 16); + pkt.append(VersionChallenge.data(), VersionChallenge.size()); uint8 securityFlags = 0; // Check if token is used @@ -562,13 +561,21 @@ bool AuthSession::HandleLogonProof() ByteBuffer packet; packet << uint8(AUTH_LOGON_PROOF); packet << uint8(WOW_FAIL_UNKNOWN_ACCOUNT); - packet << uint8(3); - packet << uint8(0); + packet << uint16(0); // LoginFlags, 1 has account message SendPacket(packet); return true; } } + if (!VerifyVersion(logonProof->A, sizeof(logonProof->A), logonProof->crc_hash, false)) + { + ByteBuffer packet; + packet << uint8(AUTH_LOGON_PROOF); + packet << uint8(WOW_FAIL_VERSION_INVALID); + SendPacket(packet); + return true; + } + TC_LOG_DEBUG("server.authserver", "'%s:%d' User '%s' successfully authenticated", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountInfo.Login.c_str()); // Update the sessionkey, last_ip, last login time and reset number of failed logins in the account table for this account @@ -596,7 +603,7 @@ bool AuthSession::HandleLogonProof() proof.error = 0; proof.AccountFlags = 0x00800000; // 0x01 = GM, 0x08 = Trial, 0x00800000 = Pro pass (arena tournament) proof.SurveyId = 0; - proof.unk3 = 0; + proof.LoginFlags = 0; // 0x1 = has account message packet.resize(sizeof(proof)); std::memcpy(packet.contents(), &proof, sizeof(proof)); @@ -621,8 +628,7 @@ bool AuthSession::HandleLogonProof() ByteBuffer packet; packet << uint8(AUTH_LOGON_PROOF); packet << uint8(WOW_FAIL_UNKNOWN_ACCOUNT); - packet << uint8(3); - packet << uint8(0); + packet << uint16(0); // LoginFlags, 1 has account message SendPacket(packet); TC_LOG_INFO("server.authserver.hack", "'%s:%d' [AuthChallenge] account %s tried to login with invalid password!", @@ -734,7 +740,7 @@ void AuthSession::ReconnectChallengeCallback(PreparedQueryResult result) pkt << uint8(WOW_SUCCESS); pkt.append(_reconnectProof.AsByteArray(16).get(), 16); // 16 bytes random - pkt << uint64(0x00) << uint64(0x00); // 16 bytes zeros + pkt.append(VersionChallenge.data(), VersionChallenge.size()); SendPacket(pkt); } @@ -760,11 +766,20 @@ bool AuthSession::HandleReconnectProof() if (!memcmp(sha.GetDigest(), reconnectProof->R2, SHA_DIGEST_LENGTH)) { + if (!VerifyVersion(reconnectProof->R1, sizeof(reconnectProof->R1), reconnectProof->R3, true)) + { + ByteBuffer packet; + packet << uint8(AUTH_RECONNECT_PROOF); + packet << uint8(WOW_FAIL_VERSION_INVALID); + SendPacket(packet); + return true; + } + // Sending response ByteBuffer pkt; pkt << uint8(AUTH_RECONNECT_PROOF); - pkt << uint8(0x00); - pkt << uint16(0x00); // 2 bytes zeros + pkt << uint8(WOW_SUCCESS); + pkt << uint16(0); // LoginFlags, 1 has account message SendPacket(pkt); _status = STATUS_AUTHED; return true; @@ -918,3 +933,38 @@ void AuthSession::SetVSFields(const std::string& rI) stmt->setString(2, _accountInfo.Login); LoginDatabase.Execute(stmt); } + +bool AuthSession::VerifyVersion(uint8 const* a, int32 aLength, uint8 const* versionProof, bool isReconnect) +{ + if (!sConfigMgr->GetBoolDefault("StrictVersionCheck", false)) + return true; + + std::array<uint8, 20> zeros = { {} }; + std::array<uint8, 20> const* versionHash = nullptr; + if (!isReconnect) + { + RealmBuildInfo const* buildInfo = AuthHelper::GetBuildInfo(_build); + if (!buildInfo) + return false; + + if (_os == "Win") + versionHash = &buildInfo->WindowsHash; + else if (_os == "OSX") + versionHash = &buildInfo->MacHash; + + if (!versionHash) + return false; + + if (!memcmp(versionHash->data(), zeros.data(), zeros.size())) + return true; // not filled serverside + } + else + versionHash = &zeros; + + SHA1Hash version; + version.UpdateData(a, aLength); + version.UpdateData(versionHash->data(), versionHash->size()); + version.Finalize(); + + return memcmp(versionProof, version.GetDigest(), version.GetLength()) == 0; +} diff --git a/src/server/authserver/Server/AuthSession.h b/src/server/authserver/Server/AuthSession.h index dd2371a895d..9c603616225 100644 --- a/src/server/authserver/Server/AuthSession.h +++ b/src/server/authserver/Server/AuthSession.h @@ -90,6 +90,8 @@ private: void SetVSFields(const std::string& rI); + bool VerifyVersion(uint8 const* a, int32 aLength, uint8 const* versionProof, bool isReconnect); + BigNumber N, s, g, v; BigNumber b, B; BigNumber K; diff --git a/src/server/authserver/authserver.conf.dist b/src/server/authserver/authserver.conf.dist index efde048726c..8000af9a9c8 100644 --- a/src/server/authserver/authserver.conf.dist +++ b/src/server/authserver/authserver.conf.dist @@ -131,6 +131,15 @@ WrongPass.BanType = 0 WrongPass.Logging = 0 # +# StrictVersionCheck +# Description: Prevent modified clients from connnecting +# Default: 0 - (Disabled) +# 1 - (Enabled) +# + +StrictVersionCheck = 0 + +# # BanExpiryCheckInterval # Description: Time (in seconds) between checks for expired bans # Default: 60 |