void WardenWin::Init(WorldSession* session, BigNumber* k) { _session = session; // Generate Warden Key SHA1Randx WK(k->AsByteArray(), k->GetNumBytes()); WK.Generate(_inputKey, 16); WK.Generate(_outputKey, 16); memcpy(_seed, Module.Seed, 16); _inputCrypto.Init(_inputKey); _outputCrypto.Init(_outputKey); sLog->outDebug(LOG_FILTER_WARDEN, "Server side warden for client %u initializing...", session->GetAccountId()); sLog->outDebug(LOG_FILTER_WARDEN, "C->S Key: %s", ByteArrayToHexStr(_inputKey, 16).c_str()); sLog->outDebug(LOG_FILTER_WARDEN, "S->C Key: %s", ByteArrayToHexStr(_outputKey, 16).c_str()); sLog->outDebug(LOG_FILTER_WARDEN, " Seed: %s", ByteArrayToHexStr(_seed, 16).c_str()); sLog->outDebug(LOG_FILTER_WARDEN, "Loading Module..."); _module = GetModuleForClient(); sLog->outDebug(LOG_FILTER_WARDEN, "Module Key: %s", ByteArrayToHexStr(_module->Key, 16).c_str()); sLog->outDebug(LOG_FILTER_WARDEN, "Module ID: %s", ByteArrayToHexStr(_module->Id, 16).c_str()); RequestModule(); }
void Battlenet::Session::HandleJoinRequestV2(WoWRealm::JoinRequestV2 const& joinRequest) { WoWRealm::JoinResponseV2* joinResponse = new WoWRealm::JoinResponseV2(); Realm const* realm = sRealmList->GetRealm(joinRequest.Realm); if (!realm || realm->Flags & (REALM_FLAG_VERSION_MISMATCH | REALM_FLAG_OFFLINE)) { joinResponse->Response = WoWRealm::JoinResponseV2::FAILURE; AsyncWrite(joinResponse); return; } joinResponse->ServerSeed = rand32(); uint8 sessionKey[40]; HmacSha1 hmac(K.GetNumBytes(), K.AsByteArray().get()); hmac.UpdateData((uint8*)"WoW\0", 4); hmac.UpdateData((uint8*)&joinRequest.ClientSeed, 4); hmac.UpdateData((uint8*)&joinResponse->ServerSeed, 4); hmac.Finalize(); memcpy(sessionKey, hmac.GetDigest(), hmac.GetLength()); HmacSha1 hmac2(K.GetNumBytes(), K.AsByteArray().get()); hmac2.UpdateData((uint8*)"WoW\0", 4); hmac2.UpdateData((uint8*)&joinResponse->ServerSeed, 4); hmac2.UpdateData((uint8*)&joinRequest.ClientSeed, 4); hmac2.Finalize(); memcpy(sessionKey + hmac.GetLength(), hmac2.GetDigest(), hmac2.GetLength()); LoginDatabase.DirectPExecute("UPDATE account SET sessionkey = '%s', last_ip = '%s', last_login = NOW(), locale = %u, failed_logins = 0, os = '%s' WHERE id = %u", ByteArrayToHexStr(sessionKey, 40, true).c_str(), GetRemoteIpAddress().to_string().c_str(), GetLocaleByName(_locale), _os.c_str(), _gameAccountInfo->Id); joinResponse->IPv4.emplace_back(realm->ExternalAddress, realm->Port); if (realm->ExternalAddress != realm->LocalAddress) joinResponse->IPv4.emplace_back(realm->LocalAddress, realm->Port); AsyncWrite(joinResponse); }
bool Battlenet::Session::HandlePasswordModule(BitStream* dataStream, ServerPacket** response) { if (dataStream->GetSize() != 1 + 128 + 32 + 128) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(AUTH_CORRUPTED_MODULE); ReplaceResponse(response, logonResponse); return false; } if (dataStream->Read<uint8>(8) != 2) // State { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(AUTH_CORRUPTED_MODULE); ReplaceResponse(response, logonResponse); return false; } BigNumber A, clientM1, clientChallenge; A.SetBinary(dataStream->ReadBytes(128).get(), 128); clientM1.SetBinary(dataStream->ReadBytes(32).get(), 32); clientChallenge.SetBinary(dataStream->ReadBytes(128).get(), 128); if (A.isZero()) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(AUTH_CORRUPTED_MODULE); ReplaceResponse(response, logonResponse); return false; } SHA256Hash sha; sha.UpdateBigNumbers(&A, &B, NULL); sha.Finalize(); BigNumber u; u.SetBinary(sha.GetDigest(), sha.GetLength()); BigNumber S = ((A * v.ModExp(u, N)) % N).ModExp(b, N); uint8 S_bytes[128]; memcpy(S_bytes, S.AsByteArray(128).get(), 128); uint8 part1[64]; uint8 part2[64]; for (int i = 0; i < 64; ++i) { part1[i] = S_bytes[i * 2]; part2[i] = S_bytes[i * 2 + 1]; } SHA256Hash part1sha, part2sha; part1sha.UpdateData(part1, 64); part1sha.Finalize(); part2sha.UpdateData(part2, 64); part2sha.Finalize(); uint8 sessionKey[SHA256_DIGEST_LENGTH * 2]; for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i) { sessionKey[i * 2] = part1sha.GetDigest()[i]; sessionKey[i * 2 + 1] = part2sha.GetDigest()[i]; } K.SetBinary(sessionKey, SHA256_DIGEST_LENGTH * 2); BigNumber M1; uint8 hash[SHA256_DIGEST_LENGTH]; sha.Initialize(); sha.UpdateBigNumbers(&N, NULL); sha.Finalize(); memcpy(hash, sha.GetDigest(), sha.GetLength()); sha.Initialize(); sha.UpdateBigNumbers(&g, NULL); sha.Finalize(); for (int i = 0; i < sha.GetLength(); ++i) hash[i] ^= sha.GetDigest()[i]; SHA256Hash shaI; shaI.UpdateData(ByteArrayToHexStr(I.AsByteArray().get(), 32)); shaI.Finalize(); // Concat all variables for M1 hash sha.Initialize(); sha.UpdateData(hash, SHA256_DIGEST_LENGTH); sha.UpdateData(shaI.GetDigest(), shaI.GetLength()); sha.UpdateBigNumbers(&s, &A, &B, &K, NULL); sha.Finalize(); M1.SetBinary(sha.GetDigest(), sha.GetLength()); if (memcmp(M1.AsByteArray().get(), clientM1.AsByteArray().get(), 32)) { PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_FAILED_LOGINS); stmt->setString(0, _accountInfo->Login); LoginDatabase.Execute(stmt); Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(AUTH_UNKNOWN_ACCOUNT); ReplaceResponse(response, logonResponse); TC_LOG_DEBUG("session", "[Battlenet::Password] %s attempted to log in with invalid password!", GetClientInfo().c_str()); return false; } if (_gameAccounts.empty()) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(LOGIN_NO_GAME_ACCOUNT); ReplaceResponse(response, logonResponse); TC_LOG_DEBUG("session", "[Battlenet::Password] %s does not have any linked game accounts!", GetClientInfo().c_str()); return false; } BigNumber M; sha.Initialize(); sha.UpdateBigNumbers(&A, &M1, &K, NULL); sha.Finalize(); M.SetBinary(sha.GetDigest(), sha.GetLength()); BigNumber serverProof; serverProof.SetRand(128 * 8); // just send garbage, server signature check is patched out in client BitStream stream; ModuleInfo* password = sModuleMgr->CreateModule(_os, "Password"); uint8 state = 3; stream.WriteBytes(&state, 1); stream.WriteBytes(M.AsByteArray(32).get(), 32); stream.WriteBytes(serverProof.AsByteArray(128).get(), 128); password->DataSize = stream.GetSize(); password->Data = new uint8[password->DataSize]; memcpy(password->Data, stream.GetBuffer(), password->DataSize); Authentication::ProofRequest* proofRequest = new Authentication::ProofRequest(); proofRequest->Modules.push_back(password); if (_gameAccounts.size() > 1) { BitStream accounts; state = 0; accounts.WriteBytes(&state, 1); accounts.Write(_gameAccounts.size(), 8); for (GameAccountInfo const& gameAccount : _gameAccounts) { accounts.Write(2, 8); accounts.WriteString(gameAccount.DisplayName, 8); } ModuleInfo* selectGameAccount = sModuleMgr->CreateModule(_os, "SelectGameAccount"); selectGameAccount->DataSize = accounts.GetSize(); selectGameAccount->Data = new uint8[selectGameAccount->DataSize]; memcpy(selectGameAccount->Data, accounts.GetBuffer(), selectGameAccount->DataSize); proofRequest->Modules.push_back(selectGameAccount); _modulesWaitingForData.push(MODULE_SELECT_GAME_ACCOUNT); } else { _gameAccountInfo = &_gameAccounts[0]; if (_gameAccountInfo->IsBanned) { delete proofRequest; Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); if (_gameAccountInfo->IsPermanentlyBanned) { logonResponse->SetAuthResult(LOGIN_BANNED); TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::Password] Banned account %s tried to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountInfo->Login.c_str()); } else { logonResponse->SetAuthResult(LOGIN_SUSPENDED); TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::Password] Temporarily banned account %s tried to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountInfo->Login.c_str()); } ReplaceResponse(response, logonResponse); return false; } proofRequest->Modules.push_back(sModuleMgr->CreateModule(_os, "RiskFingerprint")); _modulesWaitingForData.push(MODULE_RISK_FINGERPRINT); } ReplaceResponse(response, proofRequest); return true; }
static bool HandleGameAccountCreateCommand(ChatHandler* handler, char const* args) { if (!*args) { handler->SendSysMessage(LANG_CMD_SYNTAX); handler->SetSentErrorMessage(true); return false; } std::string bnetAccountName = args; uint32 accountId = Battlenet::AccountMgr::GetId(bnetAccountName); if (!accountId) { handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, bnetAccountName.c_str()); handler->SetSentErrorMessage(true); return false; } uint8 index = Battlenet::AccountMgr::GetMaxIndex(accountId) + 1; std::string accountName = std::to_string(accountId) + '#' + std::to_string(uint32(index)); // Generate random hex string for password, these accounts must not be logged on with GRUNT BigNumber randPassword; randPassword.SetRand(8 * 16); switch (sAccountMgr->CreateAccount(accountName, ByteArrayToHexStr(randPassword.AsByteArray().get(), randPassword.GetNumBytes()), bnetAccountName, accountId, index)) { case AccountOpResult::AOR_OK: handler->PSendSysMessage(LANG_ACCOUNT_CREATED, accountName.c_str()); if (handler->GetSession()) { TC_LOG_INFO("entities.player.character", "Account: %u (IP: %s) Character:[%s] (%s) created Account %s (Email: '%s')", handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress().c_str(), handler->GetSession()->GetPlayer()->GetName().c_str(), handler->GetSession()->GetPlayer()->GetGUID().ToString().c_str(), accountName.c_str(), bnetAccountName.c_str()); } break; case AccountOpResult::AOR_NAME_TOO_LONG: handler->SendSysMessage(LANG_ACCOUNT_NAME_TOO_LONG); handler->SetSentErrorMessage(true); return false; case AccountOpResult::AOR_PASS_TOO_LONG: handler->SendSysMessage(LANG_ACCOUNT_PASS_TOO_LONG); handler->SetSentErrorMessage(true); return false; case AccountOpResult::AOR_NAME_ALREADY_EXIST: handler->SendSysMessage(LANG_ACCOUNT_ALREADY_EXIST); handler->SetSentErrorMessage(true); return false; case AccountOpResult::AOR_DB_INTERNAL_ERROR: handler->PSendSysMessage(LANG_ACCOUNT_NOT_CREATED_SQL_ERROR, accountName.c_str()); handler->SetSentErrorMessage(true); return false; default: handler->PSendSysMessage(LANG_ACCOUNT_NOT_CREATED, accountName.c_str()); handler->SetSentErrorMessage(true); return false; } return true; }
std::string Battlenet::Cache::GetStreamItemsResponse::ToString() const { std::ostringstream stream; stream << "Battlenet::Cache::GetStreamItemsResponse modules " << Modules.size(); for (ModuleInfo const* module : Modules) stream << std::endl << "Battlenet::ModuleInfo Locale " << module->Region.c_str() << ", ModuleId " << ByteArrayToHexStr(module->ModuleId, 32) << ", Data " << ByteArrayToHexStr(module->Data, module->DataSize); return stream.str(); }
std::string Battlenet::AuthResume::ToString() const { std::ostringstream stream; stream << "Battlenet::AuthResume AuthResult " << Result << " PingTimeout " << PingTimeout << " Threshold " << Threshold << " Rate " << Rate << " Modules " << Modules.size(); for (ModuleInfo const* module : Modules) stream << std::endl << "Battlenet::ModuleInfo Locale " << module->Region.c_str() << ", ModuleId " << ByteArrayToHexStr(module->ModuleId, 32) << ", DataSize " << module->DataSize << ", Data " << ByteArrayToHexStr(module->Data, module->DataSize); return stream.str(); }
std::string Battlenet::AuthComplete::ToString() const { std::ostringstream stream; stream << "Battlenet::AuthComplete AuthResult " << Result << " PingTimeout " << PingTimeout << " Threshold " << Threshold << " Rate " << Rate << " FirstName " << FirstName << " LastName " << LastName << " AccountId " << AccountId << " Region " << uint32(Region) << " GameAccountName " << GameAccountName << " GameAccountFlags " << GameAccountFlags << " Modules " << Modules.size(); for (ModuleInfo const* module : Modules) stream << std::endl << "Battlenet::ModuleInfo Locale " << module->Region.c_str() << ", ModuleId " << ByteArrayToHexStr(module->ModuleId, 32) << ", DataSize " << module->DataSize << ", Data " << ByteArrayToHexStr(module->Data, module->DataSize); return stream.str(); }
int32 LoginRESTService::HandlePost(soap* soapClient) { boost::asio::ip::address_v4 address(soapClient->ip); std::string ip_address = address.to_string(); TC_LOG_DEBUG("server.rest", "[%s:%d] Handling POST request path=\"%s\"", ip_address.c_str(), soapClient->port, soapClient->path); static std::string const expectedPath = "/bnetserver/login/"; if (strstr(soapClient->path, expectedPath.c_str()) != &soapClient->path[0]) return 404; char *buf; size_t len; soap_http_body(soapClient, &buf, &len); Battlenet::JSON::Login::LoginForm loginForm; Battlenet::JSON::Login::LoginResult loginResult; if (!JSON::Deserialize(buf, &loginForm)) { if (soap_register_plugin_arg(soapClient, &ResponseCodePlugin::Init, nullptr) != SOAP_OK) return 500; ResponseCodePlugin* responseCode = reinterpret_cast<ResponseCodePlugin*>(soap_lookup_plugin(soapClient, ResponseCodePlugin::PluginId)); ASSERT(responseCode); responseCode->ErrorCode = 400; loginResult.set_authentication_state(Battlenet::JSON::Login::LOGIN); loginResult.set_error_code("UNABLE_TO_DECODE"); loginResult.set_error_message("There was an internal error while connecting to Battle.net. Please try again later."); return SendResponse(soapClient, loginResult); } std::string login; std::string password; for (int32 i = 0; i < loginForm.inputs_size(); ++i) { if (loginForm.inputs(i).input_id() == "account_name") login = loginForm.inputs(i).value(); else if (loginForm.inputs(i).input_id() == "password") password = loginForm.inputs(i).value(); } Utf8ToUpperOnlyLatin(login); Utf8ToUpperOnlyLatin(password); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_INFO); stmt->setString(0, login); if (PreparedQueryResult result = LoginDatabase.Query(stmt)) { std::string pass_hash = result->Fetch()[13].GetString(); std::unique_ptr<Battlenet::Session::AccountInfo> accountInfo = Trinity::make_unique<Battlenet::Session::AccountInfo>(); accountInfo->LoadResult(result); if (CalculateShaPassHash(login, std::move(password)) == pass_hash) { stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_CHARACTER_COUNTS_BY_BNET_ID); stmt->setUInt32(0, accountInfo->Id); if (PreparedQueryResult characterCountsResult = LoginDatabase.Query(stmt)) { do { Field* fields = characterCountsResult->Fetch(); accountInfo->GameAccounts[fields[0].GetUInt32()] .CharacterCounts[Battlenet::RealmHandle{ fields[3].GetUInt8(), fields[4].GetUInt8(), fields[2].GetUInt32() }.GetAddress()] = fields[1].GetUInt8(); } while (characterCountsResult->NextRow()); } stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_LAST_PLAYER_CHARACTERS); stmt->setUInt32(0, accountInfo->Id); if (PreparedQueryResult lastPlayerCharactersResult = LoginDatabase.Query(stmt)) { Field* fields = lastPlayerCharactersResult->Fetch(); Battlenet::RealmHandle realmId{ fields[1].GetUInt8(), fields[2].GetUInt8(), fields[3].GetUInt32() }; Battlenet::Session::LastPlayedCharacterInfo& lastPlayedCharacter = accountInfo->GameAccounts[fields[0].GetUInt32()] .LastPlayedCharacters[realmId.GetSubRegionAddress()]; lastPlayedCharacter.RealmId = realmId; lastPlayedCharacter.CharacterName = fields[4].GetString(); lastPlayedCharacter.CharacterGUID = fields[5].GetUInt64(); lastPlayedCharacter.LastPlayedTime = fields[6].GetUInt32(); } BigNumber ticket; ticket.SetRand(20 * 8); loginResult.set_login_ticket("TC-" + ByteArrayToHexStr(ticket.AsByteArray(20).get(), 20)); AddLoginTicket(loginResult.login_ticket(), std::move(accountInfo)); } else if (!accountInfo->IsBanned) { uint32 maxWrongPassword = uint32(sConfigMgr->GetIntDefault("WrongPass.MaxCount", 0)); if (sConfigMgr->GetBoolDefault("WrongPass.Logging", false)) TC_LOG_DEBUG("server.rest", "[%s, Account %s, Id %u] Attempted to connect with wrong password!", ip_address.c_str(), login.c_str(), accountInfo->Id); if (maxWrongPassword) { SQLTransaction trans = LoginDatabase.BeginTransaction(); stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_FAILED_LOGINS); stmt->setUInt32(0, accountInfo->Id); trans->Append(stmt); ++accountInfo->FailedLogins; TC_LOG_DEBUG("server.rest", "MaxWrongPass : %u, failed_login : %u", maxWrongPassword, accountInfo->Id); if (accountInfo->FailedLogins >= maxWrongPassword) { BanMode banType = BanMode(sConfigMgr->GetIntDefault("WrongPass.BanType", uint16(BanMode::BAN_IP))); int32 banTime = sConfigMgr->GetIntDefault("WrongPass.BanTime", 600); if (banType == BanMode::BAN_ACCOUNT) { stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_BNET_ACCOUNT_AUTO_BANNED); stmt->setUInt32(0, accountInfo->Id); } else { stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_IP_AUTO_BANNED); stmt->setString(0, ip_address); } stmt->setUInt32(1, banTime); trans->Append(stmt); stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_RESET_FAILED_LOGINS); stmt->setUInt32(0, accountInfo->Id); trans->Append(stmt); } LoginDatabase.CommitTransaction(trans); } } } loginResult.set_authentication_state(Battlenet::JSON::Login::DONE); return SendResponse(soapClient, loginResult); }
std::string Battlenet::Authentication::ProofRequest::ToString() const { std::ostringstream stream; stream << "Battlenet::Authentication::ProofRequest modules " << Modules.size(); for (ModuleInfo const* module : Modules) stream << std::endl << "Battlenet::ModuleInfo Locale " << module->Region.c_str() << ", ModuleId " << ByteArrayToHexStr(module->ModuleId, 32) << ", DataSize " << module->DataSize << ", Data " << ByteArrayToHexStr(module->Data, module->DataSize); return stream.str(); }