-
Notifications
You must be signed in to change notification settings - Fork 727
Bypass the latest crs v3.1.0-rc3 rules for SQL injection #1167
Comments
Hi @seedis thanks for sharing this! I've done some tests and I confirm that it works on PL1. By increasing the Paranoia Level (>=2) I can't exploit the SQLi anymore because of I've changed your PHP script in order to make it works with the WordPress DB as follows: <?php
$id=$_GET['id'];
$conn=new mysqli('mysql','root','password','wordpress');
if(!$conn){
die("Error to connect database!");
}
$sql="select user_login from wp_users where id=".$id;
echo "$sql"."</br></br>";
$res=$conn->query($sql);
if($res){
$row=$res->fetch_row();
echo '<pre>';
print_r($row);
echo '</pre>';
echo "\t Hello <b>$row[0] </b>,Welcome to login,having a good day!";
$res->free();
$conn->close();
} else {
echo "<b>".mysqli_error($conn)."</b>";
} And used this payload (blind sqli, and something like user enumeration):
By using PL2 the same payload is blocked by rule Probably, it could be intercepted by something like: SecRule ARGS "@rx {\x60([^\x60]+)\x60" "id:999,\
phase:1,\
capture,\
t:urlDecode,\
t:removeWhitespace,\
t:removeComments,\
block,msg:'SQLi Bypass Attempt #1167',\
logdata:'Detected using function %{tx.0}'" With the same payload: but I don't know if this could lead to many false positives. |
Thank you for reporting @seedis - and for trying this out @theMiddleBlue. I do not have a PHP server at hand on the quick, so I tried this out by hand with curl. I took
But curl is really upset. Then I took
and I got the following alerts:
So 942100 detects this just fine in my case. Can you guys give me a naked curl call that bypasses CRS and still executes? Other than that, detecting on PL2 is not that bad. We will always have bypasses. Having a bypass at PL1 but being detected at PL2 is inline with out project goals. But it goes without saying that changing a rule to detect this (as well) could make sense if we can avoid false positives. |
same behavior here :/ using curl it is detected by 942100 but it if I send it using BurpSuite it works. don't know why... I'm trying to figure it out. |
Glad you checked. Could you run a tcpdump when doing burp? In cases where curl interferes with the payload, we can also use netcat (nc) for raw socket writing. |
I used the default level when testing. |
ok, interesting findings:
|
@dune73 Urlencoded, the payload becomes:
I noticed that this goes undetected at PL1. It seems to be a false negative in libinjection:
But it also seems a false negative in our own rule 942140, which should detect the mention of |
@dune73 @theMiddleBlue |
I confirm. We have a PL1 bypass. Thank you @theMiddleBlue and @lifeforms. @lifeforms: Can you open an issue with libinjection? @themiddle: The whole encoding trickery is indeed funny, but you should disable deflation towards the application on the ModSec level. With that 951230 becomes always active, but this still leaves us with the blind sqli. What do we do? Leave it as is (remember: we detect at PL2) and wait for libinjection to catch up. OR extend an existing rule (which one?) or create a new one? |
Defense in depth seems to say we extend our rule and hope lib injection fixes it |
@seedis: Thank you for explaining this extension annotation. This is dangerous and tricky to detect for us. Good to have sql experts at hand that can explain things as this to us. |
I'll report it to libinjection. But libinjection > ModSec 2.9.4 is a long cycle, we can't depend on that. Maybe @franbuehler could check why
Why is it slipping past us? |
@lifeforms 942140 doesn't match because there is no boundary before information_schema the 5000 is part of the same word so we may add an additional optional word prefix to 942140 and it will work. something like this: 942440 at PL2 is there to detect the /*! |
As @lifeforms mentioned, the string
The problem in rule 942140 is, as @spartantri said, the word boundary: His solution with the But that only solves the problem related to Either we extend all our sqli rules with this regexp or we make a new rule to detect extension annotation. I am not an sql pro (had a look at: https://dev.mysql.com/doc/refman/8.0/en/comments.html), but maybe something like that would work to detect (some) extensions:
Tested with: I am not sure about false positives. The rule 942440 from PL2 catches both I would rather write a new rule (maybe even on PL1) to catch these extensions, than to extend all sql rules. |
I agree on the new rule. Yesterday, I mentioned crazy special char combinations like in #425. But thinking some more about this, I no longer propose to combine this. Extension annotation is clearly a specialty of the mysql family. So the rule should stay with the sql rules. We think there should not be too many FPs, but adding it to PL1 is still post-feature-freeze for 3.1 and we really do not know. So I do not think we should do that. Maybe for PL2 and lower to PL1 in the future. |
Vulnerability demo(php+mysql+apache)
test.php
Download and install the latest v3.1.0-rc3 rules and enable blocking protection for testing.
I found a way to bypass the rules for SQL injection through black box testing.
This method is: {`a`b} , where a is a special function name, such as if, version, etc., and b is the sql statement to be executed.
Using the method to successfully bypass the rules for SQL injection, you can see that the database name was successfully read using the error.
In this way, you can use this method to bypass the crs rules and get any content in the database in the vulnerable system.
Please fix this security issue as soon as possible,Thank You.
The text was updated successfully, but these errors were encountered: