It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 11 years ago.
I was wondering what could of allowed a user to hack my site, they changed my username, personal info and password. Can someone give me some suggestions on what it could have been. I'm using PHP MySQL and HTMLPURIFIER.
Here is the login script.
<?php
if (isset($_POST['submitted'])) { // start of submit conditional.
require_once (MYSQL);
// Validate the username or email address:
if (!empty($_POST['login']) && strlen($_POST['login']) <= 255) {
$e = mysqli_real_escape_string($dbc, $purifier->purify(strip_tags($_POST['login'])));
} else if(!empty($_POST['login']) && strlen($_POST['login']) >= 256) {
$e = FALSE;
echo '<p>Your username or email address cannot exceed 255 characters!</p>';
} else {
$e = FALSE;
echo '<p>You forgot to enter your username or email address!</p>';
}
// Validate the password:
if (!empty($_POST['pass']) && strlen($_POST['pass']) <= 255) {
$p = mysqli_real_escape_string($dbc, $_POST['pass']);
} else if(!empty($_POST['pass']) && strlen($_POST['pass']) >= 256) {
$p = FALSE;
echo '<p>Your password cannot exceed 255 characters!</p>';
} else {
$p = FALSE;
echo '<p>You forgot to enter your password!</p>';
}
if(($e != FALSE) && ($p != FALSE)) { // check pass
$pass_salt = "SELECT users.password, users.salt FROM users JOIN contact_info ON contact_info.user_id = users.user_id WHERE (contact_info.email = '" . $e . "' OR users.username = '" . $e . "') AND users.active IS NULL";
$ph = mysqli_query($dbc, $pass_salt) or trigger_error("Query: $pass_salt\n<br />MySQL Error: " . mysqli_error($dbc));
while($row = mysqli_fetch_array($ph)){
$password = $row['password'];
$salt = $row['salt'];
}
if(!empty($salt)) {
$sha512 = hash('sha512', $p . $salt);
}
if(!empty($password) == !empty($sha512)){
$user_pass = TRUE;
} else {
$user_pass = FALSE;
}
}
if(isset($user_pass) && ($user_pass == TRUE) && !empty($salt)) { // If everything's OK.
// Query the database:
$q = "SELECT users.user_id, users.first_name, users.user_level FROM users JOIN contact_info ON contact_info.user_id = users.user_id WHERE (contact_info.email = '" . $e . "' OR users.username = '" . $e . "') AND users.password = '" . $sha512 . "' AND users.active IS NULL";
$r = mysqli_query ($dbc, $q) or trigger_error("Query: $q\n<br />MySQL Error: " . mysqli_error($dbc));
if (#mysqli_num_rows($r) == 1) { // A match was made.
// Register the values & redirect:
$_SESSION = mysqli_fetch_array ($r, MYSQLI_ASSOC);
// check if user is logged in then update the old login date
$u = "UPDATE users JOIN contact_info ON contact_info.user_id = users.user_id SET users.last_login = NOW(), users.deletion = 0, users.deletion_date = NULL WHERE (contact_info.email = '" . $e . "' OR users.username = '" . $e . "') AND users.password = '" . $sha512 . "' AND users.active IS NULL";
// save the info to the database
$r = mysqli_query ($dbc, $u);
mysqli_free_result($r);
mysqli_close($dbc);
$url = BASE_URL . 'home/index.php'; // Define the URL:
header("Location: $url");
exit(); // Quit the script.
} else { // No match was made.
echo '<p>Either your username, email address or password entered do not match those on file or you have not yet activated your account.</p>';
}
} else { // If everything wasn't OK.
echo '<p>Please try again.</p>';
}
mysqli_close($dbc);
} // end of submit conditional.
?>
You should be aware of SQL Injection. That is what came up to my mind first (noticing the use of MySql). To prevent this you have to sanitize users input by using mysql_real_escape_string() (different mysql_escape_string() which is considered as deprecated). Despite this solution I'd suggest you to use either PDO or Mysqli (I usually discourage this one) in order to just fix the SQL Injection problem by the usage of Prepared Statements.
Then you should be probably aware of XSS (cross-site-scripting) that could have "injected" in your code some sort of malicious Javascript script. You can fix this a little with htmlspecialchars() that make HTML tags (such as <script>) not considered as HTML tags.
Also take a look at this Vulnerability list for PHP.
P.S.
In order to make your code more readable and "right" I'd suggest you to change strlen($_POST['login']) >= 256 into strlen($_POST['login']) > 255 which is the same but makes the reader understand immediately that the real limit is not 256 but 255.
First, make sure they can't perform an SQL injection. This is probably what they did. This is normally caused from input fields that are executed. The person doing it just has to type in an SQL command.
You can see details on this here.
Oh, welcome to StackOverflow.com! I hope you enjoy the site!
In addition to the DalexL answer, please check that you have a strong password to connect to your database.
I'm pretty sure this didn't happen to the original poster, but deceptive companies have been known to send "bills" to companies with web sites. The fine print in the "bills" transferred the domain from the company to the deceptive company.
Here's one example: Domain Registry of America scam
If you allow users to upload images, you may have been a victim of a GIF exploit. If your server settings aren't secure, viewing a GIF with embedded PHP code in it will execute the code. Check if you can find any .gif.php (or .php.gif) files on your system, they may still be there if the hacker forgot to clean up after himself.
If HTMLPURIFIER is implemented correctly for all db facing inputs then you should evaluate how you are transmitting your logins. Are you pre-hashing before submit on the client side.
I would assume that the reason is there is an input on a form that is unfiltered and it is letting some SQL injected code through.
Related
When logging into my Unity project, I get error "Array index is out of range" at this line of my C# code
if (www.text[0] == '0')
www.text pulls from this php script (www.text is returning null when debugging so it must be an error with my script).
<?php
$con = mysqli_connect('localhost', 'root', 'root', 'unityaccess');
//check that connection happened
if (mysqli_connect_errno())
{
echo "1: Connection failed"; //error code #1 = connection failed
exit();
}
$username = $_POST["name"];
$password = $_POST["password"];
//check if name exists
$namecheckquery = "SELECT username, salt, hash, score FROM players WHERE
username = ' " . $username . "';";
$namecheck = mysqli_query($con, $namecheckquery) or die("2: Name check query
failed"); //error code #2 - name check query failed
if (mysqli_num_rows($namecheck) != 1)
{
echo "5: Either no user with name, or more than one";
exit();
}
//get login info from query
$existinginfo = mysqli_fetch_assoc($namecheck)
$salt= $existinginfo["salt"];
$hash = $existinginfo["hash"];
$loginhash = crypt($password, $salt);
if($hash != $loginhash)
{
echo "6: Incorrect password"; //error code #6 - password does not hash to
match table
exit();
}
echo "0\t" . $existinginfo["score"];
?>
I'm following a tutorial and am new to php and sql.
https://www.youtube.com/watch?v=NVdjlXgbiMM
In the tutorial his code is exactly the same as mine. Looking at it myself I would assume that the echo "0\t" . $existinginfo["score"]; is the problem, and that putting a tab isn't separating it into an array. In his code he runs it and it's fine though, so I must be missing something else?
You have a space after the ' in the query on this line:
$namecheckquery = "SELECT username, salt, hash, score FROM players WHERE
username = ' " . $username . "';";
So if the username entered is user1 it will look in the database for <space>user1 (where <space> means a space character). Remove that space.
$namecheckquery = "SELECT username, salt, hash, score FROM players WHERE
username = '" . $username . "';";
Actually, it would be even better if you learned to use prepared statements, then problems like this are nearly impossible, as well as making the code safe from SQL-injection. Read How can I prevent SQL injection in PHP?
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I've been practicing security-related subjects and this challenge has befuddled me. Note: I can't access any PHP source code, nor can I edit it. I'm only able to view it.
The following is given:
I have two inputs, "user" and "pass"
After 30 times the form is sent, the salt, the hashes and the final solution change. So bruteforce isn't an option (sadly!)
#The bottom of the page (not shown in the code for some reason), it echos that it found 9 users (calling the getnumberofusers() function)
I've managed to extract this:
username = root
hashed password = 551e18b35e17017742a8ce4ed27f626e
Token (possibly salt?) = 0St31ez14wOT6jTh
What I've attempted thus far with unsuccessful results:
Using SQL injection, select a known MD5 collision as password and send its counterpart as "pass", however the salt is bothering this process. Clearly I couldn't bruteforce this because after 30 attempts the salt would change.
I tried finding the entire list of users but it doesn't print the output anywhere (only errors)
This is the code we receive:
<?php
//by Mawekl
//Objective: login as root.
//Objective is NOT:
// - Blind SQLI
// - Bruteforce password/salt/id
#WARNING
#ANTI-BLIND
#for every 30 queries
#all hashes, salt
#and final solution
#will be reset.
function getnumberofusers()
{
$q = "SELECT 1 FROM `sqlinjection1`";
$r = mysql_query($q);
return 'Number of users: ' . mysql_num_rows($r);
}
function getinfo($user)
{
$q = "SELECT `id`, `password` FROM `sqlinjection1` WHERE `username`='$user'";
$r = mysql_query($q);
if(!$r)
return mysql_error();
$r = mysql_fetch_array($r);
if(!$r)
return "Username doesn't exists.";
return $r;
}
function getfullinfo($id)
{
$q = "SELECT * FROM `sqlinjection1` WHERE `id`=$id";
$r = mysql_query($q);
if(!$r)
return mysql_error();
$r = mysql_fetch_array($r);
if(!$r)
return "What the hell?!";
return $r;
}
function confirmpassword($pass, $passcorrect, $salt)
{
$pass = md5(md5(md5($pass)).$salt);
return $pass===$passcorrect;
}
function challenge($user, $pass)
{
$info = getinfo($user);
if(!is_array($info))
return $info;
$confirm = confirmpassword($pass, $info['password'], $_ENV['ST_SALT']);
if(!$confirm)
return 'Wrong password!';
$info = getfullinfo($info['id']);
if(!is_array($info))
return $info;
$returnmessage = "Welcome " . $info['username'] . "!" . PHP_EOL .
$info['welcomemessage'] . PHP_EOL;
return $returnmessage;
}
?>
Any help is appreciated, and if you have any questions I'd love to clarify my question!
now we can select the welcome message/anything else using sql
$user="1' or exp(~(select * from (select welcomemessage from sqlinjection1 where username='user1')a)) or '1'='1"
but when we found a Secret token (that i wrote up there ^) hidden in the data base and tried using it this way:
The idea: select the hashed version as password using SQL injection so the hashes match.
Here's the code:
<?php
$salt = "v5IftFb0Tx1Jhp4b";
$hashed = "";
$p = "hello";
$hashed = md5(md5(md5($p)).$salt);
echo "The Query: " . "' AND 1 = 0 UNION SELECT `id`, '$hashed' AS `password` FROM sqlinjection1 WHERE `username` = 'root';#";
?>
It echoes the query which we put in the "username" field. In the "password" field we enter "hello".
However it's not working...
but it did not work, anyone has any idea what else can we do? How can we find out what / modify the $_ENV["ST_SALT"]? as appearently its not the secret token that we found
So I have a basic database, passwords are hashed using just the basic crypt() function (not good practice, right? but still).
I'm now trying to make a login page. This is my basic code.
if (isset($_POST['username'])
&& isset($_POST['input_password'])
&& !empty($_POST['username'])
&& !empty($_POST['input_password'])) {
$username = trim($_POST['username']);
$input_password = trim($_POST['input_password']);
$sql = "SELECT username, password FROM registration WHERE username=? && password=?";
I'm really struggling with this. I could do a login with basic text as the password, could get it to work. But the verifying aspect inherent with hashes is throwing me.
I understand I need to do something akin to:
if(crypt($input_password, $db_pass)==$db_pass) //plus the username stuff
echo 'Logged in!';
}
Do I need to do a separate SELECT query first to get the password from the entered username? And THEN verify the entered password with the database password through crypt?
So like:
$sql = "SELECT username, password FROM registration WHERE username=?";
$stmt = $db -> prepare($sql);
$stmt -> bind_param('s', $username);
$stmt -> execute();
$stmt -> bind_result($db_user, $db_pass);
$stmt -> fetch();
if(crypt($input_password, $db_pass)==$db_pass) //plus the username stuff
echo 'Logged in!';
}else{
echo 'Not logged in';
}
Would that be the right way? Getting the password directly from the database just by the username doesn't seem very safe. But I cant think of any other way.
Note: This isn't for practical use, just education.
You don't have to check if the passwords are the same in your if statement, the SQL query is sufficient.
It is sufficient to see if the retrieved row count is >= 1.
Best practice is to save a hashed version of a password in the database and to then use a SELECT query to find if the username and hashed password is the same as the supplied credentials.
My opinion would be that you should qualify the the POST better than with isset and !empty before using them in a query.
A better approach would be to generate the hash for the password and use the hash in the SELECT query then compare the user name.
The reason being this way you take SQL Injection out of the equation. For the same reason I also, when applicable, require a numeric value (e.g. last 4, phone) qualify it with intval($_POST['number']).
My preferred hash is $hash = hash('ripemd320',$password);
I do not know if it still stands true today, but at the time I researched hash algorithms ripemd320 was the one that had never been cracked.
Even so, I still check the input values to see if they posted anything that contains the SQL that is typically used for SQL injection:
$strike1 = preg_match_all('/\x2C/',$inputValue,$matches, PREG_SET_ORDER);
$strike2 = preg_match_all('/[\x21-\x2F]|[\x3A-\x40]|[\x5B-\x60]|[\x7B-\x7F]/',$inputValue,$matches, PREG_SET_ORDER);
$strike3 = preg_match_all('/COALESCE|0x|like|regex|mid|select|delete|drop|insert|do|call|replace|update|infile|lock|set|from|into|show|table|kill|reset/i',$inputValue,$matches, PREG_SET_ORDER);
Keep in mind I am old and have been doing this a long time. So yes my code may use depreciated PHP.
I also watch for Brute Force attacks.this code is from my early days and could be improved. But it works.
$sql = "SELECT `ip`,`TimeStamp` FROM `access` WHERE `ip` LIKE '$ip' AND `TimeStamp` > CURRENT_TIMESTAMP order by `TimeStamp` ASC";
$results = #mysql_query($sql);
$rows = mysql_num_rows($results);
if ($rows == 1) {
$ipCount = 1;
$timeCount = abs(strtotime($row[1]) - time());
$timeMin = $time;
$timeMax = $time;
}
$row = #mysql_fetch_array($results, MYSQL_NUM);
if ($rowCount > 1) {
$saveIP[$ipCount++] = $row[0];
$saveTime[$timeCount++] = strtotime($row[1]);
while ($row = mysql_fetch_array($results, MYSQL_NUM)) {
$saveTime[$timeCount] = strtotime($row[1]);
$time = $saveTime[$timeCount] - $saveTime[$timeCount - 1];
if ($time > $timeMax){
$timeMax = $time;
}
if ($time < $timeMin){
$timeMin = $time;
}
$rowCount += $row[0];
if ( !in_array($row[0],$saveIP)) {
$saveIP[$ipCount++] = $row[0];
$saveIP = $row[0];
$ipCount++;
}
}
}
And if I find unacceptable behavior:
#mysql_query("INSERT INTO `_portal`.`Banned` (`ip`, `TimeStamp`,`Strikes`, `Attributes`) VALUES ('$ip', CURRENT_TIMESTAMP, $alert);");
Especially on a shared Server it is wise not to put the mysql_connect() in the public script leaving the db name and password exposed if the server is misconfigured where PHP is served as MIME Type text/plain. Not that uncommon. And on a shared server I have been able to change the MIME Type for other users to text/plain using . Opps, not going to publish that code.
To connect I use something like include('/home/user/secureStorage/P7gAv2fH4pU.php');
When access to a script is administrative I only allow access from my IP.
if ((hash('ripemd320',$passcode) == '6732f3c024fe3c3c1ccd7dbe5d0fa7d4a53c516f800707bb86a9017c1e1646d9d4a2d7adc56a505d') && (substr($ip,0,11) == '152.30.52.72' || $ip == '72.3.150.55' || $ip == '17.162.23.21' )){
$admin = true;
}
I'm try to get cookies on to a browser. It's giving me parameter 1 error and parameter 3. This code works elsewhere on my site but not here. Can someone help me?
if ((!isset($_POST["uname"])) || (!isset($_POST["password"])))
{
header ("Location: wddnt/clients/'. $tattoo_extern_acct . '/index.html");
exit;
}
$userpass = md5($_POST['password']);
#$db = mysqli_connect("$dbc_ser", "$dbc_usr", "$dbc_pwd", "$dbc_db");
$sql = "SELECT id, name, company, job_title, cell_num, office_num, office_email,
login_right, first_run, attempts, locked_out FROM login
WHERE email = '".$_POST["email"]."'
AND password = PASSWORD('$userpass')";
if (mysqli_connect_errno())
{
echo 'Cannot connect to database: ' . mysqli_connect_error();
}
else
{
$result = mysqli_query($db, $sql);
while ($info = mysqli_fetch_array($result))
{
$id = stripslashes($info['id_files']);
$u_acct = stripslashes($info['uname']);
$name = stripslashes($info['name']);
$job_title = stripslashes($info['job_title']);
$location = stripslashes($info['company']);
$cell_num = stripslashes($info['cell_num']);
$office_num = stripslashes($info['office_num']);
$office_email = stripslashes($info['office_email']);
$login_right = stripslashes($info['login_right']);
$first_run = stripslashes($info['first_run']);
$attempts = stripslashes($info['attempts']);
$locked_out = stripslashes($info['locked_out']);
$land_page = stripslashes($info['land_page']);
}
}
Try debugging some of the individual variables. What is in $sql, for example? Is it correct?
Is the "Cannot connect" clause executed, or does it get to the query and fail there? (I am not sure what "parameter 1 error and parameter 3" means).
Don't forget to escape the 'email' value by the way - this code has an SQL injection hole.
header ("Location: wddnt/clients/'. $tattoo_extern_acct . '/index.html");
This is not going to work the way you expect.
$sql = "SELECT id, name, company, job_title, cell_num, office_num, office_email,
login_right, first_run, attempts, locked_out FROM login
WHERE email = '".$_POST["email"]."'
You need to read up on SQL injection.
while ($info = mysqli_fetch_array($result))
You allow multiple accounts with the same email address / password?????
It's giving me parameter 1 error and parameter 3
Couldn't you post the actual error message you get?
$id = stripslashes($info['id_files']);
WTF? Smartquotes?
I'm not sure i understand your question but the last time i checked anyone who wants to use cookies uses the $_COOKIE global variable, either for setting them or accessing them. $_POST is made to get stuffs from forms, not cookies.
Please check the manual for more details about $_COOKIE
Regards
I'm fairly new to mysql and I was wondering if the following code should be working. I've been checking with my database after submission of this form and nothing is getting inputted into the database. Please let me know what I'm doing wrong, Thank you!
<?php
$username = $_SESSION['username'];
$email = $_POST['email'];
$desc = $_POST['desc'];
$url = $_POST['url'];
$priority = $_POST['priority'];
if( strlen($username) > 0 && strlen($email) > 0 && strlen($desc) > 0)
{
$sql = "INSERT INTO feature_request_table (username, desc, email, url, priority, status)
VALUES( '$username' , '$desc' , '$email' , '$url' , '$priority' , '0' )";
echo "The sql statement is: " . $sql . "</br>";
mysql_query($sql);
//echo "The result is: " . $results . "</br>";
echo "Your request have been sent. Please allow a brief period of time for your webmaster implement your request. Thank you!";
}
mysql_close($con);
?>
Use the return value of mysql_query() and check if it is NULL to find out if the query was successful:
$result = mysql_query($sql);
// A NULL value of $result indicates failure
if (!$result) {
// something went wrong!
// See the error...
echo mysql_error();
}
Also, we don't see in the posted code that mysql_connect() was called. Also check that the connection was successfully made:
$conn = mysql_connect(all the connection details...);
if (!$conn) {
// connection failed
}
One thing I haven't seen mentioned yet is that you may not have auto-commit turned on, in which case your insert will return TRUE, but you will not see any change in the DB until you commit the insert.
You should really use the isset() function instead of strlen. Also, it does look like your never actually connecting to a mysql server according to the given code. Try posting the sql statement that is echoed into phpMyAdmin directly.
Following are the changes you need to do.
Use the column name desc with some other name of enclose in 'desc'.
Always print the error message or even terminate the output.
Check whether the POST Items are received correctly or not.
Here is the modified code.
if( isset($username) && isset($email) && isset($desc) )
{
$sql = "INSERT INTO feature_request_table (username, 'desc', email, url, priority, status)
VALUES( '$username' , '$desc' , '$email' , '$url' , '$priority' , '0' )";
echo "The sql statement is: " . $sql . "</br>";
mysql_query($sql) or die (mysql_error());
//echo "The result is: " . $results . "</br>";
echo "Your request have been sent. Please allow a brief period of time for your webmaster implement your request. Thank you!";
}
This sould do it :
$data = mysql_query($sql);
if($data === false) { // TODO: better error handling
// Do something...
echo mysql_error();
// Or see the errors...
}
Note : if you want to have valid HTML pages in all situations handle your errors don't use OR DIE().