Website hacked with MySQL injection attack

Hey everyone,
Last night my website was hacked; looked like a MySQL Injection attack… I don’t know exactly how this happened. Trust me, I know this code is pretty weak but keep in mind, this website is simply a hobby of mine. Below is the link to the website (if you would like to try getting in from there) and also the source code of the login page.

The hacker was able to login as several different users, post in the forums and listed out the passwords (which were MD5 encrypted only, no salt) real text, obviously using rainbow tables. I’ve only deleted this stuff and haven’t made any changes to the code as of yet.

Fantasy MMA Leagues, Fantasy UFC, Fantasy Teams; Fully Customizable Fantasy MMA

<?php include 'includes/global.php'; ?>
<?php
if($_SESSION['logged_in'] == true) {
	header('Location: index.php');
}
?>
<?php
$error = $_GET['error'];
if(!empty($error)) {
	$status = "<p class=\\"warning\\">Wrong username and/or password. Please try again!<br/><a style=\\"font-size:11px;\\" href=\\"forgot-login.php\\" title=\\"Forgot Login?\\">Forget your Login?</a></p>";
}
?>
<?php


if(!empty($_POST)) {
$log_email = mysql_real_escape_string(strtolower(preg_replace("/[^A-Za-z0-9]@./", "", $_POST['log_email'])));
$log_password = mysql_real_escape_string(strtolower(preg_replace("/[^A-Za-z0-9]/", "", $_POST['log_password'])));

$error_list = array();
if(empty($log_email)) {
	$error_list[] = 'You did not enter your username.';
}
if(empty($log_password)) {
	$error_list[] = 'You did not enter your password.';
}
if(empty($error_list)) {
	$log_password = md5($log_password);
	mysql_select_db('mmaf');
	$sql = "SELECT * ";
	$sql .= "FROM mma_users ";
	$sql .= "WHERE user_username='$log_email' AND user_password='$log_password' AND user_active='1' ";
	
	$result = mysql_query($sql);

	if(mysql_num_rows($result) == 1) {
		
		$result = mysql_query($sql);
		$row = mysql_fetch_assoc($result);
			$userid = $row['user_q_id'];
			$username = $row['user_username'];
			$email = $row['user_email'];
			$fname = $row['user_fname'];
			$lname = $row['user_lname'];
			$country = $row['user_country'];
			$state = $row['user_state'];
			$city = $row['user_city'];
			$gender = $row['user_gender'];
			$month = $row['user_month'];
			$day = $row['user_day'];
			$year = $row['user_year'];
			$ipaddress = $_SERVER['REMOTE_ADDR'];
			$useragent = $_SERVER["HTTP_USER_AGENT"];
			
			
			session_start();
			session_register('logged_in');
			$_SESSION['logged_in'] = true;
			session_register('username');
			$_SESSION['username'] = $username;
			session_register('email');
			$_SESSION['email'] = $email;
			session_register('fname');
			$_SESSION['fname'] = $fname;
			session_register('lname');
			$_SESSION['lname'] = $lname;
			session_register('gender');
			$_SESSION['gender'] = $gender;
			session_register('country');
			$_SESSION['country'] = $country;
			session_register('state');
			$_SESSION['state'] = $state;
			session_register('month');
			$_SESSION['month'] = $month;
			session_register('day');
			$_SESSION['day'] = $day;
			session_register('year');
			$_SESSION['year'] = $year;
			session_register('useragent');
			$_SESSION['useragent'] = $useragent;
			session_register('ipaddress');
			$_SESSION['ipaddress'] = $ipaddress;
			session_register('userid');
			$_SESSION['userid'] = $userid;

			

			mysql_select_db('mmaf');
			mysql_query("UPDATE mma_users SET user_last_login=now(), user_ipaddress='$ipaddress', user_useragent='$useragent' WHERE user_q_id='$userid' ");

			$uri_requested = $_SESSION['uri_requested'];
			if(empty($uri_requested)) {
				header("Location: controlpanel.php");
			}
			else {
				header("Location: $uri_requested");
			}
		
		}
		else {
			header("Location: login.php?error=nolog");
		}
	}
	else {
		header("Location: login.php?error=nolog");
	}
}


