Way back in 2013, Roberto Salgado’s BlackHat talk titled “SQLi Optimization and Obfuscation Techniques” showed how you could obfuscate strings and numerous other data types in ways that could be used to trick middleware and interpreters. The folks at GoSecure found that one of the tricks from the BH presentation could be used to trick Web Application Firewalls protecting applications vulnerable to SQL Injection with a MySQL or MariaDB backend. The trick involves MySQL and MariaDB ignoring numeric literals represented in scientific notation format when used in an invalid context. This allows for all sorts of interesting security things to happen.
What’s the security implication of this?
Although not a security problem in itself, the bug can be used in many security contexts to bypass controls. The usage of this bug to bypass the AWS Web Application Firewall, as shown in the blog, is a prime example of how data can be interpreted by different systems differently based on context.
Examples of valid literals are “12.E-2”, “66.55E12” and “36.96e-15”. These numeric literals are broken down by the MySQL parser into three parts; before the dot, after the dot but before the E and after the E. The bug arises due to improper verification of the part after the E where the code simply ignores the user input when provided with an invalid literal like 1234.567E().
Almost all decent Web Application Firewalls detect SQL Injections. Some more aggressively than others. SQL Injection occurs when user-provided input is parsed as part of the command on the SQL server allowing characters provided by the user to be interpreted as part of the query which allows the user to manipulate the query in unintended ways.
A web application firewall detects characters that could potentially be used to alter the meaning of the backend query, but this detection is heavily based on string matches and regular expressions.
The researchers found that the protection offered by the AWS Web Application Firewall could be bypassed using invalid and out of context scientific notation numeric literals. Hence, a request such as the following would get blocked
_curl "http://example.cloudfront.net/index.php?x=1' or '1'='1"_
__But the following request would go through
_curl "http://example.cloudfront.net/index.php?x=1' or 1.1e(0) '1'='1"_
Even in the case of ModSecurity, a popular Web Application Firewall for Apache and nginx was unable to detect a malicious string if it contained the scientific notation when it was running at a paranoia level of 1 (PL1) which is the default. The SQL Injection attempt was detected when ModSecurity was running on Paranoia level 2 (PL2).
The software running the services on all major cloud platforms have the same bugs that software running on a standalone data centre. The difference is that there are restrictive controls in place by the cloud providers to ensure user input does not reach the underlying software layer for services that are meant to expose only APIs.
Not understanding the context of the data passing through a layer raises questions about the design implications of a service. Allowing data to be inspected can also be a privacy nightmare even if it is for security reasons. In this case (if there was) the SSL termination happens at or before the WAF, allowing the data to be inspected but because the system has no context to the data, it failed to be detected as malicious).
A layered approach to security works best in practice, ensuring user data is processed as malicious regardless of source before consuming it is one way to go about (which is also a common SQL injection fix). It would be interesting to see what other cloud based web application firewalls have insufficient rules.