...

View Full Version : MD5 hashing issue...I think... PHP



MDwebdev85
01-30-2010, 01:03 AM
Hey guys, maybe someone can help me out on this one. I have a client (contract) through my work that asked for my assistance with an internal web site. It's a php site with a mySQL database. They migrated from a Red Hat server to a Sun Solaris 10 server and cannot log into anything with their passwords. They can select the tables and what not, and the link diag page shows a successful connection to the database. My concern was that the hashses for the passwords were being generated differently between the 2 different php engines.

Red Hat - 4.3.2

Sun Solaris - 4.4.5

Here's the log in form:
----------------------------------------------------------------------


<?php


function login($Code, $Password){
include("config.php");
$data = 'training';
$table = 'Agency';

if($Code == NULL || $Password ==NULL)
return "Agency Code or Password is incorrect";

//connects to database
if (!($link=mysql_pconnect($_SESSION['hostname'],$_SESSION['username'], $_SESSION['password']))) {
error(sprintf("error connecting to host %s, by user %s", $_SESSION['hostname'], $_SESSION['username']));
exit();
}

//select database
if (!mysql_select_db($data, $link)){
error(sprintf("error in executing %s database", $data));
error(sprintf("error:%d %s", mysql_errno($link), mysql_error($link)));
exit();
}

$query = "SELECT id, Code FROM $table WHERE ((Code = '$Code')) AND ((Password = md5('$Password')))";

//stores the result of the query to the array $result
if(!$result = mysql_query($query, $link)){
error(sprintf("Error in executing %s stmt", $result));
error(sprintf("error:%d %s", mysql_errno($link), mysql_error($link)));
exit();
}



//if the user exists
if(mysql_num_rows($result)){
//update last login and ip address


$date = mktime();
$id = mysql_result($result, 0, id);
$ip = ip();
$update = "UPDATE Agency SET Last_Visit = '$date', ip_address = '$ip' WHERE id = '$id'";

if(!mysql_query($update, $link)){
error(sprintf("Error in executing %s stmt", $update));
error(sprintf("error:%d %s", mysql_errno($link), mysql_error($link)));
exit();
}
$_SESSION['Code'] = mysql_result($result, 0, Code);
$_SESSION['AgencyID'] = mysql_result($result, 0, ID);

header("Location: $currentsite"); //after success it redirects
exit;
} else {
return "Username or Password is incorrect";
}
}


?>


--------------------------------------------------------------------------


Now, someone also mentioned to me that the encoding could be different. As in the old server interpreting the characters as ASCII or ANSI...and the new server interpreting the opposite. I'm not too sure, since I really haven't had to do this stuff before with passwords. I did see in the config.inc.php file the following:

--------------------------------------------------------------------------



<? php


* MySQL settings
*/
// Column types;
// varchar, tinyint, text and date are listed first, based on estimated popularity
$cfg['ColumnTypes'] = array(
'VARCHAR',
'TINYINT',
'TEXT',
'DATE',
'SMALLINT',
'MEDIUMINT',
'INT',
'BIGINT',
'FLOAT',
'DOUBLE',
'DECIMAL',
'DATETIME',
'TIMESTAMP',
'TIME',
'YEAR',
'CHAR',
'TINYBLOB',
'TINYTEXT',
'BLOB',
'MEDIUMBLOB',
'MEDIUMTEXT',
'LONGBLOB',
'LONGTEXT',
'ENUM',
'SET'
);

// Atributes
$cfg['AttributeTypes'] = array(
'',
'BINARY',
'UNSIGNED',
'UNSIGNED ZEROFILL'
);

