MediatorVendor.java
package com.jsql.model.injection.vendor;
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.injection.vendor.model.Vendor;
import com.jsql.model.injection.vendor.model.VendorYaml;
import com.jsql.util.I18nUtil;
import com.jsql.util.LogLevelUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.SystemUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
public class MediatorVendor {
/**
* Log4j logger sent to view.
*/
private static final Logger LOGGER = LogManager.getRootLogger();
private static final String LOG_VENDOR = "{} [{}]";
/**
* Database vendor currently used.
* It can be switched to another vendor by automatic detection or manual selection.
*/
private Vendor vendor;
/**
* Database vendor selected by user (default UNDEFINED).
* If not UNDEFINED then the next injection will be forced to use the selected vendor.
*/
private Vendor vendorByUser;
// TODO Replace with enum
private final Vendor auto;
private final Vendor cubrid;
private final Vendor db2;
private final Vendor derby;
private final Vendor firebird;
private final Vendor h2;
private final Vendor hsqldb;
private final Vendor informix;
private final Vendor mckoi;
private final Vendor mimer;
private final Vendor monetdb;
private final Vendor mysql;
private final Vendor neo4j;
private final Vendor oracle;
private final Vendor postgresql;
private final Vendor sqlite;
private final Vendor sqlserver;
private final Vendor sybase;
private final Vendor vertica;
private final List<Vendor> vendors;
private final InjectionModel injectionModel;
public MediatorVendor(InjectionModel injectionModel) {
this.injectionModel = injectionModel;
Vendor access = new Vendor(new VendorYaml("access.yml", injectionModel));
Vendor altibase = new Vendor(new VendorYaml("altibase.yml", injectionModel));
Vendor ctreeace = new Vendor(new VendorYaml("ctreeace.yml", injectionModel));
Vendor exasol = new Vendor(new VendorYaml("exasol.yml", injectionModel));
Vendor frontbase = new Vendor(new VendorYaml("frontbase.yml", injectionModel));
Vendor hana = new Vendor(new VendorYaml("hana.yml", injectionModel));
Vendor ingres = new Vendor(new VendorYaml("ingres.yml", injectionModel));
Vendor iris = new Vendor(new VendorYaml("iris.yml", injectionModel));
Vendor maxdb = new Vendor(new VendorYaml("maxdb.yml", injectionModel));
Vendor netezza = new Vendor(new VendorYaml("netezza.yml", injectionModel));
Vendor nuodb = new Vendor(new VendorYaml("nuodb.yml", injectionModel));
Vendor presto = new Vendor(new VendorYaml("presto.yml", injectionModel));
Vendor teradata = new Vendor(new VendorYaml("teradata.yml", injectionModel));
this.auto = new Vendor();
this.cubrid = new Vendor(new VendorYaml("cubrid.yml", injectionModel));
this.db2 = new Vendor(new VendorYaml("db2.yml", injectionModel));
this.derby = new Vendor(new VendorYaml("derby.yml", injectionModel));
this.firebird = new Vendor(new VendorYaml("firebird.yml", injectionModel));
this.h2 = new Vendor(new VendorYaml("h2.yml", injectionModel));
this.hsqldb = new Vendor(new VendorYaml("hsqldb.yml", injectionModel));
this.informix = new Vendor(new VendorYaml("informix.yml", injectionModel));
this.mckoi = new Vendor(new VendorYaml("mckoi.yml", injectionModel));
this.mimer = new Vendor(new VendorYaml("mimersql.yml", injectionModel));
this.monetdb = new Vendor(new VendorYaml("monetdb.yml", injectionModel));
this.mysql = new Vendor(new VendorYaml("mysql.yml", injectionModel));
this.neo4j = new Vendor(new VendorYaml("neo4j.yml", injectionModel));
this.oracle = new Vendor(new VendorYaml("oracle.yml", injectionModel));
this.postgresql = new Vendor(new VendorYaml("postgresql.yml", injectionModel));
this.sqlite = new Vendor(new VendorYaml("sqlite.yml", injectionModel)) {
@Override
public String transformSqlite(String resultToParse) {
var resultSqlite = new StringBuilder();
String resultTmp = resultToParse
.replaceFirst("[^(]+\\(", StringUtils.EMPTY)
.trim()
.replaceAll("\\)$", StringUtils.EMPTY);
resultTmp = resultTmp.replaceAll("\\([^)]+\\)", StringUtils.EMPTY);
for (String columnNameAndType: resultTmp.split(",")) {
if (columnNameAndType.trim().startsWith("primary key")) {
continue;
}
// Some recent SQLite use tabulation character as a separator => split() by any white space \s
String columnName = columnNameAndType.trim().split("\\s")[0];
// Some recent SQLite enclose names with ` => strip those `
columnName = StringUtils.strip(columnName, "`");
if (
!"CONSTRAINT".equals(columnName)
&& !"UNIQUE".equals(columnName)
) {
// Generate pattern \4\5\4\6 for injection parsing
resultSqlite.append((char) 4).append(columnName).append((char) 5).append("0").append((char) 4).append((char) 6);
}
}
return resultSqlite.toString();
}
};
this.sqlserver = new Vendor(new VendorYaml("sqlserver.yml", injectionModel));
this.sybase = new Vendor(new VendorYaml("sybase.yml", injectionModel));
this.vertica = new Vendor(new VendorYaml("vertica.yml", injectionModel));
this.vendors = Arrays.asList(
this.auto,
access,
altibase,
ctreeace,
this.cubrid,
this.db2,
this.derby,
exasol,
this.firebird,
frontbase,
this.h2,
hana,
this.hsqldb,
this.informix,
ingres,
iris,
maxdb,
this.mckoi,
this.mimer,
this.monetdb,
this.mysql,
this.neo4j,
netezza,
nuodb,
this.oracle,
this.postgresql,
presto,
this.sqlite,
this.sqlserver,
this.sybase,
teradata,
this.vertica
);
this.setVendor(this.mysql);
this.vendorByUser = this.auto;
}
public boolean isSqlite() {
return this.getVendor() == this.getSqlite();
}
public Vendor fingerprintVendor() {
Vendor vendorFound = null;
if (this.injectionModel.getMediatorVendor().getVendorByUser() != this.injectionModel.getMediatorVendor().getAuto()) {
vendorFound = this.injectionModel.getMediatorVendor().getVendorByUser();
LOGGER.log(
LogLevelUtil.CONSOLE_INFORM,
MediatorVendor.LOG_VENDOR,
() -> I18nUtil.valueByKey("LOG_DATABASE_TYPE_FORCED_BY_USER"),
() -> this.injectionModel.getMediatorVendor().getVendorByUser()
);
} else {
LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "Fingerprinting database...");
var insertionCharacter = URLEncoder.encode("'\"#-)'\"*", StandardCharsets.UTF_8);
String pageSource = this.injectionModel.injectWithoutIndex(insertionCharacter, "test#vendor");
var mediatorVendor = this.injectionModel.getMediatorVendor();
Vendor[] vendorsWithoutAuto = mediatorVendor.getVendors()
.stream()
.filter(v -> v != mediatorVendor.getAuto())
.toArray(Vendor[]::new);
// Test each vendor
for (Vendor vendorTest: vendorsWithoutAuto) {
if (pageSource.matches(vendorTest.instance().fingerprintErrorsAsRegex())) {
vendorFound = vendorTest;
LOGGER.log(
LogLevelUtil.CONSOLE_SUCCESS,
MediatorVendor.LOG_VENDOR,
() -> "Basic fingerprint matching vendor",
() -> vendorTest
);
break;
}
}
vendorFound = this.initializeVendor(vendorFound);
}
this.injectionModel.appendAnalysisReport(
"<span style=color:rgb(0,0,255)># Date: " + LocalDate.now().format(DateTimeFormatter.ISO_LOCAL_DATE)
+ "<br># Tested on: " + String.format("%s (v%s)", SystemUtils.OS_NAME, SystemUtils.OS_VERSION)
+ "<br># Tool: jSQL Injection v" + this.injectionModel.getVersionJsql()
+ " (<a href="+this.injectionModel.getMediatorUtils().getPropertiesUtil().getProperties().get("github.url")+">"
+ this.injectionModel.getMediatorUtils().getPropertiesUtil().getProperties().get("github.url")
+ "</a>)"
+ "<br># Database: " + vendorFound
+ "<br><br>## Vulnerability summary</span>",
true
);
var requestSetVendor = new Request();
requestSetVendor.setMessage(Interaction.SET_VENDOR);
Map<Header, Object> msgHeader = new EnumMap<>(Header.class);
msgHeader.put(Header.URL, this.injectionModel.getMediatorUtils().getConnectionUtil().getUrlByUser());
msgHeader.put(Header.VENDOR, vendorFound);
requestSetVendor.setParameters(msgHeader);
this.injectionModel.sendToViews(requestSetVendor);
return vendorFound;
}
public Vendor initializeVendor(Vendor vendor) {
var vendorFixed = vendor;
if (vendorFixed == null) {
vendorFixed = this.injectionModel.getMediatorVendor().getMysql();
LOGGER.log(
LogLevelUtil.CONSOLE_INFORM,
MediatorVendor.LOG_VENDOR,
() -> I18nUtil.valueByKey("LOG_DATABASE_TYPE_NOT_FOUND"),
() -> this.injectionModel.getMediatorVendor().getMysql()
);
} else {
LOGGER.log(
LogLevelUtil.CONSOLE_INFORM,
MediatorVendor.LOG_VENDOR,
() -> I18nUtil.valueByKey("LOG_USING_DATABASE_TYPE"),
() -> vendor
);
Map<Header, Object> msgHeader = new EnumMap<>(Header.class);
msgHeader.put(
Header.URL,
this.injectionModel.getMediatorUtils().getConnectionUtil().getUrlByUser()
);
msgHeader.put(Header.VENDOR, vendorFixed);
var requestDatabaseIdentified = new Request();
requestDatabaseIdentified.setMessage(Interaction.DATABASE_IDENTIFIED);
requestDatabaseIdentified.setParameters(msgHeader);
this.injectionModel.sendToViews(requestDatabaseIdentified);
}
return vendorFixed;
}
// Getter and setter
public Vendor getAuto() {
return this.auto;
}
public Vendor getCubrid() {
return this.cubrid;
}
public Vendor getH2() {
return this.h2;
}
public Vendor getPostgresql() {
return this.postgresql;
}
public Vendor getMysql() {
return this.mysql;
}
public Vendor getSqlite() {
return this.sqlite;
}
public Vendor getSqlserver() {
return this.sqlserver;
}
public Vendor getNeo4j() {
return this.neo4j;
}
public Vendor getVendor() {
return this.vendor;
}
public void setVendor(Vendor vendor) {
this.vendor = vendor;
}
public Vendor getVendorByUser() {
return this.vendorByUser;
}
public void setVendorByUser(Vendor vendorByUser) {
this.vendorByUser = vendorByUser;
}
public List<Vendor> getVendors() {
return this.vendors;
}
public Vendor getDb2() {
return this.db2;
}
public Vendor getHsqldb() {
return this.hsqldb;
}
public Vendor getDerby() {
return this.derby;
}
public Vendor getOracle() {
return this.oracle;
}
public Vendor getFirebird() {
return firebird;
}
public Vendor getMonetdb() {
return monetdb;
}
public Vendor getMimer() {
return mimer;
}
public Vendor getMckoi() {
return mckoi;
}
public Vendor getInformix() {
return informix;
}
public Vendor getSybase() {
return sybase;
}
public Vendor getVertica() {
return vertica;
}
}