1
2
3
4
5
6
7
8
9
10
11 package com.jsql.model;
12
13 import com.jsql.model.accessible.DataAccess;
14 import com.jsql.model.accessible.ResourceAccess;
15 import com.jsql.view.subscriber.Seal;
16 import com.jsql.model.exception.JSqlException;
17 import com.jsql.model.exception.JSqlRuntimeException;
18 import com.jsql.model.injection.method.AbstractMethodInjection;
19 import com.jsql.model.injection.method.MediatorMethod;
20 import com.jsql.model.injection.strategy.MediatorStrategy;
21 import com.jsql.model.injection.strategy.blind.callable.AbstractCallableBit;
22 import com.jsql.model.injection.engine.MediatorEngine;
23 import com.jsql.model.injection.engine.model.EngineYaml;
24 import com.jsql.util.*;
25 import com.jsql.util.GitUtil.ShowOnConsole;
26 import org.apache.commons.lang3.StringUtils;
27 import org.apache.logging.log4j.LogManager;
28 import org.apache.logging.log4j.Logger;
29
30 import javax.swing.*;
31 import java.awt.*;
32 import java.io.IOException;
33 import java.io.Serializable;
34 import java.net.*;
35 import java.net.http.HttpRequest;
36 import java.net.http.HttpRequest.BodyPublishers;
37 import java.net.http.HttpRequest.Builder;
38 import java.net.http.HttpResponse;
39 import java.net.http.HttpResponse.BodyHandlers;
40 import java.nio.charset.StandardCharsets;
41 import java.text.DecimalFormat;
42 import java.time.Duration;
43 import java.util.AbstractMap.SimpleEntry;
44 import java.util.Map;
45 import java.util.regex.Matcher;
46 import java.util.stream.Collectors;
47 import java.util.stream.Stream;
48
49
50
51
52
53
54
55
56
57 public class InjectionModel extends AbstractModelObservable implements Serializable {
58
59 private static final Logger LOGGER = LogManager.getRootLogger();
60
61 private final transient MediatorEngine mediatorEngine = new MediatorEngine(this);
62 private final transient MediatorMethod mediatorMethod = new MediatorMethod(this);
63 private final transient DataAccess dataAccess = new DataAccess(this);
64 private final transient ResourceAccess resourceAccess = new ResourceAccess(this);
65 private final transient PropertiesUtil propertiesUtil = new PropertiesUtil();
66 private final transient MediatorUtils mediatorUtils;
67 private final transient MediatorStrategy mediatorStrategy;
68
69 public static final String STAR = "*";
70 public static final String BR = "<br> ";
71
72
73
74
75 private String analysisReport = StringUtils.EMPTY;
76
77
78
79
80
81 private boolean shouldErasePreviousInjection = false;
82 private boolean isScanning = false;
83
84 public InjectionModel() {
85 this.mediatorStrategy = new MediatorStrategy(this);
86 this.mediatorUtils = new MediatorUtils(
87 this.propertiesUtil,
88 new ConnectionUtil(this),
89 new AuthenticationUtil(),
90 new GitUtil(this),
91 new HeaderUtil(this),
92 new ParameterUtil(this),
93 new ExceptionUtil(this),
94 new SoapUtil(this),
95 new MultipartUtil(this),
96 new CookiesUtil(this),
97 new JsonUtil(this),
98 new PreferencesUtil(),
99 new ProxyUtil(),
100 new ThreadUtil(this),
101 new TamperingUtil(),
102 new UserAgentUtil(),
103 new CsrfUtil(this),
104 new DigestUtil(this),
105 new FormUtil(this),
106 new CertificateUtil()
107 );
108 }
109
110
111
112
113 public void resetModel() {
114 this.mediatorStrategy.getTime().setApplicable(false);
115 this.mediatorStrategy.getBlindBin().setApplicable(false);
116 this.mediatorStrategy.getBlindBit().setApplicable(false);
117 this.mediatorStrategy.getMultibit().setApplicable(false);
118 this.mediatorStrategy.getDns().setApplicable(false);
119 this.mediatorStrategy.getError().setApplicable(false);
120 this.mediatorStrategy.getStack().setApplicable(false);
121 this.mediatorStrategy.getUnion().setApplicable(false);
122 this.mediatorStrategy.setStrategy(null);
123
124 this.mediatorStrategy.getSpecificUnion().setVisibleIndex(null);
125 this.mediatorStrategy.getSpecificUnion().setIndexesInUrl(StringUtils.EMPTY);
126
127 this.analysisReport = StringUtils.EMPTY;
128 this.isStoppedByUser = false;
129 this.shouldErasePreviousInjection = false;
130
131 this.mediatorUtils.csrfUtil().setTokenCsrf(null);
132 this.mediatorUtils.digestUtil().setTokenDigest(null);
133 this.mediatorUtils.threadUtil().reset();
134 }
135
136
137
138
139
140
141 public void beginInjection() {
142 this.resetModel();
143 try {
144 if (this.mediatorUtils.proxyUtil().isNotLive(ShowOnConsole.YES)) {
145 return;
146 }
147 LOGGER.log(
148 LogLevelUtil.CONSOLE_INFORM,
149 "{}: {}",
150 () -> I18nUtil.valueByKey("LOG_START_INJECTION"),
151 () -> this.mediatorUtils.connectionUtil().getUrlByUser()
152 );
153
154
155 this.mediatorUtils.parameterUtil().checkParametersFormat();
156 this.mediatorUtils.connectionUtil().testConnection();
157
158
159 boolean hasFoundInjection = this.mediatorMethod.getQuery().testParameters(false);
160 hasFoundInjection = this.mediatorUtils.multipartUtil().testParameters(hasFoundInjection);
161 hasFoundInjection = this.mediatorUtils.soapUtil().testParameters(hasFoundInjection);
162 hasFoundInjection = this.mediatorMethod.getRequest().testParameters(hasFoundInjection);
163 hasFoundInjection = this.mediatorMethod.getHeader().testParameters(hasFoundInjection);
164 hasFoundInjection = this.mediatorUtils.cookiesUtil().testParameters(hasFoundInjection);
165
166 if (hasFoundInjection && !this.isScanning) {
167 if (!this.getMediatorUtils().preferencesUtil().isNotShowingVulnReport()) {
168 this.sendToViews(new Seal.CreateAnalysisReport(this.analysisReport));
169 }
170 if (this.getMediatorUtils().preferencesUtil().isZipStrategy()) {
171 LOGGER.log(LogLevelUtil.CONSOLE_INFORM, "Using Zip mode for reduced query size");
172 } else if (this.getMediatorUtils().preferencesUtil().isDiosStrategy()) {
173 LOGGER.log(LogLevelUtil.CONSOLE_INFORM, "Using Dump In One Shot strategy for single query dump");
174 }
175 if (!this.mediatorUtils.preferencesUtil().isNotInjectingMetadata()) {
176 this.dataAccess.getDatabaseInfos();
177 }
178 this.dataAccess.listDatabases();
179 }
180
181 LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, () -> I18nUtil.valueByKey("LOG_DONE"));
182 this.shouldErasePreviousInjection = true;
183 } catch (InterruptedException e) {
184 LOGGER.log(LogLevelUtil.IGNORE, e, e);
185 Thread.currentThread().interrupt();
186 } catch (JSqlRuntimeException | JSqlException | IOException e) {
187 LOGGER.log(
188 LogLevelUtil.CONSOLE_ERROR,
189 "Interruption: {}",
190 e.getMessage() == null ? InjectionModel.getImplicitReason(e) : e.getMessage()
191 );
192 } finally {
193 this.sendToViews(new Seal.EndPreparation());
194 }
195 }
196
197 public static String getImplicitReason(Throwable e) {
198 String message = e.getClass().getSimpleName();
199 if (e.getMessage() != null) {
200 message += ": "+ e.getMessage();
201 }
202 if (e.getCause() != null && !e.equals(e.getCause())) {
203 message += " > "+ InjectionModel.getImplicitReason(e.getCause());
204 }
205 return message;
206 }
207
208
209
210
211
212
213 @Override
214 public String inject(
215 String dataInjection,
216 boolean isUsingIndex,
217 String metadataInjectionProcess,
218 AbstractCallableBit<?> callableBoolean,
219 boolean isReport
220 ) {
221
222 String urlInjection = this.mediatorUtils.connectionUtil().getUrlBase();
223 urlInjection = this.mediatorStrategy.buildPath(urlInjection, isUsingIndex, dataInjection);
224 urlInjection = StringUtil.cleanSql(urlInjection.trim());
225
226 URL urlObject;
227 String urlInjectionFixed;
228 try {
229 urlInjectionFixed = this.initQueryString(
230 isUsingIndex,
231 urlInjection,
232 dataInjection
233 );
234 urlObject = new URI(urlInjectionFixed).toURL();
235 } catch (MalformedURLException | URISyntaxException e) {
236 LOGGER.log(LogLevelUtil.CONSOLE_ERROR, String.format("Incorrect Query Url: %s", e.getMessage()));
237 return StringUtils.EMPTY;
238 }
239
240 String pageSource = StringUtils.EMPTY;
241
242
243 try {
244 var httpRequestBuilder = HttpRequest.newBuilder()
245 .uri(URI.create(urlObject.toString()))
246 .setHeader(HeaderUtil.CONTENT_TYPE_REQUEST, "text/plain")
247 .timeout(Duration.ofSeconds(15));
248
249 this.mediatorUtils.csrfUtil().addHeaderToken(httpRequestBuilder);
250 this.mediatorUtils.digestUtil().addHeaderToken(httpRequestBuilder);
251 this.mediatorUtils.connectionUtil().setCustomUserAgent(httpRequestBuilder);
252
253 String body = this.initRequest(isUsingIndex, dataInjection, httpRequestBuilder);
254 this.initHeader(isUsingIndex, dataInjection, httpRequestBuilder);
255
256 var httpRequest = httpRequestBuilder.build();
257 if (isReport) {
258 Color colorReport = UIManager.getColor("TextArea.inactiveForeground");
259 String report = InjectionModel.BR + StringUtil.formatReport(colorReport, "Method: ") + httpRequest.method();
260 report += InjectionModel.BR + StringUtil.formatReport(colorReport, "Path: ") + httpRequest.uri().getPath();
261 if (httpRequest.uri().getQuery() != null) {
262 report += InjectionModel.BR + StringUtil.formatReport(colorReport, "Query: ") + httpRequest.uri().getQuery();
263 }
264 if (
265 !(this.mediatorUtils.parameterUtil().getListRequest().isEmpty()
266 && this.mediatorUtils.csrfUtil().getTokenCsrf() == null)
267 ) {
268 report += InjectionModel.BR + StringUtil.formatReport(colorReport, "Body: ") + body;
269 }
270 report += InjectionModel.BR
271 + StringUtil.formatReport(colorReport, "Header: ")
272 + httpRequest.headers().map().entrySet().stream()
273 .map(entry ->
274 String.format("%s: %s", entry.getKey(),
275 String.join(StringUtils.EMPTY, entry.getValue()))
276 )
277 .collect(Collectors.joining(InjectionModel.BR));
278 return report;
279 }
280
281 HttpResponse<String> response = this.getMediatorUtils().connectionUtil().getHttpClient().build().send(
282 httpRequestBuilder.build(),
283 BodyHandlers.ofString()
284 );
285 if (this.mediatorUtils.parameterUtil().isRequestSoap()) {
286
287 pageSource = URLDecoder.decode(response.body(), StandardCharsets.UTF_8);
288 pageSource = StringUtil.fromHtml(pageSource);
289 } else {
290 pageSource = response.body();
291 }
292
293 Map<String, String> headersResponse = ConnectionUtil.getHeadersMap(response);
294 int sizeHeaders = headersResponse.keySet()
295 .stream()
296 .map(key -> headersResponse.get(key).length() + key.length())
297 .mapToInt(Integer::intValue)
298 .sum();
299 float size = (float) (pageSource.length() + sizeHeaders) / 1024;
300 var decimalFormat = new DecimalFormat("0.000");
301
302 String pageSourceFixed = pageSource
303 .replaceAll("("+ EngineYaml.CALIBRATOR_SQL +"){60,}", "$1...")
304 .replaceAll("(jIyM){60,}", "$1...");
305
306
307 this.sendToViews(new Seal.MessageHeader(
308 urlInjectionFixed,
309 body,
310 ConnectionUtil.getHeadersMap(httpRequest.headers()),
311 headersResponse,
312 pageSourceFixed,
313 decimalFormat.format(size),
314 this.mediatorStrategy.getMeta(),
315 metadataInjectionProcess,
316 callableBoolean
317 ));
318 } catch (IOException e) {
319 LOGGER.log(
320 LogLevelUtil.CONSOLE_ERROR,
321 String.format("Error during connection: %s", e.getMessage())
322 );
323 } catch (InterruptedException e) {
324 LOGGER.log(LogLevelUtil.IGNORE, e, e);
325 Thread.currentThread().interrupt();
326 }
327
328 return pageSource;
329 }
330
331 private String initQueryString(boolean isUsingIndex, String urlInjection, String dataInjection) {
332 String urlInjectionFixed = urlInjection;
333 if (
334 this.mediatorUtils.parameterUtil().getListQueryString().isEmpty()
335 && !this.mediatorUtils.preferencesUtil().isProcessingCsrf()
336 ) {
337 return urlInjectionFixed;
338 }
339
340
341
342 if (!urlInjectionFixed.contains("?")) {
343 urlInjectionFixed += "?";
344 }
345 urlInjectionFixed += this.buildQuery(
346 this.mediatorMethod.getQuery(),
347 this.mediatorUtils.parameterUtil().getQueryStringFromEntries(),
348 isUsingIndex,
349 dataInjection
350 );
351 return this.mediatorUtils.csrfUtil().addQueryStringToken(urlInjectionFixed);
352 }
353
354 private void initHeader(boolean isUsingIndex, String dataInjection, Builder httpRequest) {
355 if (!this.mediatorUtils.parameterUtil().getListHeader().isEmpty()) {
356 Stream.of(
357 this.buildQuery(
358 this.mediatorMethod.getHeader(),
359 this.mediatorUtils.parameterUtil().getHeaderFromEntries(),
360 isUsingIndex,
361 dataInjection
362 )
363 .split("\\\\r\\\\n")
364 )
365 .forEach(header -> {
366 if (header.split(":").length == 2) {
367 try {
368 HeaderUtil.sanitizeHeaders(
369 httpRequest,
370 new SimpleEntry<>(
371 header.split(":")[0],
372 header.split(":")[1]
373 )
374 );
375 } catch (JSqlException e) {
376 LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Headers sanitizing issue caught already during connection, ignoring", e);
377 }
378 }
379 });
380 }
381 }
382
383 private String initRequest(boolean isUsingIndex, String dataInjection, Builder httpRequest) {
384 if (
385 this.mediatorUtils.parameterUtil().getListRequest().isEmpty()
386 && this.mediatorUtils.csrfUtil().getTokenCsrf() == null
387 ) {
388 return dataInjection;
389 }
390
391
392
393
394 if (this.mediatorUtils.parameterUtil().isRequestSoap()) {
395 httpRequest.setHeader(HeaderUtil.CONTENT_TYPE_REQUEST, "text/xml");
396 } else {
397 httpRequest.setHeader(HeaderUtil.CONTENT_TYPE_REQUEST, "application/x-www-form-urlencoded");
398 }
399
400 var body = new StringBuilder();
401 this.mediatorUtils.csrfUtil().addRequestToken(body);
402
403 if (this.mediatorUtils.connectionUtil().getTypeRequest().matches("PUT|POST")) {
404 if (this.mediatorUtils.parameterUtil().isRequestSoap()) {
405 body.append(
406 this.buildQuery(
407 this.mediatorMethod.getRequest(),
408 this.mediatorUtils.parameterUtil().getRawRequest(),
409 isUsingIndex,
410 dataInjection
411 )
412
413
414 .replace("\u0001", "")
415 .replace("\u0003", "")
416 .replace("\u0004", "")
417 .replace("\u0005", "")
418 .replace("\u0006", "")
419 .replace("\u0007", "")
420 .replace("+", "%2B")
421 );
422 } else {
423 body.append(
424 this.buildQuery(
425 this.mediatorMethod.getRequest(),
426 this.mediatorUtils.parameterUtil().getRequestFromEntries(),
427 isUsingIndex,
428 dataInjection
429 )
430 );
431 }
432 }
433
434 var bodyPublisher = BodyPublishers.ofString(body.toString());
435 httpRequest.method(
436 this.mediatorUtils.connectionUtil().getTypeRequest(),
437 bodyPublisher
438 );
439 return body.toString();
440 }
441
442 private String buildQuery(AbstractMethodInjection methodInjection, String paramLead, boolean isUsingIndex, String sqlTrail) {
443 String query;
444 String paramLeadFixed = paramLead.replace(
445 InjectionModel.STAR,
446 TamperingUtil.TAG_OPENED + InjectionModel.STAR + TamperingUtil.TAG_CLOSED
447 );
448 if (
449
450 this.mediatorUtils.connectionUtil().getMethodInjection() != methodInjection
451
452 || this.mediatorUtils.connectionUtil().getUrlBase().contains(InjectionModel.STAR)
453 ) {
454 query = paramLeadFixed;
455 } else if (
456
457
458
459 paramLeadFixed.contains(InjectionModel.STAR)
460 ) {
461 query = this.initStarInjection(paramLeadFixed, isUsingIndex, sqlTrail);
462 } else {
463 query = this.initRawInjection(paramLeadFixed, isUsingIndex, sqlTrail);
464 }
465 query = this.cleanQuery(methodInjection, query);
466
467 if (this.mediatorUtils.connectionUtil().getMethodInjection() == methodInjection) {
468 query = this.mediatorUtils.tamperingUtil().tamper(query);
469 }
470 return this.applyEncoding(methodInjection, query);
471 }
472
473 private String initRawInjection(String paramLead, boolean isUsingIndex, String sqlTrail) {
474 String query;
475
476 if (!isUsingIndex) {
477
478
479
480 query = paramLead + sqlTrail;
481 } else {
482
483
484 query = paramLead + this.getMediatorStrategy().getSpecificUnion().getIndexesInUrl().replaceAll(
485 String.format(EngineYaml.FORMAT_INDEX, this.mediatorStrategy.getSpecificUnion().getVisibleIndex()),
486
487
488 Matcher.quoteReplacement(sqlTrail)
489 );
490 }
491
492 return query + this.mediatorEngine.getEngine().instance().endingComment();
493 }
494
495 private String initStarInjection(String paramLead, boolean isUsingIndex, String sqlTrail) {
496 String query;
497
498
499
500
501 if (!isUsingIndex) {
502 query = paramLead.replace(
503 InjectionModel.STAR,
504 sqlTrail + this.mediatorEngine.getEngine().instance().endingComment()
505 );
506 } else {
507
508
509 query = paramLead.replace(
510 InjectionModel.STAR,
511 this.mediatorStrategy.getSpecificUnion().getIndexesInUrl().replace(
512 String.format(EngineYaml.FORMAT_INDEX, this.mediatorStrategy.getSpecificUnion().getVisibleIndex()),
513 sqlTrail
514 )
515 + this.mediatorEngine.getEngine().instance().endingComment()
516 );
517 }
518 return query;
519 }
520
521
522
523
524
525 private String cleanQuery(AbstractMethodInjection methodInjection, String query) {
526 String queryFixed = query;
527 if (
528 methodInjection == this.mediatorMethod.getRequest()
529 && (
530 this.mediatorUtils.parameterUtil().isRequestSoap()
531 || this.mediatorUtils.parameterUtil().isMultipartRequest()
532 )
533 ) {
534 queryFixed = StringUtil.removeSqlComment(queryFixed)
535 .replace("+", " ")
536 .replace("%2b", "+")
537 .replace("%23", "#");
538 if (this.mediatorUtils.parameterUtil().isMultipartRequest()) {
539
540 queryFixed = queryFixed.replaceAll("(?s)\\\\n", "\r\n");
541 }
542 } else {
543 queryFixed = StringUtil.cleanSql(queryFixed);
544 }
545 return queryFixed;
546 }
547
548 private String applyEncoding(AbstractMethodInjection methodInjection, String query) {
549 String queryFixed = query;
550 if (!this.mediatorUtils.parameterUtil().isRequestSoap()) {
551 if (methodInjection == this.mediatorMethod.getQuery()) {
552
553 if (!this.mediatorUtils.preferencesUtil().isUrlEncodingDisabled()) {
554 queryFixed = queryFixed.replace("'", "%27");
555 queryFixed = queryFixed.replace("(", "%28");
556 queryFixed = queryFixed.replace(")", "%29");
557 queryFixed = queryFixed.replace("{", "%7b");
558 queryFixed = queryFixed.replace("[", "%5b");
559 queryFixed = queryFixed.replace("]", "%5d");
560 queryFixed = queryFixed.replace("}", "%7d");
561 queryFixed = queryFixed.replace(">", "%3e");
562 queryFixed = queryFixed.replace("<", "%3c");
563 queryFixed = queryFixed.replace("?", "%3f");
564 queryFixed = queryFixed.replace("_", "%5f");
565 queryFixed = queryFixed.replace(",", "%2c");
566 }
567
568 queryFixed = queryFixed.replace(StringUtils.SPACE, "+");
569 queryFixed = queryFixed.replace("`", "%60");
570 queryFixed = queryFixed.replace("\"", "%22");
571 queryFixed = queryFixed.replace("|", "%7c");
572 queryFixed = queryFixed.replace("\\", "%5c");
573 } else if (methodInjection != this.mediatorMethod.getRequest()) {
574
575 queryFixed = queryFixed.replace("+", "%20");
576 queryFixed = queryFixed.replace(",", "%2c");
577 try {
578 queryFixed = URLDecoder.decode(queryFixed, StandardCharsets.UTF_8);
579 } catch (IllegalArgumentException e) {
580 LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Incorrect values in [{}], please check the parameters", methodInjection.name());
581 throw new JSqlRuntimeException(e);
582 }
583 }
584 }
585 return queryFixed;
586 }
587
588
589
590
591
592
593 public void sendResponseFromSite(String message, String source) {
594 LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "{}, response from site:", message);
595 LOGGER.log(LogLevelUtil.CONSOLE_ERROR, ">>>{}", source);
596 }
597
598
599
600
601 public boolean shouldErasePreviousInjection() {
602 return this.shouldErasePreviousInjection;
603 }
604
605 public void setIsScanning(boolean isScanning) {
606 this.isScanning = isScanning;
607 }
608
609 public PropertiesUtil getPropertiesUtil() {
610 return this.propertiesUtil;
611 }
612
613 public MediatorUtils getMediatorUtils() {
614 return this.mediatorUtils;
615 }
616
617 public MediatorEngine getMediatorEngine() {
618 return this.mediatorEngine;
619 }
620
621 public MediatorMethod getMediatorMethod() {
622 return this.mediatorMethod;
623 }
624
625 public DataAccess getDataAccess() {
626 return this.dataAccess;
627 }
628
629 public ResourceAccess getResourceAccess() {
630 return this.resourceAccess;
631 }
632
633 public MediatorStrategy getMediatorStrategy() {
634 return this.mediatorStrategy;
635 }
636
637 public void appendAnalysisReport(String analysisReport) {
638 this.appendAnalysisReport(analysisReport, false);
639 }
640
641 public void appendAnalysisReport(String analysisReport, boolean isInit) {
642 this.analysisReport += (isInit ? StringUtils.EMPTY : "<br> <br> ") + analysisReport;
643 }
644 }