Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions addOns/ascanrules/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Maintenance changes.
- Depends on an updated version of the Common Library add-on.
- The following scan rules and their alerts have been renamed to clarify that they're time based (Issue 7341).
- SQL Injection - Oracle
- SQL Injection - MsSQL
- SQL Injection - Hypersonic

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@

import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
Expand All @@ -38,11 +37,11 @@
/**
* TODO: maybe implement a more specific UNION based check for Oracle (with table names)
*
* <p>The SqlInjectionOracleScanRule identifies Oracle specific SQL Injection vulnerabilities using
* Oracle specific syntax. If it doesn't use Oracle specific syntax, it belongs in the generic
* SQLInjection class! Note the ordering of checks, for efficiency is : 1) Error based (N/A) 2)
* Boolean Based (N/A - uses standard syntax) 3) UNION based (TODO) 4) Stacked (N/A - uses standard
* syntax) 5) Blind/Time Based (Yes)
* <p>This scan rule identifies Oracle specific SQL Injection vulnerabilities using Oracle specific
* syntax. If it doesn't use Oracle specific syntax, it belongs in the generic SQLInjection class!
* Note the ordering of checks, for efficiency is : 1) Error based (N/A) 2) Boolean Based (N/A -
* uses standard syntax) 3) UNION based (TODO) 4) Stacked (N/A - uses standard syntax) 5) Blind/Time
* Based (Yes)
*
* <p>See the following for some great specific tricks which could be integrated here
* http://www.websec.ca/kb/sql_injection
Expand All @@ -60,44 +59,16 @@
*
* @author 70pointer
*/
public class SqlInjectionOracleScanRule extends AbstractAppParamPlugin
public class SqlInjectionOracleTimingScanRule extends AbstractAppParamPlugin
implements CommonActiveScanRuleInfo {

private int expectedDelayInMs = 5000;

private boolean doUnionBased = false; // TODO: use in Union based, when we implement it
private boolean doTimeBased = false;

private int doUnionMaxRequests = 0; // TODO: use in Union based, when we implement it
private int doTimeMaxRequests = 0;

/** Oracle one-line comment */
public static final String SQL_ONE_LINE_COMMENT = " -- ";

/**
* create a map of SQL related error message fragments, and map them back to the RDBMS that they
* are associated with keep the ordering the same as the order in which the values are inserted,
* to allow the more (subjectively judged) common cases to be tested first Note: these should
* represent actual (driver level) error messages for things like syntax error, otherwise we are
* simply guessing that the string should/might occur.
*/
private static final Map<String, String> SQL_ERROR_TO_DBMS = new LinkedHashMap<>();

static {
SQL_ERROR_TO_DBMS.put("oracle.jdbc", "Oracle");
SQL_ERROR_TO_DBMS.put("SQLSTATE[HY", "Oracle");
SQL_ERROR_TO_DBMS.put("ORA-00933", "Oracle");
SQL_ERROR_TO_DBMS.put("ORA-06512", "Oracle"); // indicates the line number of an error
SQL_ERROR_TO_DBMS.put("SQL command not properly ended", "Oracle");
SQL_ERROR_TO_DBMS.put("ORA-00942", "Oracle"); // table or view does not exist
SQL_ERROR_TO_DBMS.put("ORA-29257", "Oracle"); // host unknown
SQL_ERROR_TO_DBMS.put("ORA-00932", "Oracle"); // inconsistent datatypes

// Note: only Oracle mappings here.
// TODO: is this all?? we need more error messages for Oracle for different languages. PHP
// (oci8), ASP, JSP(JDBC), etc
}

/** the 5 second sleep function in Oracle SQL */
private static String SQL_ORACLE_TIME_SELECT =
"SELECT UTL_INADDR.get_host_name('10.0.0.1') from dual union SELECT UTL_INADDR.get_host_name('10.0.0.2') from dual union SELECT UTL_INADDR.get_host_name('10.0.0.3') from dual union SELECT UTL_INADDR.get_host_name('10.0.0.4') from dual union SELECT UTL_INADDR.get_host_name('10.0.0.5') from dual";
Expand Down Expand Up @@ -167,7 +138,8 @@ public class SqlInjectionOracleScanRule extends AbstractAppParamPlugin
}

/** for logging. */
private static final Logger LOGGER = LogManager.getLogger(SqlInjectionOracleScanRule.class);
private static final Logger LOGGER =
LogManager.getLogger(SqlInjectionOracleTimingScanRule.class);

