aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2019-01-15 22:49:27 +0100
committerShauren <shauren.trinity@gmail.com>2019-01-15 22:49:27 +0100
commit250fcc8970842e3e8c6b48c15ed3b7c8ba240df1 (patch)
tree0c520fce55c6ec2bf0732ab70b51dd1f5e3b6763 /src
parentec1cfa36f4c286ad8037516460a4e99ea5d7a5ed (diff)
Core/Auth: Implement additional version check for modified clients during login
Diffstat (limited to 'src')
-rw-r--r--src/server/authserver/Authentication/AuthCodes.cpp38
-rw-r--r--src/server/authserver/Authentication/AuthCodes.h5
-rw-r--r--src/server/authserver/Server/AuthSession.cpp76
-rw-r--r--src/server/authserver/Server/AuthSession.h2
-rw-r--r--src/server/authserver/authserver.conf.dist9
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