I have a login form and I'm confused why my SQL Injection parameters doesn't work in here. I don't have any function or method for preventing the SQL Injection.
I made this login form for the testing of SQL injection and it's written in PHP.
Here is my code.
<?php
include("myconnection.php");
$error="";
if(isset($_POST["submit"]))
{
if($_POST["username"] == '' || $_POST["password"]== '')
{
$error='Please fill the blanks!';
}else
{
$username=$_POST['username'];
$password=$_POST['password'];
$sql="SELECT * FROM users WHERE username='$username' AND password='$password'";
$result=mysqli_query($db,$sql);
$row=mysqli_fetch_array($result,MYSQLI_ASSOC);
if(mysqli_num_rows($result)==1)
{
$login_user=$_POST["$username"];
header("location: myhome.php");
$error="Connected";
}
else
{
//$error="Incorrect Username/Password";
$message="Incorrect Credentials";
echo "<script='text/javascript'>$message</script>";
}
}
}
else
{
}
?>
I tried admin'OR'1'='1 in both username and password fields and any other possible basic injections but it doesn't work. I tried using the basic sql injection in most of working sites and it works, I'm just confused my my code doesnt accept sql injections.
And it gives me the same echo when you have an incorrect credentials.
I hope this is done for academic purposes as I have no idea why you would ever want to have this in any production websites. That being said it is probably because of the AND needing to also be true for the query to return any results. Where as if you had submitted admin'OR'1'='1 in the username field your query would look like
SELECT * FROM users WHERE username='admin'OR'1'='1' AND password='123'
That reads to me as WHERE username equals admin OR 1 equals 1 AND password equals 123. You would probably need to figure out how to also bypass that check as it will try to match password field still and vice versa the username field.
Seems odd to say but if you wanted to inject something maybe this would work in the username field injection' OR 1 LIMII 1# Which would make something like this
SELECT * FROM users WHERE username = 'injection' OR 1 LIMIT 1#' AND password = 'pass'
Essentially you are already injecting SQL, you are just not doing it in such a way that is yielding the results you want. Try echoing the query and running it directly in the mySQL CLI to see what the result set is and if it is a valid query. Maybe play around with the query there to try and obtain your intended injection.
Related
I'm carrying out a code review of a site and have found a possible SQL injection vulnerability. I should point out that this is for a CTF exercise so this might be a bit of a noob question. The code below queries the database for the username and password and if it finds a match on both it allows you to login.
$username = mysql_real_escape_string((string) $_POST["username"]);
$password = md5($_POST["password"]);
$query = #mysql_query("SELECT * FROM user WHERE username='$username' AND pwd='$password'");
if (#mysql_num_rows($query) !== 1) {
$html = "Your username or password is wrong<br>".ShowLoginForm();
return;
} else {
$html = "Logged in. continue</font>";
}
I have found that it is possible to log in as any user if the following code is injected directly to the database:
SELECT * FROM user WHERE username='admin' OR 1=1 '' AND pwd='anyrandomtext'
The challenge here is breaking out of the mysql_real_escape_string() statement and to do so I would like to see exactly what is being passed to the server once the input has been modified by this function. Is there a way to do this? The site is running on Apache.
Dunno what you "found" but in the code snippet you posted here there is no vulnerability.
The challenge here is breaking out of the mysql_real_escape_string() statement
Mission impossible.
There is no breach and nothing to break. Move on to the next exercise.
After successfully verifying username exists in the database, I need to verify whether the password matches as well. Therefore, I need to retrieve the hashed password from the database, right? Or do I have other choices?
I'm using PHP 5.5 API bcrypt for hashing. My code would give me a 500 internal server error when I get the password from database. How do I do this correctly?
Here's my php code:
// If found username, check password, else respond invalid username
if($countRows!==0){
// Get hash from database
// Prepare statement
$stmt = $conn->prepare('SELECT password FROM users WHERE username = ?');
// Bind
$stmt->bind_param('s', $ps_username);
// Set Parameters
$ps_username = $username;
// Execute
$hash = $stmt->execute();
// Check password
if (!password_verify($password, $hash)) {
if($error != ""){
$error .= '<br>';
}
$error .= 'The user or password you entered do not match, please try again.';
}
else {
echo 'OK';
// Session start
// Redirect user to profile/homepage
}
}
And can someone recommend something that I can learn SQL commands? I can't find a good place for that.
execute() does not return any column data. It returns a boolean (true/false). This is where your code block first fails:
$hash = $stmt->execute();
You can view examples on how to fetch data from the result set here: http://php.net/manual/en/mysqli-stmt.fetch.php
An example being:
$stmt->execute();
$stmt->bind_result($hash);
$stmt->fetch();
In response to:
And can someone recommend something that I can learn SQL commands?
This is pretty much off topic for Stackoverflow but the PHP manual for mysqli can show you how to use the mysqli API fairly well with plenty of examples. If you want to learn the Structured Query Language itself, then there are plenty of external resources for that, including MySQL's documentation.
I am using WYSIWYG Webbuilder 8 to construct a website. Part of the website will be restricted access to registered users only. To this end I have created a MySQL database. I also have a sign-up form. When a new user wishes to sign-up I would like to have the username automatically checked against the database to make sure it doesn't already exist. I intend doing this using an AJAX function as the WYSIWYG software has this option built in. What I need to build myself and this is where I'm struggling is the validate.php that the AJAX command will go to.
I have something like this at present (please excuse my ignorance!):
<?php
$username = $_POST['data'];
// TODO: lookup username in database...
if ($username == 'user')
{
echo "true";
}
else
{
echo "false";
}
?>
I have no real idea if this is adequate or secure. I have been reading some scary stuff about sql injection and other black arts involving the use of forms and I'd like to avoid pitfalls if possible.
Would some kind soul please have a look at my request and help me out? I'm not a programmer by any stretch of the imagination and I'm way out of my depth here.
Thanks in advance for your help
You want to use something that will handle the chatter between your application and the database for you. One of the best tools available for this today is the PDO library, specifically PDO-MySQL for your usage. It will handle escaping and SQL injection issues for you by using parameterized (prepared) statements
Here's an example of connecting to a database and issuing a query in MySQL
$db = new PDO('mysql:host=localhost;dbname=dbname;charset=UTF-8', 'username', 'password');
$statement = $db->prepare('SELECT user_id FROM users WHERE username = :username LIMIT 1');
$statement->bindValue(':username', $_POST['data']);
$statement->execute();
if (false == $userId = $statement->fetchColumn()) {
// No matching username was found in the database
} else {
// A matching username was found in the database
// $userId contains the matching user ID
}
Knowing how to pass this back to your JS/AJAX integration could be dependent on what framework (if any) you are using and what format you would like that data in
EDITThanks to the comments below it has been figured out that the problem lies with the md5, without everything works as it should.
But how do i implent the md5 then?
I am having some troubles with the following code below to login.
The database and register system are already working.
The problem lies that it does not find any result at all in the query.
IF the count is > 0 it should redirect the user to a secured page.
But this only works if i write count >= 0, but this should be > 0 , only if the user name and password is found he should be directed to the secure (startpage) of the site after login.
For example root (username) root (password) already exists but i cannot seem to properly login with it.
<?php
session_start();
if (!empty($_POST["send"]))
{
$username = ($_POST["username"]);
$password = (md5($_POST["password"]));
$count = 0;
$con = mysql_connect("localhost" , "root", "");
mysql_select_db("testdb", $con);
$result = mysql_query("SELECT name, password FROM user WHERE name = '".$username."' AND password = '".$password."' ")
or die("Error select statement");
$count = mysql_num_rows($result);
if($count > 0) // always goes the to else, only works with >=0 but then the data is not found in the database, hence incorrect
{
$row = mysql_fetch_array($result);
$_SESSION["username"] = $row["name"];
header("Location: StartPage.php");
}
else
{
echo "Wrong login data, please try again";
}
mysql_close($con);
}
?>
The best thing you can do in such situations is trying to find out where the problem lies.
So, you could proceed by steps and do the following:
1) start your script with a print_r($_POST), to see what variables are passed by post (by absurd, the problem might even be related to the 'send' guard parameter you have ..IE a form being sent through get)
2) Assign your query to a variable (...and don't forget to escape parameters!) and print it to screen; and then exec it on mysql (or phpmyadmin) to see what results they give.
As a side note, as someone already pointed out, this code might be subject to SQL-injection, so you might consider using prepared statements; see here: quick intro
Your login code is good.
But you also need to use md5() function BEFORE storing the password in the database. So when you are inserting the user record in the DB , apply the md5() to the password , save in the DB. Now when you will try to find the record on login, it will match correctly.
You should rewrite this with mysqli or PDO and using a newer hash function as well as a salt. MD5 is very widely used and is a target for crackers.
Can anyone see anything wrong with this login script:
public function login($username, $pass, $remember) {
// check username and password with db
// else throw exception
$connect = new connect();
$conn = $connect->login_connect();
// check username and password
$result = $conn->query("select * from login where
username='".$username."' and
password=sha1('".$pass."')");
if (!$result) {
throw new depException('Incorrect username and password combination. Please try again.');
} else {
echo $username, $pass;
}
To explain:
At the moment the script is allowing anything through. In other words the query is returning true for any username and password that are passed to it.
I've put the echo statement just as a check - obviously the script would continue in normal circumstances!
I know that the connect class and login_connect method are working because I use them in a register script that is working fine. depException is just an extension of the Exception class.
The function login() is part of the same class that contains register() that is working fine.
I know that the two variables ($username and $pass) are getting to the function because the echo statement is outputting them accurately. (The $remember variable is not needed for this part of the script. It is used later for a remember me process).
I'm stumped. Please help!
UPDATE
Thanks for those responses. I was getting confused with what the query was returning. The complete script does check for how many rows are returned and this is where the checking should have been done. Everything is now working EXCEPT for my remember me function. Perhaps someone could help with that?!?! Here is the full script:
public function login($username, $pass, $remember) {
// check username and password with db
// else throw exception
$connect = new connect();
$conn = $connect->login_connect();
// check username and password
$result = $conn->query("select * from login where
username='".$username."' and
password=sha1('".$pass."')");
if (!$result) {
throw new depException('Incorrect username and password combination. Please try again.');
}
if ($result->num_rows>0) {
$row = $result->fetch_assoc();
//assign id to session
$_SESSION['user_id'] = $row[user_id];
// assign username as a session variable
$_SESSION['username'] = $username;
// start rememberMe
$cookie_name = 'db_auth';
$cookie_time = (3600 * 24 * 30);*/ // 30 days
// check to see if user checked box
if ($remember) {
setcookie ($cookie_name, 'username='.$username, time()+$cookie_time);
}
// If all goes well redirect user to their homepage.
header('Location: http://localhost/v6/home/index.php');
} else {
throw new depException('Could not log you in.);
}
}
Thanks very much for your help.
UPDATE 2!
Thanks to your help I've got the main part of this script working. However, the remember me bit at the end still doesn't want to work.
Could someone give me a hand to sort it out?
$username, $pass and $remember are all short variable names that I assigned before passing them to the function to save writing $_POST['username'] etc. everytime. $remember refers to a checkbox.
What does $conn->query() return, a MySQL resource object like mysql_query() does? If so then it'll always compare "true". mysql_query() only returns FALSE if the query completely fails, like it has a syntax error or a table doesn't exist.
To check if you got any results you need to try to fetch a row from the result set and see if you get anything, via whatever your equivalent of mysql_fetch_row() is.
Important: Your script is vulnerable to SQL injection attacks, or even just odd usernames like o'neil with an apostrophe. You should escape all variables in a query with mysql_real_escape_string() (or equivalent) to make sure your query doesn't get messed up by special characters. Or, even better, use prepared statements which look like
select * from login where username=? and password=sha1(?)
Re: UPDATE
Variables from a form are available via either $_GET or $_POST, depending on which method was used to submit the form. Try if (isset($_POST['remember'])) to see if that check box was checked.
Important: I see that you tried to use a bare $remember to see if the check box was checked. That suggests to me that you are trying to take advantage of the register_globals feature in PHP which makes your GET and POST variables accessible via regular variable names. If that is the case you should heed the warning in the PHP manual!
WARNING
[register_globals] has been DEPRECATED as of PHP 5.3.0 and REMOVED as of PHP 6.0.0. Relying on this feature is highly discouraged.
Use $_GET and $_POST instead. I could tell you how to make if ($remember) work, actually, but given the inherent evil-ness of register_globals I'm not gonna! ;-)
Your query is open for sql-injections...
SELECT * FROM users WHERE
username = '' OR 'a' = 'a'
AND password =
sha1('guessAnyPassword')
I'd also check your result, and base the action on how many records were returned.
if (mysql_num_rows($result) > 0)
In php most queries only return False if there was an error executing them. Your query is returning a value, probably an empty array of values. This is not a false value as far as your if statement is concerned.
Check how many rows are returned. The function to do this will depend on your abstraction layer (connect class etc...)