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 = hasFoundInjection;
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, "Incorrect Query Url: {}", 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(LogLevelUtil.CONSOLE_ERROR, "Error during connection: {}", e.getMessage());
320 } catch (InterruptedException e) {
321 LOGGER.log(LogLevelUtil.IGNORE, e, e);
322 Thread.currentThread().interrupt();
323 }
324
325 return pageSource;
326 }
327
328 private String initQueryString(boolean isUsingIndex, String urlInjection, String dataInjection) {
329 String urlInjectionFixed = urlInjection;
330 if (
331 this.mediatorUtils.parameterUtil().getListQueryString().isEmpty()
332 && !this.mediatorUtils.preferencesUtil().isProcessingCsrf()
333 ) {
334 return urlInjectionFixed;
335 }
336
337
338
339 if (!urlInjectionFixed.contains("?")) {
340 urlInjectionFixed += "?";
341 }
342 urlInjectionFixed += this.buildQuery(
343 this.mediatorMethod.getQuery(),
344 this.mediatorUtils.parameterUtil().getQueryStringFromEntries(),
345 isUsingIndex,
346 dataInjection
347 );
348 return this.mediatorUtils.csrfUtil().addQueryStringToken(urlInjectionFixed);
349 }
350
351 private void initHeader(boolean isUsingIndex, String dataInjection, Builder httpRequest) {
352 if (!this.mediatorUtils.parameterUtil().getListHeader().isEmpty()) {
353 Stream.of(
354 this.buildQuery(
355 this.mediatorMethod.getHeader(),
356 this.mediatorUtils.parameterUtil().getHeaderFromEntries(),
357 isUsingIndex,
358 dataInjection
359 )
360 .split("\\\\r\\\\n")
361 )
362 .forEach(header -> {
363 if (header.split(":").length == 2) {
364 try {
365 HeaderUtil.sanitizeHeaders(
366 httpRequest,
367 new SimpleEntry<>(
368 header.split(":")[0],
369 header.split(":")[1]
370 )
371 );
372 } catch (JSqlException e) {
373 LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Headers sanitizing issue caught already during connection, ignoring", e);
374 }
375 }
376 });
377 }
378 }
379
380 private String initRequest(boolean isUsingIndex, String dataInjection, Builder httpRequest) {
381 if (
382 this.mediatorUtils.parameterUtil().getListRequest().isEmpty()
383 && this.mediatorUtils.csrfUtil().getTokenCsrf() == null
384 ) {
385 return StringUtils.EMPTY;
386 }
387
388
389
390
391 if (this.mediatorUtils.parameterUtil().isRequestSoap()) {
392 httpRequest.setHeader(HeaderUtil.CONTENT_TYPE_REQUEST, "text/xml");
393 } else {
394 httpRequest.setHeader(HeaderUtil.CONTENT_TYPE_REQUEST, "application/x-www-form-urlencoded");
395 }
396
397 var body = new StringBuilder();
398 this.mediatorUtils.csrfUtil().addRequestToken(body);
399
400 if (this.mediatorUtils.connectionUtil().getTypeRequest().matches("PUT|POST")) {
401 if (this.mediatorUtils.parameterUtil().isRequestSoap()) {
402 body.append(
403 this.buildQuery(
404 this.mediatorMethod.getRequest(),
405 this.mediatorUtils.parameterUtil().getRawRequest(),
406 isUsingIndex,
407 dataInjection
408 )
409
410
411 .replace("\u0001", "")
412 .replace("\u0003", "")
413 .replace("\u0004", "")
414 .replace("\u0005", "")
415 .replace("\u0006", "")
416 .replace("\u0007", "")
417 .replace("+", "%2B")
418 );
419 } else {
420 body.append(
421 this.buildQuery(
422 this.mediatorMethod.getRequest(),
423 this.mediatorUtils.parameterUtil().getRequestFromEntries(),
424 isUsingIndex,
425 dataInjection
426 )
427 );
428 }
429 }
430
431 var bodyPublisher = BodyPublishers.ofString(body.toString());
432 httpRequest.method(
433 this.mediatorUtils.connectionUtil().getTypeRequest(),
434 bodyPublisher
435 );
436 return body.toString();
437 }
438
439 private String buildQuery(AbstractMethodInjection methodInjection, String paramLead, boolean isUsingIndex, String sqlTrail) {
440 String query;
441 String paramLeadFixed = paramLead.replace(
442 InjectionModel.STAR,
443 TamperingUtil.TAG_OPENED + InjectionModel.STAR + TamperingUtil.TAG_CLOSED
444 );
445 if (
446
447 this.mediatorUtils.connectionUtil().getMethodInjection() != methodInjection
448
449 || this.mediatorUtils.connectionUtil().getUrlBase().contains(InjectionModel.STAR)
450 ) {
451 query = paramLeadFixed;
452 } else if (
453
454
455
456 paramLeadFixed.contains(InjectionModel.STAR)
457 ) {
458 query = this.initStarInjection(paramLeadFixed, isUsingIndex, sqlTrail);
459 } else {
460 query = this.initRawInjection(paramLeadFixed, isUsingIndex, sqlTrail);
461 }
462 query = this.cleanQuery(methodInjection, query);
463
464 if (this.mediatorUtils.connectionUtil().getMethodInjection() == methodInjection) {
465 query = this.mediatorUtils.tamperingUtil().tamper(query);
466 } else {
467 String regexToRemoveTamperTags = String.format("(?i)%s|%s", TamperingUtil.TAG_OPENED, TamperingUtil.TAG_CLOSED);
468 query = query.replaceAll(regexToRemoveTamperTags, StringUtils.EMPTY);
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
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 );
516 }
517 return query;
518 }
519
520
521
522
523
524 private String cleanQuery(AbstractMethodInjection methodInjection, String query) {
525 String queryFixed = query;
526 if (
527 methodInjection == this.mediatorMethod.getRequest()
528 && (
529 this.mediatorUtils.parameterUtil().isRequestSoap()
530 || this.mediatorUtils.parameterUtil().isMultipartRequest()
531 )
532 ) {
533 queryFixed = StringUtil.removeSqlComment(queryFixed)
534 .replace("+", " ")
535 .replace("%2b", "+")
536 .replace("%23", "#");
537 if (this.mediatorUtils.parameterUtil().isMultipartRequest()) {
538
539 queryFixed = queryFixed.replaceAll("(?s)\\\\n", "\r\n");
540 }
541 } else {
542 queryFixed = StringUtil.cleanSql(queryFixed);
543 }
544 return queryFixed;
545 }
546
547 private String applyEncoding(AbstractMethodInjection methodInjection, String query) {
548 String queryFixed = query;
549 if (!this.mediatorUtils.parameterUtil().isRequestSoap()) {
550 if (methodInjection == this.mediatorMethod.getQuery()) {
551
552 if (!this.mediatorUtils.preferencesUtil().isUrlEncodingDisabled()) {
553 queryFixed = queryFixed.replace("'", "%27");
554 queryFixed = queryFixed.replace("(", "%28");
555 queryFixed = queryFixed.replace(")", "%29");
556 queryFixed = queryFixed.replace("{", "%7b");
557 queryFixed = queryFixed.replace("[", "%5b");
558 queryFixed = queryFixed.replace("]", "%5d");
559 queryFixed = queryFixed.replace("}", "%7d");
560 queryFixed = queryFixed.replace(">", "%3e");
561 queryFixed = queryFixed.replace("<", "%3c");
562 queryFixed = queryFixed.replace("?", "%3f");
563 queryFixed = queryFixed.replace("_", "%5f");
564 queryFixed = queryFixed.replace(",", "%2c");
565 }
566
567 queryFixed = queryFixed.replace(StringUtils.SPACE, "+");
568 queryFixed = queryFixed.replace("`", "%60");
569 queryFixed = queryFixed.replace("\"", "%22");
570 queryFixed = queryFixed.replace("|", "%7c");
571 queryFixed = queryFixed.replace("\\", "%5c");
572 } else if (methodInjection != this.mediatorMethod.getRequest()) {
573
574 queryFixed = queryFixed.replace("+", "%20");
575 queryFixed = queryFixed.replace(",", "%2c");
576 try {
577 queryFixed = URLDecoder.decode(queryFixed, StandardCharsets.UTF_8);
578 } catch (IllegalArgumentException e) {
579 LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Incorrect values in [{}], please check the parameters", methodInjection.name());
580 throw new JSqlRuntimeException(e);
581 }
582 }
583 }
584 return queryFixed;
585 }
586
587
588
589
590
591
592 public void sendResponseFromSite(String message, String source) {
593 LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "{}, response from site:", message);
594 LOGGER.log(LogLevelUtil.CONSOLE_ERROR, ">>>{}", source);
595 }
596
597
598
599
600 public boolean shouldErasePreviousInjection() {
601 return this.shouldErasePreviousInjection;
602 }
603
604 public void setIsScanning(boolean isScanning) {
605 this.isScanning = isScanning;
606 }
607
608 public PropertiesUtil getPropertiesUtil() {
609 return this.propertiesUtil;
610 }
611
612 public MediatorUtils getMediatorUtils() {
613 return this.mediatorUtils;
614 }
615
616 public MediatorEngine getMediatorEngine() {
617 return this.mediatorEngine;
618 }
619
620 public MediatorMethod getMediatorMethod() {
621 return this.mediatorMethod;
622 }
623
624 public DataAccess getDataAccess() {
625 return this.dataAccess;
626 }
627
628 public ResourceAccess getResourceAccess() {
629 return this.resourceAccess;
630 }
631
632 public MediatorStrategy getMediatorStrategy() {
633 return this.mediatorStrategy;
634 }
635
636 public void appendAnalysisReport(String analysisReport) {
637 this.appendAnalysisReport(analysisReport, false);
638 }
639
640 public void appendAnalysisReport(String analysisReport, boolean isInit) {
641 this.analysisReport += (isInit ? StringUtils.EMPTY : "<br> <br> ") + analysisReport;
642 }
643
644 public void setAnalysisReport(String analysisReport) {
645 this.analysisReport = analysisReport;
646 }
647 }