Search code examples
phpsqlsql-injection

Special characters in password causing internal server error "SQL Injection attack detected via libinjection"


I have an old custom php website that I've been working on. I have updated the php code and have a password reset functionality in place. I moved the Connections folder outside of the root folder as that is what I read was the recommended course of action. My client asked for the ability to use special characters in the password reset. I have regex for this that works great. Everything seems to be working, except when I try to use multiple characters in a row, I get an internal server error. When I check the error log this is what it says:

ModSecurity: Warning. detected SQLi using libinjection with fingerprint 'novc' [file "/dh/apache2/template/etc/mod_sec3_CRS/REQUEST-942-APPLICATION-ATTACK-SQLI.conf"][msg "SQL Injection Attack Detected via libinjection"] [data "Matched Data: novc found within ARGS:newPassword2: Abcd1234!@#$"] [severity "CRITICAL"] [ver "OWASP_CRS/3.3.2"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-sqli"] [tag "paranoia-level/1"] [tag "OWASP_CRS"] [tag "capec/1000/152/248/66"]  

This was not an issue on a test website I created, but I also have the database connection file in the root of the test website folder. In the live website I have the connection file outside of the project folder as I read this was best practice.

Connections folder
--connection.php
live website folder
--index.php
--other files, etc.

test website folder
--Connection.php
--other files

Here is my query to update the password:

// if form is submitted and the value equals the value of the hidden input
if (isset($_POST['newPassword'])) {
    // password regex match
  if (!preg_match('/^(?=.*[A-Za-z])(?=.*\d)(?=.*[!#$%&()*@?^])[A-Za-z\d!#$%&()*@?^]{8,30}$/', $_POST['newPassword'])) {
    exit('password should be between 8 and 30 characters and contain at least one number and one special character');
  }
  // Check if both the password and confirm password fields match
  if ($_POST['newPassword'] != $_POST['newPassword2']) {
  exit('Passwords do not match!');
  }
  // set the date
  $month = date ("M");
  $year = date ("Y");
  $day = date ("j");
  // lastEditTime and lastEditedBy
  $lastEditTime = $month." ".$day.", ".$year; 
  $lastEditedBy = $_SESSION['MM_Username'];
  $userId = $_SESSION['MM_UserID'];
  $newPassword = password_hash($_POST['newPassword'],PASSWORD_DEFAULT);
  $updateStmt = $connection->prepare("UPDATE tbl_users SET newPassword= ?, lastEditedBy= ?, lastEditTime= ? WHERE userID= ?");
  $updateStmt->bind_param('sssi',$newPassword,$lastEditedBy,$lastEditTime,$userId);
  $updateStmt->execute();
    $updateStmt->close();     

  header("Location: reset4.php");
  exit;
}

I have never encountered this problem before. Does anyone have any advice on how to correct this?


Solution

  • Your ModSecurity rules for SQL injection are blocking things that look like SQL injection - and that can lead to false positives. These rules are likely coming from the OWASP ModSecurity Core Rule Set

    Generally you want to exclude a password field from ModSecurity Core Rule Set checking. This is normally done by adding to your ModSec config a rule like:

    SecRule REQUEST_URI "@streq /your/page/uri" \
    "id:12345,phase:1,t:none,nolog,pass,\
    ctl:ruleRemoveTargetByTag=.*;ARGS:password"
    

    Sub in your own URL and your specific params.

    I don't know how you would go about modifying your config in a Dreamhost environment (or even whether they allow that). That is a seperate question.

    Note also that ModSecurity should be configured to avoid logging the values from password and other sensitive fields. See "Removing Sensitive Data from Audit Logs" in the excellent ModSecurity Handbook.