?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Login - <?php include 'includes/title.php'; ?></title>
<?php include 'includes/header.php'; ?>
</head>
<body>
<?php include 'includes/head_nav.php'; ?>
	<div id="main">
		<div id="left">
			<div class="wide_cont">
				<div class="wide_cont_stuff" style="min-height:610px;">
					<fieldset class="field1" style="width:375px;margin:auto;">
						<legend>Login</legend>
							<?php echo "$status";?>
							<form method="post" action="<?php echo "login.php" ?>">
							<table style="width:360px;">							
								<tr>
									<td style="text-align:right;width:100px;"><b>username:</label></b></td>
									<td style="width:200px;"><input class="input1" type="text" tabindex="1" name="log_email" id="log_email" value="" /></td>
								</tr>
								<tr>
									<td style="text-align:right;width:100px;"><b>password:</label></b></td>
									<td style="width:200px;"><input class="input1"  type="password" tabindex="2" name="log_password" id="log_password"  value="" /></td>
								</tr>
								<tr>
									<td style="width:100px;"></td>
									<td style="width:200px;"><input type="submit" name="submit" value="Login!" /></td>
								</tr>
							</table>
							</form>
					</fieldset>
				</div>
			</div>
		</div>
		<?php include "includes/right.php"; ?>
		<div style="clear:both;"></div>
	</div>
</div>
<?php include "includes/footer.php"; ?>
</body>
</html>

One of the first problems I noted is that you are limiting passwords. You should not do that. Allow a user to enter anything they what into the password field. Then immediately throw it into a hashing function. Most important, do NOT use strtolower on a password. Make every password case-sensitive.

A quick means of dealing with passwords, might need more work.


$password = sha1( $_POST['log_email'] . sha1( $_POST['log_email'] . $_POST['log_password'] ) );
// No need for mysql_real_escape_string on $password.

As you see I didn’t do anything with the password, no filtering or validation it goes straight into a hashing function in this case sha1. In newer versions like 5.3 I would use the dedicated hash library. Using email as a salt for the password avoids the rainbow tables problem.

I had a similar problem with one of my joomla sites. Until now I still do not know what to do in order to prevent such hacks.

thanks for the info, i’ll def be making changes. is it possibly a XSS attack?

The password issue alone could be the source of your hack assuming a rainbow tables attack. Make sure ALL admin passwords are strong (try http://strongpasswordgenerator.com/) and make sure separate strong passwords are used for the database and another for any file access (ftp/ssh/etc) you might have.

I know you say this is a hobby site, and I don’t mean this to be too harsh (I’ve been in your shoes) but not only is that not an excuse, but if anything it should be more of a reason for you to make your site secure from the start. A “pro” would have more time to monitor the site for issues, a hobbyist typically does not.

Finally, assuming passwords from the general public were compromised, you really should notify your users. Many of them probably use the same password for everything from other forums to their bank accounts. Failure to adequately protect their passwords (it sounds like you knew about the shortcomings) and to not let them know of a compromise up front can not only hurt your reputation, but could result in some rather nasty legal actions against you.

Either way, strengthening passwords would be a good start. Good luck!

It is possible that the hacker gained access through another account on the server if the server doesn’t have adequate security. Make sure you escape ALL user supplied data including IP addresses. You didn’t do that. I don’t know if it is possible to spoof an IP address with injection code. But if it is possible, there’s an avenue.


$ipaddress = $_SERVER['REMOTE_ADDR'];
<snip>
mysql_query("UPDATE mma_users SET user_last_login=now(), [B]user_ipaddress='$ipaddress'[/B], user_useragent='$useragent' WHERE user_q_id='$userid' ");


The sad fact is that using open source scripts you are always going to be prone to being hacked. That, I guess, is the price you pay for using an open source script.

My SMF forum was hacked. My Joomla installation was hacked. In both these instances no damage occurred but a shell script was uploaded to my account. :mad:

Then I was hacked again a few months ago. :mad: I’m not sure how I was hacked and my web host’s support department wasn’t sure either. The hacker was using my account to run IRC bots or something, I’m not exactly sure. I was checking for updates to the open source scripts I use every day but I forgot to check for 5 days and a Wordpress update was released during that time. I cannot say how the hacker gained access to my hosting account, but I strongly suspect Wordpress was the entry point.

It makes me so mad. :mad:

Bottom line: if you use open source scripts check for updated versions every day.

Look at how many high profile hackings there have been lately. Not just Sony, but others, too.

Website That Outed Porn Stars Gets a Taste of Its Own Medicine

I am beginning to think that no website is ever safe. I wish that there was someplace where these hacking attacks were documented with information about how the hackers gained access so we could all learn from it.