Skip to content

Commit

Permalink
Core/Auth: Implement additional version check for modified clients du…
Browse files Browse the repository at this point in the history
…ring login
  • Loading branch information
Shauren committed Jan 15, 2019
1 parent ec1cfa3 commit 250fcc8
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 28 deletions.
38 changes: 23 additions & 15 deletions src/server/authserver/Authentication/AuthCodes.cpp
Expand Up @@ -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
};

Expand Down
5 changes: 5 additions & 0 deletions src/server/authserver/Authentication/AuthCodes.h
Expand Up @@ -19,6 +19,9 @@
#ifndef _AUTHCODES_H
#define _AUTHCODES_H

#include "Define.h"
#include <array>

enum AuthResult
{
WOW_SUCCESS = 0x00,
Expand Down Expand Up @@ -84,6 +87,8 @@ struct RealmBuildInfo
int MinorVersion;
int BugfixVersion;
int HotfixVersion;
std::array<uint8, 20> WindowsHash;
std::array<uint8, 20> MacHash;
};

namespace AuthHelper
Expand Down
76 changes: 63 additions & 13 deletions src/server/authserver/Server/AuthSession.cpp
Expand Up @@ -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
Expand All @@ -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,
Expand Down Expand Up @@ -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))
{
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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));
Expand All @@ -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!",
Expand Down Expand Up @@ -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);
}
Expand All @@ -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;
Expand Down Expand Up @@ -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;
}
2 changes: 2 additions & 0 deletions src/server/authserver/Server/AuthSession.h
Expand Up @@ -90,6 +90,8 @@ class AuthSession : public Socket<AuthSession>

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;
Expand Down
9 changes: 9 additions & 0 deletions src/server/authserver/authserver.conf.dist
Expand Up @@ -130,6 +130,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
Expand Down

1 comment on commit 250fcc8

@Shauren
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not tested with mac client

Please sign in to comment.