@Override
public int getId() {
Expand Down Expand Up @@ -210,25 +182,13 @@ public void init() {

// set up what we are allowed to do, depending on the attack strength that was set.
if (this.getAttackStrength() == AttackStrength.LOW) {
doTimeBased = true;
doTimeMaxRequests = 3;
doUnionBased = true;
doUnionMaxRequests = 3;
} else if (this.getAttackStrength() == AttackStrength.MEDIUM) {
doTimeBased = true;
doTimeMaxRequests = 5;
doUnionBased = true;
doUnionMaxRequests = 5;
} else if (this.getAttackStrength() == AttackStrength.HIGH) {
doTimeBased = true;
doTimeMaxRequests = 10;
doUnionBased = true;
doUnionMaxRequests = 10;
} else if (this.getAttackStrength() == AttackStrength.INSANE) {
doTimeBased = true;
doTimeMaxRequests = 100;
doUnionBased = true;
doUnionMaxRequests = 100;
}
}

Expand Down Expand Up @@ -256,7 +216,6 @@ public void scan(HttpMessage originalMessage, String paramName, String paramValu
long originalTimeUsed = msgTimeBaseline.getTimeElapsedMillis();
// end of timing baseline check

int countUnionBasedRequests = 0;
int countTimeBasedRequests = 0;

LOGGER.debug(
Expand All @@ -269,7 +228,6 @@ public void scan(HttpMessage originalMessage, String paramName, String paramValu
// Check for time based SQL Injection, using Oracle specific syntax
for (int timeBasedSQLindex = 0;
timeBasedSQLindex < SQL_ORACLE_TIME_REPLACEMENTS.length
&& doTimeBased
&& countTimeBasedRequests < doTimeMaxRequests;
timeBasedSQLindex++) {
HttpMessage msgAttack = getNewMsg();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,7 @@ <H2 id="id-40021">SQL Injection - Oracle (Time Based)</H2>
<br>
Note that this rule does not currently allow you to change the length of time used for the timing attacks due to the way the delay is caused.
<p>
Latest code: <a href="https://github.com/zaproxy/zap-extensions/blob/main/addOns/ascanrules/src/main/java/org/zaproxy/zap/extension/ascanrules/SqlInjectionOracleScanRule.java">SqlInjectionOracleScanRule.java</a>
Latest code: <a href="https://github.com/zaproxy/zap-extensions/blob/main/addOns/ascanrules/src/main/java/org/zaproxy/zap/extension/ascanrules/SqlInjectionOracleTimingScanRule.java">SqlInjectionOracleTimingScanRule.java</a>
<br>
Alert ID: <a href="https://www.zaproxy.org/docs/alerts/40021/">40021</a>.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ ascanrules.sqlinjection.mssql.alert.timebased.extrainfo = The query time is cont
ascanrules.sqlinjection.mssql.name = SQL Injection - MsSQL (Time Based)
ascanrules.sqlinjection.mysql.name = SQL Injection - MySQL
ascanrules.sqlinjection.name = SQL Injection
ascanrules.sqlinjection.oracle.name = SQL Injection - Oracle
ascanrules.sqlinjection.oracle.name = SQL Injection - Oracle (Time Based)
ascanrules.sqlinjection.postgres.name = SQL Injection - PostgreSQL
ascanrules.sqlinjection.refs = https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html
ascanrules.sqlinjection.soln = Do not trust client side input, even if there is client side validation in place.\nIn general, type check all data on the server side.\nIf the application uses JDBC, use PreparedStatement or CallableStatement, with parameters passed by '?'\nIf the application uses ASP, use ADO Command Objects with strong type checking and parameterized queries.\nIf database Stored Procedures can be used, use them.\nDo *not* concatenate strings into queries in the stored procedure, or use 'exec', 'exec immediate', or equivalent functionality!\nDo not create dynamic SQL queries using simple string concatenation.\nEscape all data received from the client.\nApply an 'allow list' of allowed characters, or a 'deny list' of disallowed characters in user input.\nApply the principle of least privilege by using the least privileged database user possible.\nIn particular, avoid using the 'sa' or 'db-owner' database users. This does not eliminate SQL injection, but minimizes its impact.\nGrant the minimum database access that is necessary for the application.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,13 @@
import org.zaproxy.zap.model.TechSet;
import org.zaproxy.zap.testutils.NanoServerHandler;

/** Unit test for {@link SqlInjectionOracleScanRule}. */
class SqlInjectionOracleScanRuleUnitTest extends ActiveScannerTest<SqlInjectionOracleScanRule> {
/** Unit test for {@link SqlInjectionOracleTimingScanRule}. */
class SqlInjectionOracleTimingScanRuleUnitTest
extends ActiveScannerTest<SqlInjectionOracleTimingScanRule> {

@Override
protected SqlInjectionOracleScanRule createScanner() {
return new SqlInjectionOracleScanRule();
protected SqlInjectionOracleTimingScanRule createScanner() {
return new SqlInjectionOracleTimingScanRule();
}

@Test
Expand Down