// Available functions
if ($cfg['ShowFunctionFields']) {
$cfg['Functions'] = array(
'ASCII',
'CHAR',
'SOUNDEX',
'LCASE',
'UCASE',
'NOW',
'PASSWORD',
'MD5',
'ENCRYPT',
'RAND',
'LAST_INSERT_ID',
'COUNT',
'AVG',
'SUM',
'CURDATE',
'CURTIME',
'FROM_DAYS',
'FROM_UNIXTIME',
'PERIOD_ADD',
'PERIOD_DIFF',
'TO_DAYS',
'UNIX_TIMESTAMP',
'USER',
'WEEKDAY',
'CONCAT'
);

// Which column types will be mapped to which Group?
$cfg['RestrictColumnTypes'] = array(
'VARCHAR' => 'FUNC_CHAR',
'TINYINT' => 'FUNC_NUMBER',
'TEXT' => 'FUNC_CHAR',
'DATE' => 'FUNC_DATE',
'SMALLINT' => 'FUNC_NUMBER',
'MEDIUMINT' => 'FUNC_NUMBER',
'INT' => 'FUNC_NUMBER',
'BIGINT' => 'FUNC_NUMBER',
'FLOAT' => 'FUNC_NUMBER',
'DOUBLE' => 'FUNC_NUMBER',
'DECIMAL' => 'FUNC_NUMBER',
'DATETIME' => 'FUNC_DATE',
'TIMESTAMP' => 'FUNC_DATE',
'TIME' => 'FUNC_DATE',
'YEAR' => 'FUNC_DATE',
'CHAR' => 'FUNC_CHAR',
'TINYBLOB' => 'FUNC_CHAR',
'TINYTEXT' => 'FUNC_CHAR',
'BLOB' => 'FUNC_CHAR',
'MEDIUMBLOB' => 'FUNC_CHAR',
'MEDIUMTEXT' => 'FUNC_CHAR',
'LONGBLOB' => 'FUNC_CHAR',
'LONGTEXT' => 'FUNC_CHAR',
'ENUM' => '',
'SET' => ''
);

// Map above defined groups to any function
$cfg['RestrictFunctions'] = array(
'FUNC_CHAR' => array(
'ASCII',
'CHAR',
'SOUNDEX',
'LCASE',
'UCASE',
'PASSWORD',
'MD5',
'ENCRYPT',
'LAST_INSERT_ID',
'USER',
'CONCAT'
),

'FUNC_DATE' => array(
'NOW',
'CURDATE',
'CURTIME',
'FROM_DAYS',
'FROM_UNIXTIME',
'PERIOD_ADD',
'PERIOD_DIFF',
'TO_DAYS',
'UNIX_TIMESTAMP',
'WEEKDAY'
),

'FUNC_NUMBER' => array(
'ASCII',
'CHAR',
'MD5',
'ENCRYPT',
'RAND',
'LAST_INSERT_ID',
'COUNT',
'AVG',
'SUM'
)
);

} // end if


/**
* Unset magic_quotes_runtime - do not change!
*/
set_magic_quotes_runtime(0);

/**
* File Revision - do not change either!
*/
$cfg['FileRevision'] = '$Revision: 1.182 $';
?>


***I didn't post the entire config.inc.php code, I've tried to do some searching online but haven't been successful in getting in the right direction. If anyone could point me in the right direction it would be greatly appreciated. I can post more info if need be. Thanks.

_Aerospace_Eng_
01-30-2010, 01:20 AM
Remove the space here: <? php

MDwebdev85
01-30-2010, 01:21 AM
o lol it is, i just put that there to post the code.... its not actually "there" in my document...its correct in the doc...

MDwebdev85
01-30-2010, 01:22 AM
I've never posted code before in the forum, so i wasnt sure if it needed to have an opening/closing tag in there

_Aerospace_Eng_
01-30-2010, 01:38 AM
I'm assuming you had a backup of the db structure in order to port it over to the new server. Do you have your schema available? I'm thinking the number of characters allotted for the password in the db isn't enough to hold the entire md5 hash.

MDwebdev85
01-30-2010, 01:47 AM
I'm assuming you had a backup of the db structure in order to port it over to the new server. Do you have your schema available? I'm thinking the number of characters allotted for the password in the db isn't enough to hold the entire md5 hash.


well, heres my problem...everything was already moved over, the old prod box is still being used... red hat box, and the dev box is the one that the problem is on. They are insisting that I try to figure it out, which is putting a lot of stress on me since I'm technically not a developer (i do web dev as a hobby and work knows now b/c of my big mouth). I'm also not a dba and have only worked with mysql through cpanel as far as creating a db and giving it users and letting my app do the rest, so i'd say im somewhat of a rookie...I have configured MS SQL servers but not down to doing queries and such... The solaris box the site is on now, I only have ssh access to and cant run an x session b/c theres no video...yea go figure I'd get stuck with it. I poked around an fixed a few syntax errors which i was hoping was the issue since the php engines were different revs, but no dice.... so this is where im left at...

