1 package com.jsql.model.injection.engine;
2
3 import com.jsql.model.InjectionModel;
4 import com.jsql.view.subscriber.Seal;
5 import com.jsql.model.injection.engine.model.Engine;
6 import com.jsql.model.injection.engine.model.EngineYaml;
7 import com.jsql.util.I18nUtil;
8 import com.jsql.util.LogLevelUtil;
9 import com.jsql.util.StringUtil;
10 import org.apache.commons.lang3.StringUtils;
11 import org.apache.commons.lang3.SystemUtils;
12 import org.apache.logging.log4j.LogManager;
13 import org.apache.logging.log4j.Logger;
14
15 import java.net.URLEncoder;
16 import java.nio.charset.StandardCharsets;
17 import java.time.Clock;
18 import java.time.LocalDate;
19 import java.time.format.DateTimeFormatter;
20 import java.util.Arrays;
21 import java.util.List;
22
23 public class MediatorEngine {
24
25 private static final Logger LOGGER = LogManager.getRootLogger();
26
27 private static final String LOG_ENGINE = "{} [{}]";
28
29
30
31
32
33 private Engine engine;
34
35
36
37
38
39 private Engine engineByUser;
40
41
42 private final Engine auto;
43 private final Engine access;
44 private final Engine altibase;
45 private final Engine clickhouse;
46 private final Engine cockroachdb;
47 private final Engine cubrid;
48 private final Engine dameng;
49 private final Engine db2;
50 private final Engine derby;
51 private final Engine duckdb;
52 private final Engine exasol;
53 private final Engine firebird;
54 private final Engine greenplum;
55 private final Engine h2;
56 private final Engine hana;
57 private final Engine hsqldb;
58 private final Engine informix;
59 private final Engine mariadb;
60 private final Engine mckoi;
61 private final Engine mimer;
62 private final Engine monetdb;
63 private final Engine mysql;
64 private final Engine neo4j;
65 private final Engine oracle;
66 private final Engine postgres;
67 private final Engine presto;
68 private final Engine spanner;
69 private final Engine sqlite;
70 private final Engine sqlserver;
71 private final Engine sybase;
72 private final Engine vertica;
73 private final Engine virtuoso;
74
75 private final List<Engine> engines;
76 private final List<Engine> enginesForFingerprint;
77
78 private final InjectionModel injectionModel;
79
80 public MediatorEngine(InjectionModel injectionModel) {
81 this.injectionModel = injectionModel;
82
83 Engine ctreeace = new Engine(new EngineYaml("ctreeace.yml", injectionModel));
84 Engine frontbase = new Engine(new EngineYaml("frontbase.yml", injectionModel));
85 Engine ingres = new Engine(new EngineYaml("ingres.yml", injectionModel));
86 Engine iris = new Engine(new EngineYaml("iris.yml", injectionModel));
87 Engine maxdb = new Engine(new EngineYaml("maxdb.yml", injectionModel));
88 Engine netezza = new Engine(new EngineYaml("netezza.yml", injectionModel));
89 Engine nuodb = new Engine(new EngineYaml("nuodb.yml", injectionModel));
90 Engine teradata = new Engine(new EngineYaml("teradata.yml", injectionModel));
91
92 this.auto = new Engine();
93 this.access = new Engine(new EngineYaml("access.yml", injectionModel));
94 this.altibase = new Engine(new EngineYaml("altibase.yml", injectionModel));
95 this.cubrid = new Engine(new EngineYaml("cubrid.yml", injectionModel));
96 this.clickhouse = new Engine(new EngineYaml("clickhouse.yml", injectionModel));
97 this.cockroachdb = new Engine(new EngineYaml("cockroachdb.yml", injectionModel));
98 this.dameng = new Engine(new EngineYaml("dameng.yml", injectionModel));
99 this.db2 = new Engine(new EngineYaml("db2.yml", injectionModel));
100 this.derby = new Engine(new EngineYaml("derby.yml", injectionModel));
101 this.duckdb = new Engine(new EngineYaml("duckdb.yml", injectionModel));
102 this.exasol = new Engine(new EngineYaml("exasol.yml", injectionModel));
103 this.firebird = new Engine(new EngineYaml("firebird.yml", injectionModel));
104 this.greenplum = new Engine(new EngineYaml("greenplum.yml", injectionModel));
105 this.h2 = new Engine(new EngineYaml("h2.yml", injectionModel));
106 this.hana = new Engine(new EngineYaml("hana.yml", injectionModel));
107 this.hsqldb = new Engine(new EngineYaml("hsqldb.yml", injectionModel));
108 this.informix = new Engine(new EngineYaml("informix.yml", injectionModel));
109 this.mariadb = new Engine(new EngineYaml("mariadb.yml", injectionModel));
110 this.mckoi = new Engine(new EngineYaml("mckoi.yml", injectionModel));
111 this.mimer = new Engine(new EngineYaml("mimersql.yml", injectionModel));
112 this.monetdb = new Engine(new EngineYaml("monetdb.yml", injectionModel));
113 this.mysql = new Engine(new EngineYaml("mysql.yml", injectionModel));
114 this.neo4j = new Engine(new EngineYaml("neo4j.yml", injectionModel));
115 this.oracle = new Engine(new EngineYaml("oracle.yml", injectionModel));
116 this.postgres = new Engine(new EngineYaml("postgres.yml", injectionModel));
117 this.presto = new Engine(new EngineYaml("presto.yml", injectionModel));
118 this.spanner = new Engine(new EngineYaml("spanner.yml", injectionModel));
119 this.sqlite = new Engine(new EngineYaml("sqlite.yml", injectionModel)) {
120 @Override
121 public String transform(String resultToParse) {
122 var resultSqlite = new StringBuilder();
123
124 String resultTmp = resultToParse
125 .replaceFirst("[^(]+\\(", StringUtils.EMPTY)
126 .trim()
127 .replaceAll("\\)$", StringUtils.EMPTY)
128 .replaceAll("\\([^)]+\\)", StringUtils.EMPTY);
129
130 for (String columnNameAndType: resultTmp.split(",")) {
131 if (columnNameAndType.trim().startsWith("primary key")) {
132 continue;
133 }
134
135 String columnName = columnNameAndType.trim().split("\\s")[0];
136
137 columnName = StringUtils.strip(columnName, "`");
138 if (
139 !"CONSTRAINT".equals(columnName)
140 && !"UNIQUE".equals(columnName)
141 ) {
142
143 resultSqlite.append((char) 4).append(columnName).append((char) 5).append("0").append((char) 4).append((char) 6);
144 }
145 }
146 return resultSqlite.toString();
147 }
148 };
149 this.sqlserver = new Engine(new EngineYaml("sqlserver.yml", injectionModel));
150 this.sybase = new Engine(new EngineYaml("sybase.yml", injectionModel));
151 this.vertica = new Engine(new EngineYaml("vertica.yml", injectionModel));
152 this.virtuoso = new Engine(new EngineYaml("virtuoso.yml", injectionModel));
153
154 this.engines = Arrays.asList(
155 this.auto, this.access, this.altibase, ctreeace, this.clickhouse, this.cockroachdb, this.cubrid, this.dameng, this.db2, this.derby, this.duckdb,
156 this.exasol, this.firebird, frontbase, this.greenplum, this.h2, this.hana, this.hsqldb, this.informix, ingres, iris, maxdb, this.mariadb, this.mckoi,
157 this.mimer, this.monetdb, this.mysql, this.neo4j, netezza, nuodb, this.oracle, this.postgres, this.presto, this.spanner, this.sqlite, this.sqlserver,
158 this.sybase, teradata, this.vertica, this.virtuoso
159 );
160 this.enginesForFingerprint = Arrays.asList(
161 this.mysql, this.postgres, this.sqlite, this.h2, this.hsqldb, this.oracle, this.sqlserver, this.mariadb, this.spanner, this.duckdb,
162 this.altibase, ctreeace, this.cubrid, this.db2, this.derby, this.exasol, this.firebird, frontbase, this.hana, this.informix, ingres,
163 iris, maxdb, this.mckoi, this.mimer, this.monetdb, this.neo4j, netezza, nuodb, this.presto, this.sybase, teradata, this.vertica,
164 this.virtuoso, this.clickhouse, this.access, this.dameng, this.cockroachdb, this.greenplum
165 );
166
167 this.engine = this.mysql;
168 this.engineByUser = this.auto;
169 }
170
171 public Engine fingerprintEngine() {
172 Engine engineFound = null;
173 if (this.injectionModel.getMediatorEngine().getEngineByUser() != this.injectionModel.getMediatorEngine().getAuto()) {
174 engineFound = this.injectionModel.getMediatorEngine().getEngineByUser();
175 LOGGER.log(
176 LogLevelUtil.CONSOLE_INFORM,
177 MediatorEngine.LOG_ENGINE,
178 () -> I18nUtil.valueByKey("LOG_DATABASE_TYPE_FORCED_BY_USER"),
179 () -> this.injectionModel.getMediatorEngine().getEngineByUser()
180 );
181 } else {
182 LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "[Step 1] Fingerprinting database using raw fingerprinting...");
183 var insertionCharacter = URLEncoder.encode("'\"#-)'\"*", StandardCharsets.UTF_8);
184 String pageSource = this.injectionModel.injectWithoutIndex(insertionCharacter, "test#engine");
185
186 var mediatorEngine = this.injectionModel.getMediatorEngine();
187 Engine[] enginesWithoutAuto = mediatorEngine.getEngines()
188 .stream()
189 .filter(v -> v != mediatorEngine.getAuto())
190 .toArray(Engine[]::new);
191
192
193 for (Engine engineTest : enginesWithoutAuto) {
194 if (pageSource.matches(engineTest.instance().fingerprintErrorsAsRegex())) {
195 engineFound = engineTest;
196 LOGGER.log(
197 LogLevelUtil.CONSOLE_SUCCESS,
198 "Found database [{}] using raw fingerprinting",
199 () -> engineTest
200 );
201 break;
202 }
203 }
204 if (engineFound == null) {
205 engineFound = this.injectionModel.getMediatorEngine().getMysql();
206 LOGGER.log(
207 LogLevelUtil.CONSOLE_INFORM,
208 MediatorEngine.LOG_ENGINE,
209 () -> I18nUtil.valueByKey("LOG_DATABASE_TYPE_NOT_FOUND"),
210 () -> this.injectionModel.getMediatorEngine().getMysql()
211 );
212 }
213 }
214
215 var urlGitHub = this.injectionModel.getMediatorUtils().propertiesUtil().getProperty("github.url");
216 this.injectionModel.appendAnalysisReport(
217 String.join(
218 StringUtils.EMPTY,
219 "# Date: ", LocalDate.now(Clock.systemUTC()).format(DateTimeFormatter.ISO_LOCAL_DATE),
220 "<br> # Tested on: ", SystemUtils.OS_NAME, " (", SystemUtils.OS_VERSION, ")",
221 "<br> # Tool: ", StringUtil.APP_NAME, " v", this.injectionModel.getPropertiesUtil().getVersionJsql(),
222 " (<a href=", urlGitHub, ">", urlGitHub, "</a>)",
223 "<br> # Database: ", engineFound.toString(),
224 "<br> <br> ## Vulnerability summary</span>"
225 ),
226 true
227 );
228
229 this.injectionModel.sendToViews(new Seal.ActivateEngine(engineFound));
230 return engineFound;
231 }
232
233
234
235
236 public Engine getEngine() {
237 return this.engine;
238 }
239
240 public void setEngine(Engine engine) {
241 this.engine = engine;
242 }
243
244 public Engine getEngineByUser() {
245 return this.engineByUser;
246 }
247
248 public void setEngineByUser(Engine engineByUser) {
249 this.engineByUser = engineByUser;
250 }
251
252 public List<Engine> getEngines() {
253 return this.engines;
254 }
255
256 public List<Engine> getEnginesForFingerprint() {
257 return this.enginesForFingerprint;
258 }
259
260
261
262
263 public Engine getAuto() {
264 return this.auto;
265 }
266
267 public Engine getAccess() {
268 return this.access;
269 }
270
271 public Engine getAltibase() {
272 return this.altibase;
273 }
274
275 public Engine getClickhouse() {
276 return this.clickhouse;
277 }
278
279 public Engine getCockroachdb() {
280 return this.cockroachdb;
281 }
282
283 public Engine getCubrid() {
284 return this.cubrid;
285 }
286
287 public Engine getDameng() {
288 return this.dameng;
289 }
290
291 public Engine getDb2() {
292 return this.db2;
293 }
294
295 public Engine getDerby() {
296 return this.derby;
297 }
298
299 public Engine getDuckdb() {
300 return this.duckdb;
301 }
302
303 public Engine getExasol() {
304 return this.exasol;
305 }
306
307 public Engine getFirebird() {
308 return this.firebird;
309 }
310
311 public Engine getGreenplum() {
312 return this.greenplum;
313 }
314
315 public Engine getH2() {
316 return this.h2;
317 }
318
319 public Engine getHana() {
320 return this.hana;
321 }
322
323 public Engine getHsqldb() {
324 return this.hsqldb;
325 }
326
327 public Engine getInformix() {
328 return this.informix;
329 }
330
331 public Engine getMariadb() {
332 return this.mariadb;
333 }
334
335 public Engine getMckoi() {
336 return this.mckoi;
337 }
338
339 public Engine getMimer() {
340 return this.mimer;
341 }
342
343 public Engine getMonetdb() {
344 return this.monetdb;
345 }
346
347 public Engine getMysql() {
348 return this.mysql;
349 }
350
351 public Engine getNeo4j() {
352 return this.neo4j;
353 }
354
355 public Engine getOracle() {
356 return this.oracle;
357 }
358
359 public Engine getPostgres() {
360 return this.postgres;
361 }
362
363 public Engine getPresto() {
364 return this.presto;
365 }
366
367 public Engine getSpanner() {
368 return this.spanner;
369 }
370
371 public Engine getSqlite() {
372 return this.sqlite;
373 }
374
375 public Engine getSqlserver() {
376 return this.sqlserver;
377 }
378
379 public Engine getSybase() {
380 return this.sybase;
381 }
382
383 public Engine getVertica() {
384 return this.vertica;
385 }
386
387 public Engine getVirtuoso() {
388 return this.virtuoso;
389 }
390 }