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