Skip to main content
Version: 2.11

ARMR SQL Rule

Overview

SQL injection (SQLi) attack consists of the insertion or “injection” of a SQL query via the input data from the client to the application. The ARMR sql rule can be used to enable protection against SQL injection attacks.

info

SQL Injection vulnerabilities are covered by CWE-89.

Given (Conditions)

The user can specify two conditions in the ARMR sql rule - input and vendor.

input

This allows the user to specify the source of the untrusted data.

The following three sources are supported:

  • http data introduced via HTTP/HTTPS requests

  • database data introduced via JDBC connections

  • deserialization data introduced via Java or XML deserialization

The rule will trigger if the source of the untrusted data matches that specified in the rule.

If no value is specified then a default value of http is used.

An exception will be thrown if an unsupported value is provided.

vendor

This is an optional declaration that allows the user to specify the database type to be protected. The following databases are supported:

  • db2

  • mariadb

  • mssql

  • mysql

  • oracle

  • sybase

  • postgres

In addition, a value of any may be specified which will enable the agent to automatically detect the database type used by the application.

One of the listed database types, or the value any, must be specified if the vendor declaration is present.

If no vendor declaration is specified then a default value of any is used.

  • options:

    • Depending on the database configuration, the following optional parameters are also supported to allow the agent to accurately detect SQL injection attacks:

      • ansi-quotes - mysql and mariadb: corresponds to the ANSI_QUOTES server mode.

      • no-backslash-escapes - mysql and mariadb: corresponds to the NO_BACKSLASH_ESCAPES server mode.

      • quoted-identifiers - mssql and sybase: corresponds to the QUOTED_IDENTIFIER flag

When (Event)

injection

This condition allows the user to specify the type of injection:

  • successful-attempt the rule will trigger upon detecting a valid SQLi payload that would have resulted in a successful SQLi attack, exploiting the underlying database.

  • failed-attempt the rule will trigger upon detecting an invalid SQLi payload that would have resulted in an unsuccessful SQLi attack, which could expose the underlying database configuration or vendor.

If no value is specified then a default value of successful-attempt is used.

In addition, the user may optionally specify the following parameter:

  • permit: query-provided the rule will not trigger in the case where the entire SQL query (and not just part of it) has come from any of the untrusted sources defined in the input declaration.

An exception will be thrown if an unsupported value is provided. |

info

Multiple sql rules are allowed in the same ARMR mod providing they have different injection types.

Then (Action)

The action statement specifies the action the agent takes whenever an attack is detected. There are two supported actions protect and detect:

protectA valid SQL injection attack is not allowed to be processed by the database.

If configured, a log message is generated with details of the event.

Optionally, for protect action, one can specify a new HTTP 400 response code to be sent by the web-server when the SQL injection takes place using the syntax http-response: {new-response: {code: 400}}, for example;

protect(http-response: {new-response: {code: 400}}, message: "", severity: 10)
detectMonitoring mode: the application behaves as normal. SQLi attack are allowed by the agent.

If configured, a log message is generated with details of the event.

A log message must be specified with this action.

In the case of protect, if no additional configuration is given, the rule will take a default action depending on which of the injection types has occurred. A specific action can be configured for this rule to send an HTTP response with a specified status code and a message as body. These configurations are further described in the table below.

warning

The HTTP 400 (Bad Request) status code is only supported in the protect action declaration.

warning

Not all applications / application servers will allow the http-response code to be actually sent to the client. In cases where the transfer of the data from the server to the client has already started (i.e. where a portion of the webpage has already been rendered, before SQL Injection has happened), the output stream will be closed by the rule PROTECT action, but the delivery of the 200 response code could have already happened.

successful-attemptfailed-attempt
protectdefaultA SQLException is thrown by the agent to indicate the SQL statement is invalid, letting the server handle the exception gracefully.The HTTP connection, from which the malicious data that exploited the SQL statement originated, is disconnected.
send HTTP 400 (Bad Request) responseThe server will respond back to the web client with a brand new HTTP response that has been configured with a status code (HTTP 400 Bad Request).The server will respond back to the web client with a brand new HTTP response that has been configured with a status code (HTTP 400 Bad Request).
detectThe SQL injection attack is allowed to be processed by the database.The invalid SQL statement is allowed to be processed by the database.

As part of the action statement, the user may optionally specify the parameter stacktrace: “full”. When this parameter is specified, the stacktrace of the location of the attempted exploit is included in the security log entry.

info

Payload whitelisting can be applied using the property com.waratek.AllowSQLiPayloads. The value supplied should be a comma-separated list of strings to substring-match against SQLi payloads to be whitelisted and therefore not register as an SQL injection attack.

  • To whitelist events where untrusted input contains a substring-match to 'users' :

