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