MDwebdev85
01-30-2010, 04:05 AM
http://imgur.com/mslFz

screenshot of the mysql cli....is this what i need to be looking at?

MDwebdev85
01-30-2010, 04:10 AM
I also did describe AgencyPasswords;

shows details, the MD5 varchar is (40)

MattF
01-30-2010, 04:27 AM
40 should be fine. MD5 is only 32, if I recall correctly.

You should be looking at what the system logs are telling you before anything else. Also, what versions of MySQL are running on each? Enable error_reporting and see what gets logged from PHP.

MDwebdev85
01-30-2010, 05:31 AM
this is showing in the access_log

[29/Jan/2010:23:14:56 -0500] "POST /index.php HTTP/1.1" 200 5827

_Aerospace_Eng_
01-30-2010, 07:33 AM
But did you enable error reporting and check the error log?

Puffin the Erb
01-30-2010, 03:30 PM
Just a thought, as mentioned MD5 hashes comprise 32 hexadecimal digits, SHA hashes have 40. Are you sure the passwords are not hashed with SHA?

bdl
01-30-2010, 07:09 PM
My concern was that the hashses for the passwords were being generated differently between the 2 different php engines.

MD5 is MD5 is MD5.... it's a portable hashing algo, so you can use it in PHP, MySQL, JavaScript, etc ad nauseum. Same with SHA1. Otherwise, any other hashing algorithms, whatever the source, must output the same string, or what good would a hash be? So if there is a custom built SHA256 hash method in an installation of MySQL for example, any number of SHA256 methods whether they are a PHP "built-in" or a script that produces this hash must all output the same hash value.


Add to that, the dev team us using MySQL's MD5 implementation, NOT PHP's:


$query = "SELECT id, Code FROM $table WHERE ((Code = '$Code')) AND ((Password = md5('$Password')))";


That is an unescaped function call in the string, i.e. it is inside the SQL statement, thus it is using MySQL's MD5.