com.waratek.AllowSQLiPayloads=users

  • To whitelist events where untrusted input contains a substring-match to 'nam', e.g. name, names, named, naming:

com.waratek.AllowSQLiPayloads=nam

  • To whitelist events where untrusted input contains a substring-match to either 'AND' or 'OR'

com.waratek.AllowSQLiPayloads=AND,OR

  • The substring matches are case-sensitive. If the payload to be whitelisted includes a comma, then the comma should be escaped with a backslash so it is not considered the list delimiter. Therefore, to whitelist events where untrusted input contains a substring-match to 'foo,BAr'

com.waratek.AllowSQLiPayloads=foo\,BAr

  • Whitelisted values may contain spaces. To whitelist events where untrusted input contains a substring-match to ‘AND DOB IS NULL' .

com.waratek.AllowSQLiPayloads=AND DOB IS NULL

Example

The following sql rule is used to protect a MySQL database from SQL injection attacks.

The input and injection conditions are satisfied when the untrusted data originates from an HTTP/HTTPS request, and the resulting SQL statement is either a valid query that will exploit the database, or an invalid query that may disclose information about the database configuration or vendor.

An action of protect is defined to ensure that the agent does not allow any malicious SQL statement to be processed by the database. A log message and severity are both specified which will be included in any generated log entries if an attack is detected.

app("SQL mod"):
requires(version: ARMR/2.7)
sql("Protect MySql database from SQL Injection attacks"):
vendor(mysql)
input(http)
injection(successful-attempt, failed-attempt)
protect(message: "SQL injection attack detected and blocked", severity: High)
endsql
endapp

Logging

When the sql rule is triggered a log entry similar to the following is generated:

<10>1 2021-03-30T17:33:55.538+01:00 userX_system java 32008 - - CEF:0|ARMR:ARMR|ARMR|2.7|Protect MySql database from SQL Injection attacks|Execute Rule|High|rt=Mar 30 2021 17:33:55.537 +0100 dvchost=userX_system procid=32008 appVersion=1 ruleType=sql securityFeature=sql injection act=protect msg=SQL injection attack detected and blocked databaseVendor=mysql httpSessionId=3153E581A645E2A54D3C12D3928473BC sql=SELECT * FROM users_table WHERE str_name\='' or '1'\='1'; taintSource=HTTP_SERVLET httpRequestUri=/spiracle/Get_int httpRequestMethod=GET internalHttpRequestUri=/spiracle/Get_int httpCookies=JSESSIONID\=3153E581A645E2A54D3C12D3928473BC remoteIpAddress=0:0:0:0:0:0:0:1

Further Examples

The following mod is the same as the previous example, with the stacktrace also logged:

app("SQL mod - with stacktrace"):
requires(version: ARMR/2.7)
sql("Protect MySql database from SQL Injection attacks"):
vendor(mysql)
input(http)
injection(successful-attempt, failed-attempt)
protect(message: "SQL injection attack detected and blocked", severity: High, stacktrace: "full")
endsql
endapp

Logging

When the above ARMR sql rule is triggered a log entry similar to the following is generated:

<10>1 2021-04-01T11:30:25.075+01:00 userX_system java 25024 - - CEF:0|ARMR:ARMR|ARMR|2.7|Protect MySql database from SQL Injection attacks|Execute Rule|High|rt=Apr 01 2021 11:30:25.073 +0100 dvchost=userX_system procid=25024 appVersion=1 ruleType=sql securityFeature=sql injection act=protect msg=SQL injection attack detected and blocked stacktrace=com.waratek.spiracle.sql.util.SelectUtil.executeQuery(SelectUtil.java:67)\ncom.waratek.spiracle.sql.servlet.oracle.Get_int.executeRequest(Get_int.java:77)\ncom.waratek.spiracle.sql.servlet.oracle.Get_int.doGet(Get_int.java:52)\njavax.servlet.http.HttpServlet.service(HttpServlet.java:624)\njavax.servlet.http.HttpServlet.service(HttpServlet.java:731)\nsun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\nsun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\nsun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\njava.lang.reflect.Method.invoke(Method.java:498)\norg.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)\norg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)\norg.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)\nsun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\nsun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\nsun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\njava.lang.reflect.Method.invoke(Method.java:498)\norg.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)\norg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)\norg.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:218)\norg.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)\norg.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)\norg.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:169)\norg.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)\norg.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:956)\norg.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)\norg.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:442)\norg.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1082)\norg.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:623)\norg.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:316)\njava.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)\njava.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)\norg.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\njava.lang.Thread.run(Thread.java:748) databaseVendor=mysql httpSessionId=Unknown sql=SELECT * FROM users_table WHERE str_name\='' or '1'\='1'; taintSource=HTTP_SERVLET httpRequestUri=/spiracle/Get_int httpRequestMethod=GET internalHttpRequestUri=/spiracle/Get_int httpCookies= remoteIpAddress=0:0:0:0:0:0:0:1

