Hum. Anybody remembering the japanese servers ? They're like ghost server, still at patch ~5065. This technique would work ?
Quote:
They use the official account servers.
bool CUserList::LoginUser(LPCTSTR szAccount, LPCTSTR szPassword, SOCKET_ID idSocket) // ½öÓÃÓÚ·ÇÕʺŷþÎñÆ÷Æô¶¯
{
#ifdef ACCOUNT_ENABLE
return false;
#endif
bool bRet = false;
SQLBUF szSQL;
sprintf(szSQL, "SELECT id, name, account_id, recordmap_id FROM %s WHERE account='%s' && password='%s'", _TBL_USER, szAccount, szPassword);
IRecordset* pRes = GameWorld()->GetDatabase()->CreateNewRecordset(szSQL); //VVVVVVVVVVVVVVVVVVVVVVVV
if(pRes)
{
OBJID idUser = pRes->LoadDWord("id");
NAMESTR szName = "ÎÞ";
pRes->LoadString(szName, "name", _MAX_NAMESIZE);
OBJID idAccount = pRes->LoadDWord("account_id");
OBJID idMap = pRes->LoadDWord("recordmap_id");
PROCESS_ID idProcess = MapList()->GetMapProcessID(idMap);
ASSERT (idProcess != PROCESS_NONE);
int nLevel = 0; // δÕʺŷþÎñÆ÷µÇ¼£¬²»ÐèÒªµÈ¼¶
CreateUser(idProcess, idUser, szName, idAccount, idSocket, nLevel, szAccount);
bRet = true;
pRes->Release();; //AAAAAAAAAAAAAAAAAAAAAAAAAA
GameWorld()->SendFee(idAccount, CMsgFee_A::FEE_BEGIN);
}
{
m_nPlayerAmount++;
if(m_nMaxPlayerAmount < m_nPlayerAmount)
m_nMaxPlayerAmount = m_nPlayerAmount;
extern struct STAT_STRUCT g_stat;
InterlockedExchange(&g_stat.nAllPlayers, m_nPlayerAmount);
InterlockedExchange(&g_stat.nMaxPlayers, m_nMaxPlayerAmount);
InterlockedIncrement(&g_stat.nLoginPlayers);
}
return bRet;
}
That's not the code that's used for the login server. The source I have (whether it is official or not) does escape the username and password that is received from the client before querying the database.Quote:
Taken from UserList.cpp in the official Eudemons server source code. Doesn't seem to have a lot of protection against SQL injection
void InsertBackslash(char * bufTarget, const char * pszSource)
{
const char * pSour = pszSource;
char * pTarg = bufTarget;
while(*pSour)
{
if(*pSour == '\\' || *pSour == '\'')
*(pTarg++) = '\\';
*(pTarg++) = *(pSour++);
}
*pTarg = 0;
}
Oh, I just remember a case like a long time ago when people were logging other people's accounts, way before the whole incident with the "hack case forums" or whatever that got broken into. I just thought it had to do with the SQL injection into the username/password. Probably not thenQuote:
That's not the code that's used for the login server. The source I have (whether it is official or not) does escape the username and password that is received from the client before querying the database.
Code:void InsertBackslash(char * bufTarget, const char * pszSource) { const char * pSour = pszSource; char * pTarg = bufTarget; while(*pSour) { if(*pSour == '\\' || *pSour == '\'') *(pTarg++) = '\\'; *(pTarg++) = *(pSour++); } *pTarg = 0; }
That's code from the server source code right?Quote:
Taken from UserList.cpp in the official Eudemons server source code. Doesn't seem to have a lot of protection against SQL injection
//////////////////////////////////////////////////////////////////////
// password == "" ±íʾ²»¼ì²éÃÜÂë
BOOL CAccount::Create(const char* pszName, const char* pszPassword)
{
try{
if(!pszName || _MAX_NAMESIZE <= strlen(pszName))
return false;
if(!pszPassword || _MAX_PSWSIZE <= strlen(pszPassword))
return false;
if (m_pRes != NULL)
{
::LogSave("WARNING: CAccount::Create() m_pRes not NULL.");
this->Destroy();
}
char bufName[256];
InsertBackslash(bufName, pszName); //
// if(strchr(pszName, '\'') || strchr(pszName, '\\')) // µ¥ÒýºÅ(')³£Á¿ºÍ·´Ð±¸Ü(\)³£Á¿
{
// ::LogSave("ERROR: Login with illegal username [%s]. can't login.", pszName); //¡ï DEBUG
// return false;
}
char bufPassword[256];
InsertBackslash(bufPassword, pszPassword);
// if(strchr(pszPassword, '\'') || (strlen(pszPassword) && pszPassword[strlen(pszPassword)-1] == '\\')) // µ¥ÒýºÅ(')³£Á¿ºÍ·´Ð±¸Ü(\)³£Á¿
// if(strchr(pszPassword, '\'') || strchr(pszPassword, '\\')) // µ¥ÒýºÅ(')³£Á¿ºÍ·´Ð±¸Ü(\)³£Á¿
{
// ::LogSave("ERROR: Login with illegal password [%s]. can't login.", pszPassword); //¡ï DEBUG
// return false;
}
m_pRes = new CMyRecordset(&g_db);
if(!m_pRes)
{
::LogSave("ERROR: CAccount::Create() can't new CMyRecordset object.");
return false;
}
if(bufPassword[0])
sprintf(m_szSQL, SQL_ACCOUNT_STMT, POINTTABLE, bufName, bufPassword);
else
sprintf(m_szSQL, SQL_ACCOUNT_STMT2, POINTTABLE, bufName);
if (!m_pRes->Open(m_szSQL))
{
::LogSave("ERROR: CAccount::Create(char*) can't Open() database for [%s]", m_szSQL);
delete m_pRes;
m_pRes = NULL;
return false;
}
if (m_pRes->RecordCount() == 0)
{
m_pRes->Close();
delete m_pRes;
m_pRes = NULL;
return false;
}
if(!this->LoadInfo())
{
::LogSave("ERROR: CAccount::Create() can't LoadInfo()");
return false;
}
return true;
}
catch(...)
{
::LogSave("exception catch at CAccount::Create(%s).", pszName);
return false;
}
}
Haha yeah, my bad. I don't have the account server source :(Quote:
That's code from the server source code right?
I'm fairly sure that method is called after the account server has received and verified the information, before passing it over to the game server.
Taken from the account server source:
Where InsertBackslash replaces any bad SQL characters.
Edit: whoops, didn't see the earlier post.
Quote:
FallenCO PM was 1 and they didnt manually change them ;)
In binaries certain commands will not work if your account UID is in that range.Quote:
That means they used a weird database backup.
The client (and server) expect player uid's to be above 1 million. It's fairly well documented and while changing it to a non default range might 'help' versus this type of a tool... it's really quite a pointless measure and will likely screw up various gameplay elements.