Skip to content

Commit

Permalink
Core/Auth: Resolved authentication bypass
Browse files Browse the repository at this point in the history
  • Loading branch information
Chaosvex authored and Shauren committed Nov 10, 2016
1 parent c4dd6d1 commit ed2cd6b
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 47 deletions.
73 changes: 31 additions & 42 deletions src/server/authserver/Server/AuthSession.cpp
Expand Up @@ -118,10 +118,10 @@ 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_RECONNECT_PROOF, sizeof(AUTH_RECONNECT_PROOF_C), &AuthSession::HandleReconnectProof };
handlers[REALM_LIST] = { STATUS_AUTHED, REALM_LIST_PACKET_SIZE, &AuthSession::HandleRealmList };

return handlers;
Expand Down Expand Up @@ -154,8 +154,7 @@ void AccountInfo::LoadResult(Field* fields)
}

AuthSession::AuthSession(tcp::socket&& socket) : Socket(std::move(socket)),
_sentChallenge(false), _sentProof(false),
_status(STATUS_CONNECTED), _build(0), _expversion(0)
_status(STATUS_CHALLENGE), _build(0), _expversion(0)
{
N.SetHexStr("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7");
g.SetDword(7);
Expand Down Expand Up @@ -285,10 +284,7 @@ void AuthSession::SendPacket(ByteBuffer& packet)

bool AuthSession::HandleLogonChallenge()
{
if (_sentChallenge)
return false;

_sentChallenge = true;
_status = STATUS_CLOSED;

sAuthLogonChallenge_C* challenge = reinterpret_cast<sAuthLogonChallenge_C*>(GetReadBuffer().GetReadPointer());
if (challenge->size - (sizeof(sAuthLogonChallenge_C) - AUTH_LOGON_CHALLENGE_INITIAL_SIZE - 1) != challenge->I_len)
Expand Down Expand Up @@ -428,7 +424,10 @@ void AuthSession::LogonChallengeCallback(PreparedQueryResult result)

// Fill the response packet with the result
if (AuthHelper::IsAcceptedClientBuild(_build))
{
pkt << uint8(WOW_SUCCESS);
_status = STATUS_LOGON_PROOF;
}
else
pkt << uint8(WOW_FAIL_VERSION_INVALID);

Expand Down Expand Up @@ -477,10 +476,7 @@ void AuthSession::LogonChallengeCallback(PreparedQueryResult result)
bool AuthSession::HandleLogonProof()
{
TC_LOG_DEBUG("server.authserver", "Entering _HandleLogonProof");
if (_sentProof)
return false;

_sentProof = true;
_status = STATUS_CLOSED;

// Read the packet
sAuthLogonProof_C *logonProof = reinterpret_cast<sAuthLogonProof_C*>(GetReadBuffer().GetReadPointer());
Expand All @@ -500,9 +496,7 @@ bool AuthSession::HandleLogonProof()

// SRP safeguard: abort if A == 0
if (A.IsZero())
{
return false;
}

SHA1Hash sha;
sha.UpdateBigNumbers(&A, &B, NULL);
Expand Down Expand Up @@ -571,24 +565,6 @@ bool AuthSession::HandleLogonProof()
// Check if SRP6 results match (password is correct), else send an error
if (!memcmp(M.AsByteArray(sha.GetLength()).get(), logonProof->M1, 20))
{
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
// No SQL injection (escaped user name) and IP address as received by socket

PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGONPROOF);
stmt->setString(0, K.AsHexStr());
stmt->setString(1, GetRemoteIpAddress().to_string().c_str());
stmt->setUInt32(2, GetLocaleByName(_localizationName));
stmt->setString(3, _os);
stmt->setString(4, _accountInfo.Login);
LoginDatabase.DirectExecute(stmt);

// 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())
{
Expand All @@ -610,6 +586,24 @@ bool AuthSession::HandleLogonProof()
}
}

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
// No SQL injection (escaped user name) and IP address as received by socket

PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGONPROOF);
stmt->setString(0, K.AsHexStr());
stmt->setString(1, GetRemoteIpAddress().to_string().c_str());
stmt->setUInt32(2, GetLocaleByName(_localizationName));
stmt->setString(3, _os);
stmt->setString(4, _accountInfo.Login);
LoginDatabase.DirectExecute(stmt);

// 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
{
Expand Down Expand Up @@ -705,10 +699,7 @@ bool AuthSession::HandleLogonProof()

bool AuthSession::HandleReconnectChallenge()
{
if (_sentChallenge)
return false;

_sentChallenge = true;
_status = STATUS_CLOSED;

sAuthLogonChallenge_C* challenge = reinterpret_cast<sAuthLogonChallenge_C*>(GetReadBuffer().GetReadPointer());
if (challenge->size - (sizeof(sAuthLogonChallenge_C) - AUTH_LOGON_CHALLENGE_INITIAL_SIZE - 1) != challenge->I_len)
Expand Down Expand Up @@ -768,6 +759,7 @@ void AuthSession::ReconnectChallengeCallback(PreparedQueryResult result)
_accountInfo.LoadResult(fields);
K.SetHexStr(fields[9].GetCString());
_reconnectProof.SetRand(16 * 8);
_status = STATUS_RECONNECT_PROOF;

pkt << uint8(WOW_SUCCESS);
pkt.append(_reconnectProof.AsByteArray(16).get(), 16); // 16 bytes random
Expand All @@ -779,10 +771,7 @@ void AuthSession::ReconnectChallengeCallback(PreparedQueryResult result)
bool AuthSession::HandleReconnectProof()
{
TC_LOG_DEBUG("server.authserver", "Entering _HandleReconnectProof");
if (_sentProof)
return false;

_sentProof = true;
_status = STATUS_CLOSED;

sAuthReconnectProof_C *reconnectProof = reinterpret_cast<sAuthReconnectProof_C*>(GetReadBuffer().GetReadPointer());

Expand Down
10 changes: 5 additions & 5 deletions src/server/authserver/Server/AuthSession.h
Expand Up @@ -34,8 +34,11 @@ struct AuthHandler;

enum AuthStatus
{
STATUS_CONNECTED = 0,
STATUS_AUTHED
STATUS_CHALLENGE = 0,
STATUS_LOGON_PROOF,
STATUS_RECONNECT_PROOF,
STATUS_AUTHED,
STATUS_CLOSED
};

struct AccountInfo
Expand Down Expand Up @@ -90,9 +93,6 @@ class AuthSession : public Socket<AuthSession>
BigNumber K;
BigNumber _reconnectProof;

bool _sentChallenge;
bool _sentProof;

AuthStatus _status;
AccountInfo _accountInfo;
std::string _tokenKey;
Expand Down

0 comments on commit ed2cd6b

Please sign in to comment.