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