if (!($link=mysql_pconnect($_SESSION['hostname'],$_SESSION['username'], $_SESSION['password']))) {


UGGHHHHH. Are they really doing this?? They have bigger problems than MD5.

I'd really like to see the code that is calling this 'login' function. Is the password passed into the function plaintext, i.e. not hashed? I'm curious if the hash is doubled up at some point, which I've seen.

The db should be using CHAR(32), not VARCHAR(40), if it's truly MD5.

Puffin the Erb has a really insightful comment, that at some point in time they may have switched to SHA1 because the field length is 40.


EDIT: To add to the "could be SHA1" theory, perform a LENGTH() on all of the `Password` field data. If the data is returned as 32 characters, you most likely have an MD5 hash. Otherwise, if it's 40, I'd guess SHA1. Anything other than those two values and who knows what happened.


SELECT
`Code`
, LENGTH(`Password`) AS pass_data_length
FROM `yourtable`
GROUP BY pass_data_length
LIMIT 100;


You can remove the LIMIT clause of course; I just added that in case you have 10000 records and you don't want it to parse through them all.

MDwebdev85
01-30-2010, 10:48 PM
Here's the index page with the form that calls the login.php


<?php session_start();
if (isset($_POST['Code'])){
include_once("login.php");
$Error = login($_POST['Code'], $_POST['Password']);
}



if(isset($_SESSION['AgencyID'])){
header("Location: http://".$_SERVER['SERVER_NAME'].dirname($_SERVER['PHP_SELF'])."/welcome.php"); //after success it redirects
exit;
}


?>
<html>
<head>
<title>Log In</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<link href="style.css" rel="stylesheet" type="text/css">
</head>
<body leftmargin="0" topmargin="0" onLoad="MM_preloadImages('Images/Header_r2_c1_f2.gif','Images/Header_r2_c2_f2.gif','Images/Header_r2_c2_f4.gif','Images/Header_r2_c2_f3.gif','Images/Header_r2_c3_f2.gif','Images/Header_r2_c3_f4.gif','Images/Header_r2_c3_f3.gif','Images/Header_r2_c4_f2.gif','Images/Header_r2_c4_f4.gif','Images/Header_r2_c4_f3.gif')">
<table width="100%" border="0" cellpadding="0" cellspacing="0">
<tr>
<td background="Images/head_fill.gif"><?php require_once('Header.html'); ?></td>
<td background="Images/head_fill.gif" class="LeftBar">&nbsp;</td>
</tr></table>
<table width="90%" height="350" border="0" cellpadding="0" cellspacing="0">
<tr valign="top">
<td width="125" bgcolor="AFB2AA"><img src="Images/left_empty.gif" width="125" height="20"></td>
<td width="1" bgcolor="#666666"><img src="Images/spacer.gif" width="1" height="1"></td>
<td width="1" class="main">
<p>&nbsp;</p></td>
<td class="main"><p><br>
</p>
<p>&nbsp;</p>
<p>
<?php

if(isset($Error))
echo '<p align="center"><font color="red">'.$Error.'</font></p>';

?>
</p>
<table width="200" border="0" align="center" cellspacing="0" cellpadding="0" class="main_noindent">
<tr>
<td> <form name="form1" method="post" action="index.php">
<p class="main">&nbsp;Agency Code:<br>
<input name="Code" type="text" id="Code" value="<?php echo $_POST['$Code'];?>" size="4" maxlength="4">
<br>
Password:<br>
<input type="password" name="Password">
</p>
<p align="center" class="main">
<input name="imageField" type="image" src="Images/login_button.gif" width="55" height="22" border="0">
</p>
</form></td>
</tr>
</table></td>
</tr>
</table>
<table width="100%" height="20" border="0" cellpadding="0" cellspacing="0" background="Images/bottom_bar.gif">
<tr>
<td>&nbsp;</td>
</tr>
</table>
</body>
</html>


btw..thanks for all of your help guys... 32 char hash....

I also just ssh'ed into the old production server that is working, described the table and it shows (40) as well...

MDwebdev85
01-30-2010, 11:32 PM
I'd really like to see the code that is calling this 'login' function. Is the password passed into the function plaintext, i.e. not hashed? I'm curious if the hash is doubled up at some point, which I've seen.

I just got en email from my contact person that I'm working with. He says he added a user into the db, along with a hash of a password. When viewed in the table, the hash is twice the length of the others...

bdl
01-30-2010, 11:45 PM
Ok very good, I can see the $_POST['Password'] value seems to be passed untouched into the function.

But here's something odd:


<input name="Code" type="text" id="Code" value="<?php echo $_POST['$Code'];?>" size="4" maxlength="4">


Notice that? It's using a $_POST index with the value of $Code, not Code. I don't think this effects the login, as it should only effect whether or not the value input was introduced into the form again, as on an error.

Some further suggestions:

Search all scripts for the string 'md5' (case insensitive search), see if there is a doubling up somewhere, or if it has simply been omitted. I don't see any mention of a stored procedure, but if one exists check that as well.
Start with some simple tests on the stored data itself, i.e. a known record with known data. If you can perform a simple manual test, such as


SELECT Code FROM sometable WHERE Password= MD5('knownPasswordValue');

If the above test yields a response, create a simple PHP script that has nothing to do with this codebase and run the same test. Then add a form to target the script and use POST request data.


As I'm getting ready to post this I see your comment:


I just got en email from my contact person that I'm working with. He says he added a user into the db, along with a hash of a password. When viewed in the table, the hash is twice the length of the others...


So what is the length of all the other stored `Password` field values? How could the developer tell if it was "twice the length", unless all the other values were < 1/2 the field size, i.e. 40 characters. Something is definitely wrong there. Let's say the field size is 40, and you store an MD5 hash in it. that's 32 characters, with 8 (theoretically) left over. With me so far? Ok, so if you somehow double the 32 char value, it's 64 chars and the 40 char limit will truncate the rest of the data. So my question again is, how long is the data stored in that field now?

MDwebdev85
01-31-2010, 12:15 AM
ok, I removed the $, which doesn't fix the log in issue, but it does show the undefined index error in the field itself:

<br /><b>Notice</b>: Undefined index: Code in <b>/usr/local/apache2/htdocs/training/index.php</b> on line <b>49</b><br />

I didn't find any stings contaning "md5" or "MD5" in any of the scripts other than the index script.

As for the password hash length, heres a screenshot of the selected "users" table...

http://imgur.com/sIRY5

The password in the "users" table, seems to have a 16 char hash...? and the new user that was manually added to the db has a 32char hash...? Bear with me, its all starting ro run together, been going at this for almost 24 hours straight now...

bdl
01-31-2010, 12:40 AM
The password in the "users" table, seems to have a 16 char hash...? and the new user that was manually added to the db has a 32char hash...?

Ok, so can we at least verify that the new, manually added hash value is indeed a MD5 hash value? It's repeatable with the MD5 function?

As far as the other 16 char values, I'm wondering if at some point in time they used the MySQL 'Password' function? The old (before MySQL v4.1) Password function output a 16 char string. I'm not certain what other hash algos might output a 16 char string.

MDwebdev85
01-31-2010, 12:47 AM
ok, so i went to hashcrack.com and input the password that he emailed me, the one he manually put ini the database. I hashed that password and it has 2 extra chars than what the hash in the database shows...BUT the varchar is shows 40 for the MD5 function...

MDwebdev85
01-31-2010, 01:18 AM
ok, now ive noticed something else....in the table there are 2 hashes...one is Mysql hash which is short 16 chars i think, then next to that is the md5 hash.. 32 chars...do you think my problem is that its only using one hash?

bdl
01-31-2010, 04:17 AM
ok, now ive noticed something else....in the table there are 2 hashes...one is Mysql hash which is short 16 chars i think, then next to that is the md5 hash.. 32 chars...do you think my problem is that its only using one hash?

You'll have to be more specific than that. Without giving up any relevant data, can you post the table schema along with sample data showing the hash values you're talking about?

MDwebdev85
01-31-2010, 04:23 AM
You'll have to be more specific than that. Without giving up any relevant data, can you post the table schema along with sample data showing the hash values you're talking about?


http://imgur.com/sIRY5

does that work?

MattF
01-31-2010, 08:52 AM
Just on a slight aside, have you thought of telling the customer to get a coder in who knows what they're doing to sort it, perchance? Doing amateur hour on a customers setup isn't exactly what a contractor should be doing.

_Aerospace_Eng_
01-31-2010, 08:59 AM
Just on a slight aside, have you thought of telling the customer to get a coder in who knows what they're doing to sort it, perchance? Doing amateur hour on a customers setup isn't exactly what a contractor should be doing.
Agreed. You said there is a field that is 16 chars long so maybe they doing some kind of salting?

MDwebdev85
01-31-2010, 09:12 AM
Just on a slight aside, have you thought of telling the customer to get a coder in who knows what they're doing to sort it, perchance? Doing amateur hour on a customers setup isn't exactly what a contractor should be doing.

yea i know, I've suggested that, my company knows i do web design as a "hobby" since by trade I'm a sys engineer, not a developer. But because of my big mouth i got roped into this one, and they're insisting that "i" get it working...yea lucky me...but at the same time I'm always willing to learn, and this is actually kind of challenging, which i like...they have a production system up and running currently, the one with the problem is on a dev box that in the end once the issues are resolved will go live. But since Ive been working on it, I personally would like to get it working. Sinc3e I've now dug into it, I kind of want to get it working, I don't give up.... The sys admin and our contact I'm working with "knows" I'm not an expert but we have a good relationship with them, but who knows...should have kept my mouth shut... lol

MDwebdev85
01-31-2010, 09:13 AM
Agreed. You said there is a field that is 16 chars long so maybe they doing some kind of salting?


well...i didnt see anything in any of the scripts about a salt...the only string i saw with any sort of hashing was on the login.php script which has the mysql query along with the md5 hash....

MattF
01-31-2010, 09:22 AM
As long as the customer knows... Have you checked the SQL logs yet? I'm still banking you have a version password mismatch. What versions of SQL are running on each box?

MDwebdev85
02-01-2010, 02:18 AM
As long as the customer knows... Have you checked the SQL logs yet? I'm still banking you have a version password mismatch. What versions of SQL are running on each box?

Old Red Hat server - 3.23.58

New Solaris server - 5.0.51

So after doing some further research i found the following:

http://dev.mysql.com/doc/refman/5.1/en/password-hashing.html

It seems that the mysql versions are causing the hashing issue.

MattF
02-01-2010, 02:23 AM
That's why I said to see what errors were being logged, back near the start of the thread. Always start with the system logs when fault finding.

MDwebdev85
02-01-2010, 02:25 AM
That's why I said to see what errors were being logged, back near the start of the thread. Always start with the system logs when fault finding.

yea i know, im working in uncharted territory (for me). I'm a windows systems guy and most of this is new. I appreciate all of the help you guys gave as well.

MattF
02-01-2010, 02:29 AM
No worries mate. It'll save you grief in future if you go the right way round though. :D The logs will always, (relevant reporting levels defined), reveal exactly what area you need to be checking. That's one of the reasons they are there.

MDwebdev85
02-01-2010, 02:31 AM
No worries mate. It'll save you grief in future if you go the right way round though. :D The logs will always, (relevant reporting levels defined), reveal exactly what area you need to be checking. That's one of the reasons they are there.

well ive figured out what the problem is. There are about 1,000 or so users...so i have to come up with a plan on how to re-generate the hashes..., hopefully without having to register all of the users again.

MattF
02-01-2010, 02:41 AM
Don't forget to change the column width too. You need it set at 41 instead of 40, judging by that page.

MDwebdev85
02-01-2010, 02:42 AM
Don't forget to change the column width too. You need it set at 41 instead of 40.

Right, already did that as well.

bdl
02-01-2010, 02:47 AM
Old Red Hat server - 3.23.58

New Solaris server - 5.0.51

So after doing some further research i found the following:

http://dev.mysql.com/doc/refman/5.1/en/password-hashing.html

It seems that the mysql versions are causing the hashing issue.

I was curious about this myself; however, this only applies if the MySQL "Password" function was used, as I mentioned in my previous post (http://www.codingforums.com/showpost.php?p=916780&postcount=18). This does not apply to MD5.

So again, was the MySQL "Password" function used at some point in time? Then they switched to MD5? If the "Password" function is still in use somewhere in the code, it will create a 41 character hash value, and the 40 char `Password` field will truncate the data.

MDwebdev85
02-01-2010, 02:57 AM
I was curious about this myself; however, this only applies if the MySQL "Password" function was used, as I mentioned in my previous post (http://www.codingforums.com/showpost.php?p=916780&postcount=18). This does not apply to MD5.

So again, was the MySQL "Password" function used at some point in time? Then they switched to MD5? If the "Password" function is still in use somewhere in the code, it will create a 41 character hash value, and the 40 char `Password` field will truncate the data.

in the table, I have the following:

Code | Password | PasswordFunction | MD5Function | Status |



the code being the ID to login with, the Password showed cleartext, PasswordFunction had a 16char hash, and the MD5Function had an MD5 hash.

bdl
02-01-2010, 03:13 AM
So the db is storing
a) the password in plaintext (wow),
b) the password as a 16char hash produced by the MySQL Password() function and
c) the password as a 32char hash produced by the MD5 function
????

