0

I have a big problem.

I own a website with have a membership area. I have a competitor that consistently hacking member's accounts.

I hired a security expert for that. he fix a few sql query's but didn't found any problem with the login code.

The real problem - if someone mistaken with his password automaticly it's inserted into a DB So I would be able to know what string he submitted.

The password on the DB is encrypt with MD5. But the same competitor, hacked my own account and when I changed my password he tried to submit the last password I had. So now I know for a fact that he know exactly what my password was.

my password was something really long and tricky, there is no chance of it being on any MD5 reserve online.

Do you know what can be the problem? How did he hacked this? and how did he know my password string as it is?

Thank you !

This is the login.php file included:

if(isset($_POST['login'])){
  //Input filteren
  $name = htmlspecialchars(addslashes($_POST['username'])); 
  $ww = htmlspecialchars(addslashes($_POST['password']));
  //Wachtwoord omzetten naar md5 
  $wwmd5 = md5($_POST['password']);

  //Gegevens laden voor het foute inloggen.
  $inlog_fout_sql = mysql_query("SELECT `datum`, `ip`, `spelernaam` FROM `inlog_fout` WHERE `ip`='".$_SERVER['REMOTE_ADDR']."' ORDER BY `id` DESC");
  $inlog_fout = mysql_fetch_array($inlog_fout_sql); 
  $aftellen = 1200-(time()-strtotime($inlog_fout['datum']));

  //Geen inlognaam ingevuld
  if($_POST['username'] == '')
    $inlog_error = $txt['alert_no_username'];
  //Geen wachtwoord ingevoerd
  elseif($ww == '')
    $inlog_error = $txt['alert_no_password'];
  //Is het wel drie keer mis gegaan
  elseif((mysql_num_rows($inlog_fout_sql) >= 300) AND ($inlog_fout['ip'] === $_SERVER['REMOTE_ADDR']) AND ($aftellen > 0)) {
    $inlog_error = $txt['alert_time_sentence'].' <span><script type="text/javascript">writetimer("'.$aftellen.'")</script></span>';
  }
  else{
    if($aftellen < 0)
      mysql_query("DELETE FROM `inlog_fout` WHERE `ip`='".$_SERVER['REMOTE_ADDR']."'");

    // Gegevens laden om te kijken voor de gebruiker
    $naam = $_POST['username'];
    $gegevens_sql = mysql_query("SELECT `id`, `username`, `wachtwoord`, `premiumaccount`, `account_code` FROM `members` WHERE `username`='".$naam."'"); 
    // Gegevens laden om te kijken voor de gebruiker
    $gegeven_sql  = mysql_query("SELECT `username`, `wachtwoord`, `account_code` FROM `members` WHERE `wachtwoord`='".$wwmd5."' AND `username`='".$naam."'");
    $gegeven = mysql_fetch_array($gegevens_sql);

    if(mysql_num_rows($gegevens_sql) == 0)
      $inlog_error = $txt['alert_unknown_username'];
    elseif($gegeven['username'] != $naam)
      $inlog_error = $txt['alert_unknown_username'];
    //Kijken of account niet is verbannen
    elseif(mysql_num_rows(mysql_query("SELECT id FROM ban WHERE id = '".$gegeven['id']."'")) > 0)
      $inlog_error = $txt['alert_account_banned'];
    elseif(mysql_num_rows($gegeven_sql) == 0){
      $datum = date("Y-m-d H:i:s");
      mysql_query("INSERT INTO `inlog_fout` (`datum`, `ip`, `spelernaam`, `wachtwoord`) 
        VALUES ('".$datum."', '".$_SERVER['REMOTE_ADDR']."', '".$naam."', '".$ww."')");

      if((mysql_num_rows($inlog_fout_sql) < 300) AND ($gegeven['wachtwoord'] != $wwmd5))
        $inlog_error = 'סיסמא שגויה';
    }
    elseif($gegeven['account_code'] != 1)
      $inlog_error = $txt['alert_account_not_activated'];
    else{
      //If Onthoud Check box is checked save cookie
        setcookie("pa_1", $gegeven['username'], time()+(60*60*24*365));
        setcookie("pa_2", $_POST['password'], time()+(60*60*24*365));

      //Zorgen dat gebruiker weer 3 pogingen heeft.
      mysql_query("DELETE FROM `inlog_fout` WHERE `ip`='".$_SERVER['REMOTE_ADDR']."'");

      //tijd opslaan dat het lid inlogt, zodat de site weet dat hij online is.
      $tijd = time();
      mysql_query("UPDATE `members` SET `ip_ingelogd`='".$_SERVER['REMOTE_ADDR']."', `online`='".$tijd."' WHERE `username`='".$gegeven['username']."'");

      //Datum opvragen
      $date = date("Y-m-d H:i:s");
      //Opslaan in de inlog_logs tabel
      $queryloginlogs = mysql_query("SELECT `id` FROM `inlog_logs` WHERE `ip`='".$_SERVER['REMOTE_ADDR']."' AND `speler`='".$gegeven['username']."'");
      if(mysql_num_rows($queryloginlogs) == "0"){
        mysql_query("INSERT INTO `inlog_logs` (`ip`, `datum`, `speler`) 
          VALUES ('".$_SERVER['REMOTE_ADDR']."', '".$date."', '".$naam."')");
      }
      else
        mysql_query("UPDATE `inlog_logs` SET `datum`='".$date."' WHERE `speler`='".$gegeven['username']."' AND `ip`='".$_SERVER['REMOTE_ADDR']."'");

      //zet naam in variabele, zodat het later nog gebruikt kan worden
      $_SESSION['id'] = $gegeven['id'];
      $_SESSION['naam'] = $gegeven['username'];
      //Hash opslaan
      $_SESSION['hash'] = md5($_SERVER['REMOTE_ADDR'].",".$gegeven['username']);
      //Ben je wel premium
      if($gegeven['premiumaccount'] > 0)
        $_SESSION['userid'] = $gegeven['id'];
      //naar de ingame pagina sturen
      header('location: ?page=home');
    }
  }
}
AstroCB
  • 12,337
  • 20
  • 57
  • 73
  • MD5 was broken years ago. It's no surprise they got your password. Using MD5 for password is a bad practice and insecure. Use modern best practices or else stuff like this happens. – John Conde Feb 20 '14 at 02:00
  • write a script that replaces every password in your database with a new, salted password and use [crypt()](http://us2.php.net/manual/en/function.crypt.php) or [password_hash()](http://www.php.net/manual/en/function.password-hash.php) – timgavin Feb 20 '14 at 02:04
  • 2
    Also, fire your "security expert." – timgavin Feb 20 '14 at 02:07
  • How can i do it? I have almost 8000 registerd users. and the password is encrypt with md5, can i reverse it somehow? – user3330698 Feb 20 '14 at 02:11
  • 1
    Don't. Option 1: When they login successfully matching the md5, update the password field to the newer more secure format. (Edit: obviously you'd have to check for both storage formats, at least for a while.) Option 2: Change everyone's password and force them to reset it. – EPB Feb 20 '14 at 02:19
  • Ok. I think I'll go with option to. But any idea of how he was able to get the md5? – user3330698 Feb 20 '14 at 02:28
  • 1
    @EPB if he waits until each user logs in to change their password he is still open to a security risk until all users have logged in - which may never happen. This is why I suggested replacing all passwords at once with something more secure. This will force the users to reset their passwords using the new, secure format. – timgavin Feb 20 '14 at 03:59
  • @Tim, I am well aware of this. Option 1 sacrifices some security in exchange for more convenience, and I should have made a point of this. I also shouldn't have listed it first. It is a perfectly viable option in some scenarios however. I've used both. Though my implementation of option 1 usually involved a time limit after which stragglers were set to `!` and instructed to do a password reset when they tried to log in. – EPB Feb 20 '14 at 05:38

1 Answers1

2

I can see at least one way that an attacker can read your passwords using your code, without breaking an MD5 hash.

$naam = $_POST['username'];
. . .
$gegevens_sql = mysql_query("SELECT `id`, `username`, `wachtwoord`, `premiumaccount`, `account_code` FROM `members`
    WHERE `username`='".$naam."'"); 

You are interpolating $_POST['username'] into your SQL query without protecting it at all.


No-- wait, I'm wrong. They can do an SQL injection attack in at least two places in the code you show, but I don't see how they could read the password, because of the following code:

elseif($gegeven['username'] != $naam)
  $inlog_error = $txt['alert_unknown_username'];

They can't both fetch the plaintext password into $gegeven['username'] and pass this if-test.


Still, the fact that your code is vulnerable to SQL injection is a huge red flag. If you are in the habit of copying $_POST variables directly into your queries, there is likely another way they could exploit it in other parts of your app that we're not seeing here.

Recommendations:

  1. Reset all the passwords in your database @EPB suggested.

  2. Learn how to prevent SQL injection.

  3. Ask your security analyst why they didn't catch this.

  4. Never store plaintext passwords.

Community
  • 1
  • 1
Bill Karwin
  • 538,548
  • 86
  • 673
  • 828