title: SQL injection attack with php
body: <p>this is part of an assignment for my computer security class, so I'm not looking for specific answers, just some help.</p>
  
  <p>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.</p>
  
  <p>I'm pretty sure I know where the vulnerability is, but I can't quite seem to get my attacks to work. </p>
  
  <p>The code in question (it's kinda long, but the only part that matters is in the first part): </p>
  
  <pre><code>&lt;html&gt;&lt;head&gt;&lt;title&gt;FrobozzCo Community Credit Union&lt;/title&gt;&lt;/head&gt;
  &lt;body&gt;
  &lt;h1&gt;FrobozzCo Community Credit Union&lt;/h1&gt;
  &lt;h4&gt;&lt;i&gt;We're working for GUE&lt;/i&gt;&lt;/h4&gt;
  &lt;hr&gt;
  &lt;?php
  
  $debugmode = 1;
  function debug($msg) {
  
      global $debugmode;
  
      if ($debugmode) {
          echo "&lt;h4&gt;$msg&lt;/h4&gt;\n";
      }
  }
  
  $thispage = 'FCCU.php';
  echo "&lt;form action='$thispage' method='post' name='theform'&gt;\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 "&lt;p&gt;&lt;b&gt;Your ID number and password you entered do not match.&lt;/b&gt;&lt;/p&gt;";
          echo "&lt;p&gt;Please try again.&lt;/p&gt;";
          login();
      } else { // this user is authenticated!
  
          // store authentication information in this form
          echo "&lt;input type=\"hidden\" name=\"id\" value=\"$id\" /&gt;\n";
          echo "&lt;input type=\"hidden\" name=\"password\" value=\"$password\" /&gt;\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 "&lt;hr&gt;\n";
  echo "Generated by FCCU.php at " . date("l M dS, Y, H:i:s",5678)."&lt;br&gt;";
  
  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 "&lt;table bgcolor='#ff0000' color='#ffffff' align=center border=1&gt;
            &lt;tr&gt;&lt;td&gt;&lt;center&gt;&lt;b&gt;ERROR!&lt;/b&gt;&lt;/center&gt;&lt;/td&gt;&lt;/tr&gt;
            &lt;tr&gt;&lt;td&gt;
                    &lt;p align='center'&gt;$msg&lt;/p&gt;
                    &lt;p align='center'&gt;Please go back and try again or contact tech support.&lt;/p&gt;
                    &lt;p align='center'&gt;&lt;i&gt;args: $error&lt;/i&gt;&lt;/p&gt;
                &lt;p align='center'&gt;&lt;input type='submit' name='clear' value='Clear Message'&gt;&lt;/p&gt;
  
                &lt;/td&gt;&lt;/tr&gt;
            &lt;/table&gt;";
  }
  
  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 &gt; 0 &amp;&amp; $giver_has &gt;= $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 "&lt;h2 align='center'&gt;Cash withdrawal of $$amount complete.&lt;/h2&gt;
                &lt;h3 align='center'&gt;Your cash should be ready in accounting within 45 minutes.&lt;/h3&gt;\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 &gt; 0 &amp;&amp; $giver_has &gt;= $amount &amp;&amp; $bank &amp;&amp; $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 "&lt;h2 align='center'&gt;Wire of $$amount to bank ($bank) account ($account) complete.&lt;/h2&gt;\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 &gt; 0 &amp;&amp; $giver_has &gt;= $amount &amp;&amp; $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 "&lt;h2 align='center'&gt;Transfer of $$amount to $recipient complete.&lt;/h2&gt;\n";
      } else {
          action_error("Problem with employee fund transfer!",
                           "'$giver_id', '$recipient', '$amount', '$giver_has'");
      }
  }
  
  function account_info($row) {
  
      echo "&lt;table border='1' align='center'&gt;
            &lt;tr&gt;&lt;td colspan='2'&gt;&lt;p&gt;&lt;center&gt;&lt;b&gt;Account Information&lt;/b&gt;&lt;/center&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;
            &lt;tr&gt;&lt;td&gt;&lt;b&gt;Account:&lt;/b&gt;&lt;/td&gt;&lt;td&gt;$row[0]&lt;/td&gt;&lt;/tr&gt;
            &lt;tr&gt;&lt;td&gt;&lt;b&gt;Balance:&lt;/b&gt;&lt;/td&gt;&lt;td&gt;$$row[1]&lt;/td&gt;&lt;/tr&gt;
            &lt;tr&gt;&lt;td&gt;&lt;b&gt;Birthdate:&lt;/b&gt;&lt;/td&gt;&lt;td&gt;$row[6]&lt;/td&gt;&lt;/tr&gt;
            &lt;tr&gt;&lt;td&gt;&lt;b&gt;SSN:&lt;/b&gt;&lt;/td&gt;&lt;td&gt;$row[5]&lt;/td&gt;&lt;/tr&gt;
            &lt;tr&gt;&lt;td&gt;&lt;b&gt;Phone:&lt;/b&gt;&lt;/td&gt;&lt;td&gt;$row[4]&lt;/td&gt;&lt;/tr&gt;
            &lt;tr&gt;&lt;td&gt;&lt;b&gt;Email:&lt;/b&gt;&lt;/td&gt;&lt;td&gt;$row[7]@frobozzco.com&lt;/td&gt;&lt;/tr&gt;
            &lt;/table&gt;\n";
  }
  
  function account_actions($row, $names) {
  
      global $thispage;
  
      echo "&lt;table border=1 width='600' align='center'&gt;
  
            &lt;tr&gt;&lt;td&gt;&lt;center&gt;&lt;b&gt;Account Actions&lt;/b&gt;&lt;/center&gt;&lt;/td&gt;&lt;/tr&gt;
  
            &lt;tr&gt;&lt;td&gt;&lt;center&gt;&lt;b&gt;Wire Funds&lt;/b&gt;&lt;/center&gt;&lt;/td&gt;&lt;/tr&gt;
  
            &lt;tr&gt;&lt;td&gt;
            &lt;p&gt;To wire funds: enter the amount (in whole dollars), the 
            receiving bank's &lt;b&gt;routing number&lt;/b&gt; and &lt;b&gt;receiving account number&lt;/b&gt;, 
            and press 'Wire Funds!'&lt;/p&gt;
            Wire amount: $&lt;input name=wire_amount /&gt;&lt;br /&gt;
            Routing Number: &lt;input name=routing /&gt; (e.g. 091000022)&lt;br /&gt;
            Account Number: &lt;input name=wire_acct /&gt; (e.g. 923884509)&lt;br /&gt;
            &lt;p align='center'&gt;&lt;input type='submit' name='action' value='Wire Money'&gt;&lt;/p&gt;
            &lt;p /&gt;
            &lt;/td&gt;&lt;/tr&gt;
  
            &lt;tr&gt;&lt;td&gt;&lt;center&gt;&lt;b&gt;Transfer Money&lt;/b&gt;&lt;/center&gt;&lt;/td&gt;&lt;tr&gt;
  
            &lt;tr&gt;&lt;td&gt;&lt;p&gt;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!'&lt;/p&gt;
            Transfer Amount: $&lt;input name=transfer_amount /&gt;&lt;br /&gt;
            Transfer To: ";
            // create dropdown menu with accounts
            echo "&lt;select name='transfer_to' selected='select employee'&gt;\n";
            echo "&lt;option value='nobody'&gt;select employee&lt;/option&gt;\n";
            while ($name = mysql_fetch_array($names)) {
                echo "&lt;option value=\"$name[1], $name[0]\"&gt;$name[1], $name[0]&lt;/option&gt;\n";
            }
            echo "&lt;/select&gt;\n";
            echo "&lt;br /&gt;
            &lt;p align='center'&gt;&lt;input type='submit' name='action' value='Transfer Money'&gt;&lt;/p&gt;
            &lt;p /&gt;
            &lt;/td&gt;&lt;/tr&gt;
  
            &lt;tr&gt;&lt;td&gt;&lt;center&gt;&lt;b&gt;Withdraw Cash&lt;/b&gt;&lt;/center&gt;&lt;/td&gt;&lt;tr&gt;
  
            &lt;tr&gt;&lt;td&gt;&lt;p&gt;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.&lt;/p&gt;
            Withdraw Amount: $&lt;input name=withdraw_amount /&gt;&lt;br /&gt;
            &lt;p align='center'&gt;&lt;input type='submit' name='action' value='Withdraw Money'&gt;&lt;/p&gt;
            &lt;p /&gt;
            &lt;/td&gt;&lt;/tr&gt;
            &lt;/table&gt;
            \n";
  
  }
  
  function banner($row) {
  
      global $thispage;
  
      $fullname = "$row[2] $row[3]";
      echo "&lt;table width='100%'&gt;&lt;tr&gt;&lt;td&gt;
      &lt;p align='left'&gt;Welcome, $fullname. (&lt;a href='$thispage'&gt;Log Out&lt;/a&gt;)&lt;/p&gt;
            &lt;/td&gt;&lt;td&gt;
            &lt;p align='right'&gt;&lt;i&gt;(If you aren't $fullname, &lt;a href='$thispage'&gt;click here&lt;/a&gt;.)&lt;/i&gt;&lt;/p&gt;
            &lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;\n";
      echo "&lt;hr&gt;\n";
  
  
  }
  
  function login() {
  
      global $thispage;
  
      echo "&lt;p&gt;Enter your &lt;b&gt;account ID&lt;/b&gt; and password and click \"submit.\"&lt;/p&gt;\n";
      echo "&lt;table&gt;\n";
      echo "&lt;tr&gt;&lt;td&gt;Account ID Number: &lt;/td&gt;&lt;td&gt;&lt;input name='id' cols='10' /&gt;&lt;/td&gt;&lt;/tr&gt;\n";
      echo "&lt;tr&gt;&lt;td&gt;Password (alphanumeric only): &lt;/td&gt;&lt;td&gt;&lt;input name='password' cols='30' /&gt;&lt;/td&gt;&lt;/tr&gt;\n";
      echo "&lt;tr&gt;&lt;td&gt;&lt;input type='submit' value='Submit' name='submit'&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;\n";
      echo "&lt;/table&gt;\n";
  
  }
  
  ?&gt;
  &lt;/form&gt;
  &lt;p&gt;Done.&lt;/p&gt;
  &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>
  
  <p>The line:</p>
  
  <pre><code>$query = "SELECT * FROM accounts WHERE id = $id AND password = '$password'";
  </code></pre>
  
  <p>I've tried a couple of strings in the ID input (I'm working from my browser) such as</p>
  
  <pre><code>100 OR id=id;
  0 OR 1=1;
  </code></pre>
  
  <p>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.</p>
  
  <p>That or I'm completely overlooking a more obvious exploit.</p>