Where in the last three pages did you mention this?

MDwebdev85
02-01-2010, 03:32 AM
So the db is storing
a) the password in plaintext (wow),
b) the password as a 16char hash produced by the MySQL Password() function and
c) the password as a 32char hash produced by the MD5 function
????

Where in the last three pages did you mention this?

I thought I did? maybe not... This is all new to me lol. Although I do enjoy the experience...

so this is where I stand now... trying to fix this cluster F* lol

EDIT** oh yea, it was in plain text originally, until I edited the password and then it shows a hash where it used to be clear text.

bdl
02-01-2010, 04:00 AM
so this is where I stand now... trying to fix this cluster F* lol

Right, I'm with you there.


EDIT** oh yea, it was in plain text originally, until I edited the password and then it shows a hash where it used to be clear text.

Yeah, I thought that was probably what you posted. No worries.

Anyway, this was the crucial piece of the puzzle IMHO. To be quite honest, the dev team needs to really revisit their policy on storing passwords. NEVER store the password as plain text. Slightly less heinous than that is to use a non-standard hash format, and omit a salt. I strongly recommend they alter the table to use only *one* password field, and use SHA256 with a salt as the value.

So does this square you away? Or are you still working on solving this issue?

MDwebdev85
02-01-2010, 04:04 AM
Right, I'm with you there.