The following mod enables the agent to automatically detect the database type in use by the application. The mod protects against valid SQL injection attacks that originate from an HTTP/HTTPS request.

app("SQL mod 2"):
requires(version: ARMR/2.7)
sql("Protect database from successful SQL Injection attacks"):
vendor(any)
input(http)
injection(successful-attempt)
protect(message: "SQL injection attack detected and blocked", severity: Very-High)
endsql
endapp

The following mod monitors a MSSQL database, detecting valid SQL injection attacks that originate from a JDBC connection.

app("SQL mod 3"):
requires(version: ARMR/2.7)
sql("Protect MSSQL database from successful stored SQL Injection attacks"):
vendor(mssql)
input(database)
injection(successful-attempt)
detect(message: "SQL injection attack detected", severity: 5)
endsql
endapp

The following mod protects an Oracle database against valid SQL injection attacks that originate from an HTTP /HTTPS request. If the entire SQL query has originated from an HTTP/HTTPS request then the mod will let it through to the database.

app("SQL mod 4"):
requires(version: ARMR/2.7)
sql("Protect Oracle database from successful SQL Injection attacks"):
vendor(oracle)
input(http)
injection(successful-attempt, permit: query-provided)
protect(message: "SQL injection attack detected and blocked", severity: 8)
endsql
endapp

The following mod does not specify the vendor declaration, enabling, by default, the agent to automatically detect the database type in use by the application. The mod protects against invalid attempts at SQL injection that originate from various untrusted sources. Logging is switched off by the omission of the log message parameter.

app("SQL mod 5"):
requires(version: ARMR/2.7)
sql("Protect database from unsuccessful SQL Injection attacks from various sources"):
input(http, database, deserialization)
injection(failed-attempt)
protect()
endsql
endapp

The following mod does not specify the vendor declaration which is equivalent to specifying vendor(any) , as was the case in the previous example above. The mod protects against invalid attempts at SQL injection that originate from various untrusted sources. Logging is switched on by the inclusion of the log message parameter.

app("SQL mod 6"):
requires(version: ARMR/2.7)
sql("Protect database from unsuccessful SQL Injection attacks from various sources"):
input(http, database, deserialization)
injection(failed-attempt)
protect(message: "SQL injection failed attempt blocked", severity: Medium)
endsql
endapp

Logging

When the above ARMR sql rule is triggered a log entry similar to the following is generated. The databaseVendor CEF extension is not an expected CEF extension when a failed-attempt SQL security event is logged

<12>1 2024-03-19T10:35:31.342Z userX_system java 5750 - - CEF:0|ARMR|SQL mod 6|2.7|Protect database from unsuccessful SQL Injection attacks from various sources|Execute Rule|Medium|rt=Mar 19 2024 10:35:31.341 +0000 msg=SQL injection failed attempt blocked httpSessionId=202A1F3E9FFF5161C87E2612D2DF7EF6 appVersion=1 httpRequestUri=/spiracle/MsSql_Get_int httpCookies=JSESSIONID\=202A1F3E9FFF5161C87E2612D2DF7EF6 procid=5750 httpRequestMethod=GET sql=SELECT * FROM users WHERE id \= '1'' taintSource=HTTP_SERVLET act=protect dvchost=userX_system ruleType=sql securityFeature=sql injection internalHttpRequestUri=/spiracle/MsSql_Get_int remoteIpAddress=127.0.0.1

The following mod automatically detects the database type in use by the application. It protects databases against valid SQL injection attacks but also malicious SQL queries that originate from an untrusted HTTP request source. The action configuration in place returns an HTTP 400 response back to the web client with a default message as the response body.

app("SQL mod 7"):
requires(version: ARMR/2.7)
sql("Protect against SQLI attacks and malicious SQL payloads coming from HTTP"):
injection(successful-attempt, failed-attempt)
protect(http-response: {new-response: {code: 400}},
message: "SQL injection attack detected and blocked", severity: 10)
endsql
endapp

The Waratek Agent v25.2.0 introduces a new CEF extension sqlTaintPattern that will be logged in SQL injection events. The sqlTaintPattern extension contains details on which of the characters in the SQL injection payload triggering the sql rule were tainted (or not tainted), and gives the taint source of each tainted character. For example:

sqlTaintPattern=______________________________JJJJJDDDDDDCCCCCXX_

The individual characters correspond with the taint sources of the payload, according to the mapping:

DATABASE -> D
HTTP_COOKIE -> C
HTTP_SERVLET -> H
JAVA_DESERIALIZATION -> J
XML_DESERIALIZATION -> X