I've done some Google'ing and it's brought up nothing so I'm asking here.
I'm trying to run this query (the language is PHP):
SELECT * FROM table WHERE MD5(field1) = '$var'
It's not returning any rows,
Any help is greatly appreciated.
P.S.
I've tried some variations such as "SELECT field1 as name FROM table WHERE MD5(name) = '$var'" but it still doesn't work.
EDIT:
I figured it out. A lot of the answers to this question are assuming a lot of things such as 1. it's for a login system (it's for something related, but not for a login system), 2. i'm not hashing my values before saving them in the db (I am, but this certain situation requires me not knowing the plaintext, thus requiring me to MD5 the column in the SQL query). A lot of these assumptions were made because I simplified the hell out of the example to convey my question. Thank you to those who tried answering.
Yes, MySQL has a built in MD5 function.
<?php
...("SELECT * FROM table WHERE MD5(password) = '$password';") or die(...
?>
should work fine. If it's not returning any rows then you must be doing something else wrong.
It would seem that you are MD5ing the wrong value. The password in the DB should not be plain text, it should have been hashed and that value stored. The query as you have it written is hashing a hash then comparing it to the plain text entered by the user. Try this instead -
SELECT * FROM table WHERE password = MD5($password);
As Vincent mentioned, it would make sense to hash the password before sending the query to the DB server.
$passhash = MD5($password);
SELECT * FROM table WHERE password = $passhash;
Related
Ok,
So, i'm a little unsure on this.
I have a url parameter username.
and I have this statement
SELECT * FROM users WHERE user_hash = md5($_GET['username'])
Is this secure?
Upon account creation an md5 hashed version of the username and the password are stored.
I'm confused as this seems so simple, if md5 stops sql injection why isn't username and password always saved in hash form?
Yes, this will avoid SQL injection, because md5() always returns a string of hex code.
But it isn't a general solution to SQL-injection. You would have to encode almost all the data in your tables in MD5 format. For instance,
$sql = "UPDATE users SET fullname = '" . md5($_GET['fullname']) . "'
WHERE id = '" . md5($_GET['id']) . "'";
But MD5 is a one-way hash, so there would be no way of displaying the full name that was stored this way.
Short answer is no, MD5 does not prevent SQL injection. Proper coding is the best way to handle this.
Reason being in this case is that your query string parameter is allowing direct access to the sql. E.g. what if the user sends you:
?username=%27a%27);DROP%20TABLE%20users;%20--
That fakes the MD5 function out and drops the users table. Of course they have to know somethings about your database in order to do this. The correct way to handle it would be to MD5 the value before it went into the SQL. In PHP it would be something like this:
$username = $GET['username'];
$hashed_username = md5($username);
$sql = "SELECT * FROM users WHERE user_hash = '$hashed_username'"
Or the best solution would be to use bound variables in queries where you let the SQL libraries handle the translation. If you are using PHP, look into PDO bindParam, http://php.net/manual/en/pdostatement.bindparam.php
BTW, your SQL won't work because you would need to quote (') the get variable in the SQL.
I'm confused as this seems so simple, if md5 stops sql injection why isn't username and password always saved in hash form?
The reason is because simple operations like searching for a user with a particular name would be impossible.
SELECT * FROM users where user LIKE '%cat%'
Would find all users with the word cat within it.
Also simple administration would be impossible, you can't even view a roster of all users.
Ok,
So, i'm a little unsure on this.
I have a url parameter username.
and I have this statement
SELECT * FROM users WHERE user_hash = md5($_GET['username'])
Is this secure?
Upon account creation an md5 hashed version of the username and the password are stored.
I'm confused as this seems so simple, if md5 stops sql injection why isn't username and password always saved in hash form?
Yes, this will avoid SQL injection, because md5() always returns a string of hex code.
But it isn't a general solution to SQL-injection. You would have to encode almost all the data in your tables in MD5 format. For instance,
$sql = "UPDATE users SET fullname = '" . md5($_GET['fullname']) . "'
WHERE id = '" . md5($_GET['id']) . "'";
But MD5 is a one-way hash, so there would be no way of displaying the full name that was stored this way.
Short answer is no, MD5 does not prevent SQL injection. Proper coding is the best way to handle this.
Reason being in this case is that your query string parameter is allowing direct access to the sql. E.g. what if the user sends you:
?username=%27a%27);DROP%20TABLE%20users;%20--
That fakes the MD5 function out and drops the users table. Of course they have to know somethings about your database in order to do this. The correct way to handle it would be to MD5 the value before it went into the SQL. In PHP it would be something like this:
$username = $GET['username'];
$hashed_username = md5($username);
$sql = "SELECT * FROM users WHERE user_hash = '$hashed_username'"
Or the best solution would be to use bound variables in queries where you let the SQL libraries handle the translation. If you are using PHP, look into PDO bindParam, http://php.net/manual/en/pdostatement.bindparam.php
BTW, your SQL won't work because you would need to quote (') the get variable in the SQL.
I'm confused as this seems so simple, if md5 stops sql injection why isn't username and password always saved in hash form?
The reason is because simple operations like searching for a user with a particular name would be impossible.
SELECT * FROM users where user LIKE '%cat%'
Would find all users with the word cat within it.
Also simple administration would be impossible, you can't even view a roster of all users.
the code below is unable to find a matching record when it "should":
$result = mysql_query("SELECT * FROM $tbl_Name WHERE userID = '$userID' AND userKey = password('$user_password')"); // where $user_password = god12345 for example
userID comparison works fine if I remove the AND....
password comparison fails above. I am certain that when the user was created the password was hashed using password().
If I set $user_password to the actual hash stored in the data and compare literals, it works.
... AND userKey = '$user_password' // where $user_password = *29A59C23ED11F7E2510 for example
This is destroying me. Obviously I don't want to compare literals.
You can't expect password() to work when it's being interpreted as text.
Try:
$result = mysql_query("SELECT * FROM $tbl_Name WHERE userID = '$userID' AND userKey = '" . password('$user_password') . "'");
I'm not 100% sure if this will answer the question but here goes.
When a user signs up you hash the password, so on the database the password is a crazy looking string. This can't be reversed so if you want to check if a password entered is right you'll have to hash the new input from the user login in and then compare that hash with the one on your database.
Does that help?
Instead of using the mysql PASSWORD function which is in my opinion very weak, try to save your passwords into the database encrypted by php. For example:
$password = md5('MyApplicationSalt'.$user['creationdate'].$newpassword);
mysql_query('UPDATE users SET password = "'.$password.'" WHERE id = '.$user['id']);
The main reason to do this is:
Creating a much stronger hash of your password: Using PASSWORD from mysql means that there is no additionnal salting done. If someone were to create a table of all possible passwords from 1-10 characters and then PASSWORD() them and compare to your stolen data, they could reverse the passwords. Using a salt will prevent this in the event that only your data is stolen. Obviously, if code is stolen, it doesn't protect it, the person can search for the hash salt and still reverse it.
Another reason would be to be able to log correctly what you are doing. For example, try logging your SQL query using the method before and check if the data is always the same. It should... if it's not it might be that you have special characters laying somewhere in your string when comparing or when updating...
Good luck
Thanks to everyone who answered, particularly Mathieu who inspired me to realize my error.
userKey VARCHAR(20) BINARY NOT NULL
As of MySQL 4.1, the PASSWORD() function has been modified to produce a longer 41-byte hash value.
So the problem was... the value stored in the dbase when I created the user was limited to 20 characters while the inputted value for login comparison was a longer 41-byte hash value.
Prior to MySQL 4.1, password hashes computed by the PASSWORD() function are 16 bytes long.
I was expecting the varchar(20) to hold all of the hash since the book I'm using as a guide was written in 2000....time to buy a new book.
I'm writing a script in PHP to allow a user to change their password. I make them enter their old password (even if they are logged in already) and then the new password. I'm trying to compare the old password and then update the field to the new password without running two separate queries, but my code isn't working like I expected. Is there a bug here? Or is this not allowed for some reason? What do you suggest?
mysql_query("UPDATE users SET userpass = '$encryptedPW' WHERE userid = '$uid' AND userpass = '$currentPW'");
I could see if mySQL performed the tasks in the order they're written, but it has to find the line before it can update it, right?
Thank you very much!
Billy
ETA: Sorry! Typo!
What does the actual generated query look like? Did you check if the query query succeeded?
$result = mysql_query("UPDATE ....") or die(mysql_error());
if (mysql_affected_rows() != 1) {
die("Failed to change password");
}
The or die() portion will handle any sql syntax errors, while the affected_rows will check if something did get updated. If the affected row count isn't 1 (assuming you're not allowing duplicate username/password pairs), then something didn't work right. 0 = no affected rows, no changes made. >1 = you've got duplicate user/password pairs.
Also make sure that you're comparin apples to apples. If you're storing the passwords in encrypted/hashed form, then you'll have to compare hashed/encrypted passwords for the results to make sense.
... WHERE password='letmein'
would fail if the password is actually stored as encrypted binary garbage.
from your code, I see that you use encrypted passwords. Check that you encrypted both passwords.
Furthermore, you have userpass and user_pass in your query. These are two "different" columns.
You have the right idea here, but I would advise against (for security concerns) using mysql_query() with unfiltered input. I'd rather see you using a prepared statement.
From your above query, however, it seems as if you have two different columns, user_pass and userpass. That may be the source of your woes for now.
Ok, starting fresh >
For our first assignment in a System Security class, we have to hack into the professors "cheaply organized" sql database. I know the only user is "admin" and picking a random password, the select statement generated in the php is:
select user_id from user where user_username = 'admin' AND user_password = md5('noob')
Now, I go for the basic starting point of trying to hack the crappy login with "admin'--"
select user_id from user where user_username = 'admin'--' AND user_password = md5('noob')
but the actual value being pushed to the database is
select user_id from user where user_username = 'admin\'--' AND user_password = md5('noob')
which doesn't help. The server uses POST to get the values from the form. I've already bypassed any value processing on my side of the send by disabling javascript.
There does not appear to be anything in the php that modifies the input in any way.
Assuming the select statement is part of a login form, then most likely it's generated something like this:
$user = $_POST['username'];
$pwd = $_POST['password'];
$query = "SELECT .... WHERE user_username='$user' AND user_password=md5('$pwd')";
which means, you could hack in by entering:
noob') or ('a'='a
for the password, giving you
SELECT .... AND user_password=md5('noob') or ('a'='a')
^^^^^^^^^^^^^^^^^-- your contribution
The actual password might not match, but 'a' will always equal itself, so the where clause will succeed and match a record based purely on the username and return the admin user's user_id.
As others had mentioned the escaping that you see is not the OS, but some form of encoding done in PHP (likely magic quotes, but could be a straight call to addslashes()).
Basically what you need to do is send in a form of quote that will not be escaped. You should research why one would use mysql_escape_string() rather than addslashes() and/or check this out: http://forums.hackthissite.org/viewtopic.php?f=37&t=4295&p=30747
Try ' OR 1; -- as user name. Imagine what the SQL query from such a user name looks like.
This has nothing to do with the operating system. The operating system simply runs the PHP package. PHP is what does sanitization, etc.
Have you tried submitting the following string for user_username?:
admin' OR 1=1-- #assuming mysql
Would yield a query:
select user_id from user where user_username = 'admin' OR 1=1 --' AND user_password = md5('noob')
In mysql (assuming the database type), -- is a comment, so everything after 1=1 is ignored. As a result, you've successfully gained access.
If php magic quotes are on, however, this will be slightly more difficult. You will need to submit characters outside of utf-8 or attempt overflows or submitting null bytes.
You could also try a bit of googling after entering a string that will error out the admin and use part of message that comes back as the key words.
You could also use the http://gray.cs.uni.edu/moodle/mod/forum/discuss.php?d=106 fourm to ask questions so the whole class can benifit!
if you can figure out how to upload files that would be great! I want to get c99.php up to really do some damage!
you could also try some "hash" verse "dash dash"