Yeah, I thought that was probably what you posted. No worries.

Anyway, this was the crucial piece of the puzzle IMHO. To be quite honest, the dev team needs to really revisit their policy on storing passwords. NEVER store the password as plain text. Slightly less heinous than that is to use a non-standard hash format, and omit a salt. I strongly recommend they alter the table to use only *one* password field, and use SHA256 with a salt as the value.

So does this square you away? Or are you still working on solving this issue?

Well, I still cannot log in. I'm trying to sort through everything to see where it is hanging up still. Right now, I'm working on a DEV box, so I can pretty much do what ever I want to it. I just want to get to be able to log in, but securely at the same time...oh, and the DEV team you speak of...there is none... thats why I got roped into fixing this, along with my big mouth...

MDwebdev85
02-01-2010, 04:06 AM
Right, I'm with you there.
I strongly recommend they alter the table to use only *one* password field, and use SHA256 with a salt as the value.


any tips on how to do this? Or alter the table to use only the MD5Function?

bdl
02-01-2010, 04:32 AM
any tips on how to do this? Or alter the table to use only the MD5Function?

Well, sure. If you want to stick with MD5, alter the table so that there is only one `Password` field, and I'd name it something else like `UserPWord` or something a bit obscure. Those that try SQL injection on login pages looking for a weakness will guess 'password' or 'Password' as a table field every time. Alter it to use CHAR(32) as the data type.

