Monday, November 11, 2019

mysql - SQL injection attack with php




this is part of an assignment for my computer security class, so I'm not looking for specific answers, just some help.



We were given a faulty program (in php) that controls a sql database (a bank account) and we have to find a way to create a SQL injection attack that will let us log into an account without knowing it's ID ahead of time.



I'm pretty sure I know where the vulnerability is, but I can't quite seem to get my attacks to work.



The code in question (it's kinda long, but the only part that matters is in the first part):



FrobozzCo Community Credit Union


FrobozzCo Community Credit Union


We're working for GUE





$debugmode = 1;
function debug($msg) {

global $debugmode;


if ($debugmode) {
echo "

$msg

\n";
}
}

$thispage = 'FCCU.php';
echo "
\n";
$dbuser = 'fccu';
$dbpass = 'fccubucks';
$dbhost = 'localhost';

$dbname = $dbuser;

$PARAM = array_merge($_GET, $_POST);

// get username and password from form
if (!$PARAM['id'] || !$PARAM['password']) {
login();
} else { // otherwise, attempt to authenticate
$id = $PARAM['id'];
$password = $PARAM['password'];


$link_id = mysql_connect($dbhost, $dbuser, $dbpass);
mysql_select_db($dbname);

$query = "SELECT * FROM accounts WHERE id = $id AND password = '$password'";
debug($query);
$result = mysql_query($query) or die(mysql_error());
$row = mysql_fetch_array($result); // there should be only one row

if (!$row) { // auth failure

echo "

Your ID number and password you entered do not match.

";
echo "

Please try again.

";
login();
} else { // this user is authenticated!

// store authentication information in this form
echo "\n";
echo "\n";

banner($row);


// perform any requested actions (wire, transfer, withdraw)
if ($PARAM['action'] == 'Transfer Money') {
transfer_funds($id,
$password,
$PARAM['transfer_to'],
$PARAM['transfer_amount']);
} elseif ($PARAM['action'] == 'Wire Money') {
wire_funds($id,
$password,

$PARAM['routing'],
$PARAM['wire_acct'],
$PARAM['wire_amount']);
} elseif ($PARAM['action'] == 'Withdraw Money') {
withdraw_cash($id,
$password,
$PARAM['withdraw_amount']);
}

// normal output


// account info
$query = "SELECT * FROM accounts WHERE id = $id AND password = '$password'";
$result = mysql_query($query) or die(mysql_error());
$row = mysql_fetch_array($result); // there should be only one row
account_info($row);

// get current account list by name
$query = "SELECT first, last FROM accounts ORDER BY last";
$names = mysql_query($query) or die(mysql_error());

account_actions($row, $names);
}


}
echo "
\n";
echo "Generated by FCCU.php at " . date("l M dS, Y, H:i:s",5678)."
";

function name_to_id($name) {


global $dbhost, $dbuser, $dbpass, $dbname;
$splitname = explode(", ", $name);

$link_id = mysql_connect($dbhost, $dbuser, $dbpass);
mysql_select_db($dbname);
$query = "SELECT id FROM accounts WHERE first = '$splitname[1]' AND last = '$splitname[0]'";
$result = mysql_query($query) or die(mysql_error());
$row = mysql_fetch_array($result);
$id = $row[0];


return $id;
}

function action_error($msg, $error) {

echo "


ERROR!

$msg


Please go back and try again or contact tech support.



args: $error




";
}

function withdraw_cash($id, $password, $amount) {

global $dbhost, $dbuser, $dbpass, $dbname;


$amount = floor($amount);

$link_id = mysql_connect($dbhost, $dbuser, $dbpass);
mysql_select_db($dbname);

$query = "SELECT bal FROM accounts WHERE password = '$password' AND id = $id";
debug("126: ($password) " . $query);
$result = mysql_query($query);


$row = mysql_fetch_array($result);
$giver_has = $row[0];

if ($amount > 0 && $giver_has >= $amount) {
$giver_has = $giver_has - $amount; // there's a problem here but it's not SQL Injection...
pretend("withdraw cash", $amount);
$query = "UPDATE accounts SET bal = $giver_has WHERE password = '$password' AND id = $id LIMIT 1";
mysql_query($query) or die(mysql_error());
echo "

Cash withdrawal of $$amount complete.


Your cash should be ready in accounting within 45 minutes.

\n";

} else {
action_error("Problem with cash withdrawal!",
"'$id', '$giver_has', '$amount'");
}
}


function wire_funds($id, $password, $bank, $account, $amount) {

global $dbhost, $dbuser, $dbpass, $dbname;


$amount = floor($amount);

$link_id = mysql_connect($dbhost, $dbuser, $dbpass);
mysql_select_db($dbname);

$query = "SELECT bal FROM accounts WHERE password = '$password' AND id = $id";
debug($query);
$result = mysql_query($query);


$row = mysql_fetch_array($result);
$giver_has = $row[0];

if ($amount > 0 && $giver_has >= $amount && $bank && $account) {
$giver_has = $giver_has - $amount; // there's a problem here but it's not SQL Injection...
pretend("wire money", $amount, $bank, $acct);
$query = "UPDATE accounts SET bal = $giver_has WHERE password = '$password' AND id = $id LIMIT 1";
debug($query);
mysql_query($query) or die(mysql_error());
echo "

Wire of $$amount to bank ($bank) account ($account) complete.

\n";

} else {
action_error("Problem with wire fund transfer!",
"'$id', '$amount', '$giver_has', '$bank', '$account'");
}
}

function pretend() {

return 1;
}


function transfer_funds($giver_id, $password, $recipient, $amount) {

global $dbhost, $dbuser, $dbpass, $dbname;

$amount = floor($amount);
$recipient_id = name_to_id($recipient);

$link_id = mysql_connect($dbhost, $dbuser, $dbpass);
mysql_select_db($dbname);


$query = "SELECT bal FROM accounts WHERE id = $giver_id OR id = $recipient_id";
debug($query);
$result = mysql_query($query);

$row = mysql_fetch_array($result);
$recipient_has = $row[0];
$row = mysql_fetch_array($result);
$giver_has = $row[0];
debug("$giver_has, $recipient_has");


if ($amount > 0 && $giver_has >= $amount && $recipient_has) {
$giver_has = $giver_has - $amount; // there's a problem here but it's not SQL Injection...
$recipient_has = $recipient_has + $amount; // does anyone know what it is?
$query = "UPDATE accounts SET bal = $recipient_has WHERE id = $recipient_id LIMIT 1";
debug($query);
mysql_query($query) or die(mysql_error());
$query = "UPDATE accounts SET bal = $giver_has WHERE password = '$password' AND id = $giver_id LIMIT 1";
debug($query);
mysql_query($query) or die(mysql_error());

echo "

Transfer of $$amount to $recipient complete.

\n";
} else {
action_error("Problem with employee fund transfer!",
"'$giver_id', '$recipient', '$amount', '$giver_has'");
}
}

function account_info($row) {

echo "








Account Information

Account:$row[0]
Balance:$$row[1]
Birthdate:$row[6]
SSN:$row[5]
Phone:$row[4]
Email:$row[7]@frobozzco.com
\n";
}


function account_actions($row, $names) {

global $thispage;

echo "

















Account Actions
Wire Funds

To wire funds: enter the amount (in whole dollars), the
receiving bank's routing number and receiving account number,
and press 'Wire Funds!'


Wire amount: $
Routing Number: (e.g. 091000022)
Account Number: (e.g. 923884509)



Transfer Money

To transfer money to another FCCU account holder, select the
employee from the drop-down menu below, enter an ammount (in whole dollars)
to transfer, and press 'Transfer Money!'


Transfer Amount: $
Transfer To: ";
// create dropdown menu with accounts
echo "\n";
echo "



Withdraw Cash

To withdraw cash, enter an amount (in whole dollars) and press
the 'Withdraw Cash!' button. The cash will be available in the accounting
office within 45 minutes.


Withdraw Amount: $





\n";

}

function banner($row) {

global $thispage;

$fullname = "$row[2] $row[3]";
echo "


Welcome, $fullname. (Log Out)



(If you aren't $fullname, click here.)


\n";
echo "
\n";


}

function login() {


global $thispage;

echo "

Enter your account ID and password and click \"submit.\"

\n";
echo "\n";
echo "\n";
echo "\n";
echo "\n";
echo "
Account ID Number:
Password (alphanumeric only):
\n";


}

?>

Done.






The line:




$query = "SELECT * FROM accounts WHERE id = $id AND password = '$password'";


I've tried a couple of strings in the ID input (I'm working from my browser) such as



100 OR id=id;
0 OR 1=1;



To try and comment out the password part of the command. I'm pretty new to SQL so I think I'm just formatting this wrong.



That or I'm completely overlooking a more obvious exploit.


Answer



You need to make sure to comment out the rest of the query, so the quotes don't trip you up and so any extra clauses are ignored.



Try setting the ID to:



0 OR id=id -- 



The --  (that's hyphen, hyphen, space: the space is important) is a comment in MySQL.


No comments:

Post a Comment

hard drive - Leaving bad sectors in unformatted partition?

Laptop was acting really weird, and copy and seek times were really slow, so I decided to scan the hard drive surface. I have a couple hundr...