Vanilla 1 is no longer supported or maintained. If you need a copy, you can get it here.
HackerOne users: Testing against this community violates our program's Terms of Service and will result in your bounty being denied.
Vanilla Session Handling
I wouldn't necessarily say this is a bug, but more of an act of oversight on behalf of the developers. I was in the process of developing an external application to interact with Vanilla when I found an objectionable way Cookies are handled.
If you look at the function ValidateUserCredentials() you will find the following code:
$s->SetMainTable("User", "u");
$s->AddSelect("UserID", "u");
$s->AddSelect("UserID", "u", "EncryptedUserID", "md5");
$s->AddJoin("Role", "r", "RoleID", "u", "RoleID", "left join");
$s->AddSelect("CanLogin", "r");
$s->AddWhere("u.Name", $Username, "=");
$s->AddWhere("u.Password", $Password, "=", "and", "md5");
*snip*
$EncryptedUserID = $rows["EncryptedUserID"];
*snip*
$this->SetCookieCredentials($EncryptedUserID, $VerificationKey);
Although MD5 hashing the UserID seems innocent at first, lets take a look at the function ValidateCookieCredentials() when the Cookie is retreived and verified:
$s->SetMainTable("User", "u");
$s->AddSelect("UserID", "u");
$s->AddSelect("UserID", "u", "EncryptedUserID", "md5");
$s->AddWhere("md5(UserID)", $EncryptedUserID, "=");
$s->AddWhere("VerificationKey", $VerificationKey, "=");
At first this looks fine, but then you should notice that this is basically translating to the statement 'SELECT UserID, MD5(UserID) from User WHERE MD5(UserID) = $EncryptedUserID AND VerificationKey = $VerificationKey'. So wheres the problem? Well imagine having a mere 20,000 registered users on the forum. That would generate 20,000 MD5() calls by your DBMS. This will almost definately cause a spike in processor usage depending on the Server. Now imagine that forum had a mere 500 active users and you ran 'rm -f /tmp/sess*', restarted your HTTPD or any other action which would clear PHP's Session Cache. That would within a very short period of time generate 500 * 20,000 = 10,000,000 MD5() requests! More than enough to temporarily cripple most Servers especially if the DBMS has poorly implemented its MD5 routine.
At a closer examination of the UserID field we find that its a simple Integer with Auto Increment set. With our previous 20,000 User example that would give us a mere 20,000 possible combinations to check through to reverse the hash in a Cookie to the original UserID. You could even just go to the forum and find the Profile ID of the User you have obtained the Cookie from to reverse the UserID aswell.
With the lack of Security in regards to attempting to mask the UserID from a potential hacker, and the clear bottleneck created by the Validation routines, is there any reason why Cookie Authentication should be handled in the current way?
If you look at the function ValidateUserCredentials() you will find the following code:
$s->SetMainTable("User", "u");
$s->AddSelect("UserID", "u");
$s->AddSelect("UserID", "u", "EncryptedUserID", "md5");
$s->AddJoin("Role", "r", "RoleID", "u", "RoleID", "left join");
$s->AddSelect("CanLogin", "r");
$s->AddWhere("u.Name", $Username, "=");
$s->AddWhere("u.Password", $Password, "=", "and", "md5");
*snip*
$EncryptedUserID = $rows["EncryptedUserID"];
*snip*
$this->SetCookieCredentials($EncryptedUserID, $VerificationKey);
Although MD5 hashing the UserID seems innocent at first, lets take a look at the function ValidateCookieCredentials() when the Cookie is retreived and verified:
$s->SetMainTable("User", "u");
$s->AddSelect("UserID", "u");
$s->AddSelect("UserID", "u", "EncryptedUserID", "md5");
$s->AddWhere("md5(UserID)", $EncryptedUserID, "=");
$s->AddWhere("VerificationKey", $VerificationKey, "=");
At first this looks fine, but then you should notice that this is basically translating to the statement 'SELECT UserID, MD5(UserID) from User WHERE MD5(UserID) = $EncryptedUserID AND VerificationKey = $VerificationKey'. So wheres the problem? Well imagine having a mere 20,000 registered users on the forum. That would generate 20,000 MD5() calls by your DBMS. This will almost definately cause a spike in processor usage depending on the Server. Now imagine that forum had a mere 500 active users and you ran 'rm -f /tmp/sess*', restarted your HTTPD or any other action which would clear PHP's Session Cache. That would within a very short period of time generate 500 * 20,000 = 10,000,000 MD5() requests! More than enough to temporarily cripple most Servers especially if the DBMS has poorly implemented its MD5 routine.
At a closer examination of the UserID field we find that its a simple Integer with Auto Increment set. With our previous 20,000 User example that would give us a mere 20,000 possible combinations to check through to reverse the hash in a Cookie to the original UserID. You could even just go to the forum and find the Profile ID of the User you have obtained the Cookie from to reverse the UserID aswell.
With the lack of Security in regards to attempting to mask the UserID from a potential hacker, and the clear bottleneck created by the Validation routines, is there any reason why Cookie Authentication should be handled in the current way?
0
This discussion has been closed.
Comments
Regardless, What do you suggest?