If you want to keep it a straight MD5 hash, it's 32 chars. If you want to "salt" the input, the output MD5 hash is... 32 chars. So you're fine either way.

If you want to upscale to SHA1 (which isn't much but every little bit helps), use a CHAR(40) field. SHA1 is available in PHP, JavaScript (and most other languages) and MySQL.

If you want to go further and upgrade to SHA256, the field size must be 64 chars. SHA256 is NOT available by default in MySQL, but it could be custom compiled to use an implementation of it. You're not going to go to that trouble though, because an implementation is readily available in PHP via the hash() extension (http://www.php.net/hash).

Regardless, your PHP code should look something more like this for user registration or login:


$salt= 'RANDOMSTRINGOFCHARS';

$codeValue= 'some value';
$passwordHashValue= sha1( $salt . 'Your Password Here');
$otherValue= 'other value';
$sql= 'INSERT INTO table (codeField,pwordField,otherField) VALUES ';
$sql.= "('{$codeValue}', '{$passwordHashValue}', '{$otherValue}')";


So regardless of what hash mechanism you use, you can do it in PHP and use a salt. Just concatenate the salt value into the hash function and the output will always be 32, 40, 64, etc chars depending on the hash algo output.

Important factor here is that you MUST keep the salt value safe. If you store it in that one PHP script, it must not change or you'll be borked when you try to match password hash values later. It becomes an integral part of the password matching process. Salt the hash when you store it, you must salt it again to compare for logins. Remember that!

Please read up online on SQL injection (http://www.google.com/search?&q=sql%20injection) and hash salts (http://www.google.com/search?hl=en&q=hash+salts). If you're interested, I wrote this up (http://blang.name/hashsalt/) a few years back on how to implement a random salt to be used with your hash. It may be a bit obscure, but there is some good stuff in there IMHO. Note that article also shows how to make use of the aforementioned PHP hash() function.

MDwebdev85
02-01-2010, 04:43 AM
Well, sure. If you want to stick with MD5, alter the table so that there is only one `Password` field, and I'd name it something else like `UserPWord` or something a bit obscure. Those that try SQL injection on login pages looking for a weakness will guess 'password' or 'Password' as a table field every time. Alter it to use CHAR(32) as the data type.

If you want to keep it a straight MD5 hash, it's 32 chars. If you want to "salt" the input, the output MD5 hash is... 32 chars. So you're fine either way.

If you want to upscale to SHA1 (which isn't much but every little bit helps), use a CHAR(40) field. SHA1 is available in PHP, JavaScript (and most other languages) and MySQL.

If you want to go further and upgrade to SHA256, the field size must be 64 chars. SHA256 is NOT available by default in MySQL, but it could be custom compiled to use an implementation of it. You're not going to go to that trouble though, because an implementation is readily available in PHP via the hash() extension (http://www.php.net/hash).

Regardless, your PHP code should look something more like this for user registration or login:


$salt= 'RANDOMSTRINGOFCHARS';

$codeValue= 'some value';
$passwordHashValue= sha1( $salt . 'Your Password Here');
$otherValue= 'other value';
$sql= 'INSERT INTO table (codeField,pwordField,otherField) VALUES ';
$sql.= "('{$codeValue}', '{$passwordHashValue}', '{$otherValue}')";


So regardless of what hash mechanism you use, you can do it in PHP and use a salt. Just concatenate the salt value into the hash function and the output will always be 32, 40, 64, etc chars depending on the hash algo output.

Important factor here is that you MUST keep the salt value safe. If you store it in that one PHP script, it must not change or you'll be borked when you try to match password hash values later. It becomes an integral part of the password matching process. Salt the hash when you store it, you must salt it again to compare for logins. Remember that!

Please read up online on SQL injection (http://www.google.com/search?&q=sql%20injection) and hash salts (http://www.google.com/search?hl=en&q=hash+salts). If you're interested, I wrote this up (http://blang.name/hashsalt/) a few years back on how to implement a random salt to be used with your hash. It may be a bit obscure, but there is some good stuff in there IMHO. Note that article also shows how to make use of the aforementioned PHP hash() function.

Cool, thanks A LOT! I bookmarked your site and will definitely read it. The app is an internal application, so I think I want to keep it using MD5. Just want to get it working for the time being and then possibly upgrade later down the road. Now, all of the php scripts call to the first column of Password, if I am reading it correctly. Should I be dropping the PasswordFunction & MD5Function columns?

bdl
02-01-2010, 04:53 AM
Now, all of the php scripts call to the first column of Password, if I am reading it correctly. Should I be dropping the PasswordFunction & MD5Function columns?

Well, if the PHP scripts all use the first field (which I think is where all the confusion comes in), then I would drop the other two fields if you're certain you don't need those values. You can always keep them intact for later or copy them to another table for later reference. It would certainly be less confusing if there were only one field and if that one field has a consistent hashing mechanism storing the value. You can always (and you should) review and change the PHP code that references the database anyway, if you plan on using a hash salt as I mentioned.

MDwebdev85
02-01-2010, 04:56 AM
Well, if the PHP scripts all use the first field (which I think is where all the confusion comes in), then I would drop the other two fields if you're certain you don't need those values. You can always keep them intact for later or copy them to another table for later reference. It would certainly be less confusing if there were only one field and if that one field has a consistent hashing mechanism storing the value. You can always (and you should) review and change the PHP code that references the database anyway, if you plan on using a hash salt as I mentioned.

well where I was getting confused at was in all the scripts the queries call $Password.... which to me seems its just calling the first column..I'm unsure why the other 2 columns are even there, none of the code has changed between the dev server and the prod server it is currently running on.


EDIT***

I ran the hash that mysql generated for the password which has a "*" at the beginning which was the hash that mysql generated. If I take the "*" off of the hash and run it through hashcrack it gives the password. Is the "*" creating a problem?


Update*** getting closer...

I removed the md5 in the query:



$query = "SELECT id, Code FROM $table WHERE ((Code = '$Code')) AND ((Password =('$Password')))";


and can now log into the system. Although, I have to log in with the hash that is stored in mysql, with the "*" added. So thats where I'm at... calling it a night.



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum