PDA

View Full Version : MySQL being exploited...?



Shinykirby
02-17-2009, 06:20 AM
I'm relatively new to PHP, so you will notice that any code I post below will be extremely sloppy. I've worked primarily with Java so that's what I base most of my syntax and layout on.

Anyway, here is the situation. I'm connecting two server's databases, one has the function of being primarily a webserver (mainly to handle a large amount of traffic), the other as the main server which already has an extreme amount of traffic (a little over 30 queries a second?)

However, that is not the problem. I have linked the servers fine and my PHP script runs fine. What the intention is, the script is basically a ballot count, you put in "votes" (one every 12 hours) for benefits on the main server for the user's account. The accounts are on the main server, with passwords stored in a salted sha512 hash. For efficiency reasons, I didn't want to keep connecting to the main server to authenticate the passwords, so another part of my script is that it does a one-time-retrieval of the information from the main database and it will store the information on the webserver's database. That's also fine (and it runs pretty fast, too, once your account has been logged into the database).

So what they do is, they log into the webserver with the intention of increasing their ballot "vote" by 1 (for records) using their account from the main server. If they've already voted, their account is already stored and it's accessed from the local database, otherwise it's fetched from the main server then stored on the local database. After the webserver records this "ballot vote" (I really was at a loss of words for the system, but it seems to work well), it will close the connection with the webserver, then do a small, final update on the main server for their benefits there.

So basically the script goes like this:
Log into webserver > authenticate password/account > log vote into local database > increase "times voted" by 1 > close local connection - open external connection > increase their "points" there by 2,000 > close external connection

(My apologies if the above description is too vague or too in-depth)

Simple enough. Now for my actual problem.

What I also integrated is a ban($account, $ip) function, which will IP ban you from both the webserver and external server, as well as logging you into a ban list and deleting all of your records. This is used in case they exploit the vote script and they have more than getMaxVotes() votes.

Now, the ban function works, it will properly wipe their records and ban them from the servers. The problem is that it never actually happens and people still seem to bypass all of my checks in my script where I'm hoping they're running the exploit from. I honestly have no clue how they're doing it, but I do know where the problem is.

The reason the exploits came about is because doing this "vote" system will earn you bonuses on the main server (which I explained earlier). Ergo, if you exploit it, you can rack up some hefty bonuses in a short amount of time (which, for the developers, totally sucks).

Without further ado, here is my script. If you need to know what the ban() function looks like, let me know but that is definitely not the problem - it bans properly, but it's never called in the script no matter what.

Note that I removed all the database connection info for security reasons. I'm well aware you need access granted to connect, but I'm paranoid.

(You may notice I put a ban check about 4 times in the script because I'm growing increasingly frustrated with this, and frustration = poor code)


<?php
include 'functions.php';

// do voting
$conn = mysql_connect("------------------") or die ('Error connecting to MySQL!');
mysql_select_db("votelog");

$earnedpoints = false;
$account = $_POST['name'];
$account = mysql_real_escape_string($account);
$pass = $_POST['password'];
$pass = mysql_real_escape_string($pass);

if ($account == "") {
echo 'Enter an account name!';
exit();
}
if ($pass == "") {
echo 'Enter a password!';
exit();
}

$ip = $_SERVER['REMOTE_ADDR'];
$time = time();
$accountexists = false;
$votepw = null;
$votesalt = null;
$passhash = null;

$voteacc = mysql_query("SELECT * FROM accounts WHERE name='$account'");
$checkvoteacc = mysql_fetch_array($voteacc);
$hasaccount = 0;
while ($checkvoteacc) {
$hasaccount++;
$accountexists = true;
break;
}

if ($accountexists) {
$getvotepw = mysql_query("SELECT * FROM accounts WHERE name='$account'");
$getvoteinfo = mysql_fetch_array($getvotepw);
$votepw = $getvoteinfo['password'];
$votesalt = $getvoteinfo['salt'];
$passhash = hash('sha512',$pass.$votesalt);
} else {
$passconn = mysql_connect('~~~~~~~~~~~') or die ('Error connecting to MySQL!');
mysql_select_db("datahandler");

$getacc = mysql_query("SELECT * FROM accounts WHERE name='$account'");
$getpass = mysql_fetch_array($getacc);
$checking = 0;
while ($getpass) {
$checking++;
break;
}
if ($checking == 0) {
echo 'Invalid account!';
exit();
}
$dbpassword = $getpass['password'];
$dbsalt = $getpass['salt'];

$newpass = hash('sha512',$pass.$dbsalt);
if ($newpass != $dbpassword) {
echo 'Wrong password!';
exit();
}
mysql_close($passconn);
$conn = mysql_connect("--------------------") or die ('Error connecting to MySQL!');
$q = mysql_query("INSERT INTO accounts (`name`, `password`, `salt`) VALUES ('$account', '$newpass', '$dbsalt')");
if (!$q) {
$message = 'Invalid query: ' . mysql_error() . "\n";
$message .= 'Whole query: ' . $q;
die($message);
}
$votepw = $newpass;
$votesalt = $dbsalt;
$passhash = hash('sha512',$pass.$votesalt);
}

if ($votepw != $passhash) {
echo 'Password is incorrect.';
exit();
} else {
$query = mysql_query("SELECT * FROM records WHERE account='$account' OR ip='$ip'");
$banquery = mysql_query("SELECT * FROM banlist WHERE account='$account' or ip='$ip'");
$numrows = 0;
$banrows = 0;
$lasttime = mysql_fetch_array($query);
$checkbanned = mysql_fetch_array($banquery);
$timecalc = $time - $lasttime['date'];
$amount = $lasttime['times'];
if ($amount > (getMaxVotes() + 1)) { // +2 to compenstate for lag? :\
ban($account, $ip);
exit();
}
while ($lasttime) {
$numrows++;
break; // we're only confirming existance, not fetching an array
}
while ($checkbanned) {
$banrows++;
break;
}
if ($banrows > 0) {
echo 'Your account has been permanently blocked from using this feature for exploiting a glitch. ';
exit();
} else {
if ($numrows > 0) {
if ($timecalc < 43200) {
echo 'Max number of votes anybody can have: ';
echo getMaxVotes();
echo '<br>';
echo 'You\'ve already voted with this account ('. $account .') or IP ('. $ip .') in the last 12 hours!';
echo '<br>';
echo 'Last voted on: '. date('M d\, h:i:s A', $lasttime['date']) .'';
exit();
} else {
mysql_query("UPDATE records SET account='$account', date='$time', times=times+1 WHERE ip='$ip'");
if ($amount + 1 > getMaxVotes()) {
ban($account, $ip); //listed several times in case of exploit
exit();
}
$earnedpoints = true;
}
} else {
$success = mysql_query("INSERT INTO records (`account`, `ip`, `date`, `times`) VALUES ('$account', '$ip', '$time', 1)");
if (!$success) {
$message = 'Invalid query: ' . mysql_error() . "\n";
$message .= 'Whole query: ' . $query;
die($message);
} else {
$earnedpoints = true;
}
}
}
}

$recheck = mysql_query("SELECT * FROM records WHERE account='$account'");
$recheckfetch = mysql_fetch_array($recheck);
$currentvotes = $recheckfetch['times'];

mysql_close($conn);

$conn2 = mysql_connect('~~~~~~~~~~~') or die ('Error connecting to MySQL!');
mysql_select_db("datahandler");

//ugh
if ($currentvotes > getMaxVotes()) {
ban($account, $ip);
exit();
}
if ($earnedpoints) {
$points = mysql_query("UPDATE accounts SET points=points+2000 WHERE name='$account'");
if (!$points) {
$message = 'Invalid query: ' . mysql_error() . "\n";
$message .= 'Whole query: ' . $query;
die($message);
}
}
mysql_close($conn2);

echo 'Vote submitted!';
?>