1 package com.jsql.model.injection.strategy;
2
3 import com.jsql.model.InjectionModel;
4 import com.jsql.model.accessible.DataAccess;
5 import com.jsql.view.subscriber.Seal;
6 import com.jsql.model.exception.JSqlException;
7 import com.jsql.model.injection.engine.model.EngineYaml;
8 import com.jsql.model.suspendable.AbstractSuspendable;
9 import com.jsql.model.suspendable.SuspendableGetIndexes;
10 import com.jsql.util.I18nUtil;
11 import com.jsql.util.LogLevelUtil;
12 import com.jsql.util.StringUtil;
13 import org.apache.commons.lang3.StringUtils;
14 import org.apache.logging.log4j.LogManager;
15 import org.apache.logging.log4j.Logger;
16
17 import java.util.ArrayList;
18 import java.util.Arrays;
19 import java.util.Comparator;
20 import java.util.List;
21 import java.util.regex.Pattern;
22
23 public class StrategyUnion extends AbstractStrategy {
24
25 private static final Logger LOGGER = LogManager.getRootLogger();
26
27 private String indexesInUrl = StringUtils.EMPTY;
28 protected String visibleIndex;
29 protected String sourceIndexesFound = StringUtils.EMPTY;
30 private int nbIndexesFound = 0;
31
32 private String performanceLength = "0";
33
34 public StrategyUnion(InjectionModel injectionModel) {
35 super(injectionModel);
36 }
37
38 @Override
39 public void checkApplicability() throws JSqlException {
40 if (this.injectionModel.getMediatorUtils().preferencesUtil().isStrategyUnionDisabled()) {
41 LOGGER.log(LogLevelUtil.CONSOLE_INFORM, AbstractStrategy.FORMAT_SKIP_STRATEGY_DISABLED, this.getName());
42 return;
43 }
44
45 this.logChecking();
46
47
48 this.indexesInUrl = new SuspendableGetIndexes(this.injectionModel).run();
49 if (StringUtils.isNotEmpty(this.indexesInUrl)) {
50 this.visibleIndex = this.getVisibleIndex(this.sourceIndexesFound);
51 }
52
53 this.isApplicable = StringUtils.isNotEmpty(this.indexesInUrl)
54 && Integer.parseInt(this.injectionModel.getMediatorStrategy().getUnion().getPerformanceLength()) > 0
55 && StringUtils.isNotBlank(this.visibleIndex);
56
57 if (this.isApplicable) {
58 LOGGER.log(
59 LogLevelUtil.CONSOLE_SUCCESS,
60 "{} [{}] at index [{}] showing [{}] characters",
61 () -> I18nUtil.valueByKey(AbstractStrategy.KEY_LOG_VULNERABLE),
62 this::getName,
63 () -> this.visibleIndex,
64 () -> this.performanceLength
65 );
66 this.allow();
67 } else {
68 this.unallow();
69 }
70 }
71
72 @Override
73 public void allow(int... i) {
74 this.injectionModel.appendAnalysisReport(
75 StringUtil.formatReport(LogLevelUtil.COLOR_BLU, "### Strategy: " + this.getName())
76 + this.injectionModel.getReportWithIndexes(
77 this.injectionModel.getMediatorEngine().getEngine().instance().sqlUnion(StringUtil.formatReport(LogLevelUtil.COLOR_GREEN, "<query>"), "0", true),
78 "metadataInjectionProcess"
79 )
80 );
81 this.injectionModel.sendToViews(new Seal.MarkStrategyVulnerable(this));
82 }
83
84 @Override
85 public void unallow(int... i) {
86 this.injectionModel.sendToViews(new Seal.MarkStrategyInvulnerable(this));
87 }
88
89 @Override
90 public String inject(String sqlQuery, String startPosition, AbstractSuspendable stoppable, String metadataInjectionProcess) {
91 return this.injectionModel.injectWithIndexes(
92 this.injectionModel.getMediatorEngine().getEngine().instance().sqlUnion(sqlQuery, startPosition, false),
93 metadataInjectionProcess
94 );
95 }
96
97 @Override
98 public void activateWhenApplicable() {
99 if (this.injectionModel.getMediatorStrategy().getStrategy() == null && this.isApplicable()) {
100 LOGGER.log(
101 LogLevelUtil.CONSOLE_INFORM,
102 "{} [{}]",
103 () -> I18nUtil.valueByKey("LOG_USING_STRATEGY"),
104 this::getName
105 );
106 this.injectionModel.getMediatorStrategy().setStrategy(this);
107 this.injectionModel.sendToViews(new Seal.ActivateStrategy(this));
108 }
109 }
110
111
112
113
114
115
116
117
118 public String getVisibleIndex(String firstSuccessPageSource) {
119
120
121 String regexAllIndexes = String.format(EngineYaml.FORMAT_INDEX, "(\\d+?)");
122 var regexSearch = Pattern.compile("(?s)"+ regexAllIndexes).matcher(firstSuccessPageSource);
123
124 List<String> listFoundIndexes = new ArrayList<>();
125 while (regexSearch.find()) {
126 listFoundIndexes.add(regexSearch.group(1));
127 }
128 String[] arrayFoundIndexes = listFoundIndexes.toArray(new String[0]);
129
130
131
132
133 String performanceQuery = this.injectionModel.getMediatorEngine().getEngine().instance().sqlCapacity(arrayFoundIndexes);
134 String performanceSourcePage = this.injectionModel.injectWithoutIndex(performanceQuery, "union#size");
135
136
137
138
139 regexSearch = Pattern.compile("(?s)"+ DataAccess.LEAD +"(\\d+)("+ EngineYaml.CALIBRATOR_SQL +"+)").matcher(performanceSourcePage);
140 List<String[]> performanceResults = new ArrayList<>();
141 while (regexSearch.find()) {
142 performanceResults.add(new String[]{regexSearch.group(1), regexSearch.group(2)});
143 }
144 if (performanceResults.isEmpty()) {
145 this.performanceLength = "0";
146 return null;
147 }
148
149
150
151
152 var lengthFields = new Integer[performanceResults.size()][2];
153 for (var i = 0 ; i < performanceResults.size() ; i++) {
154 lengthFields[i] = new Integer[] {
155 performanceResults.get(i)[1].length()
156 + performanceResults.get(i)[0].length(),
157 Integer.parseInt(performanceResults.get(i)[0])
158 };
159 }
160
161
162 Arrays.sort(lengthFields, Comparator.comparing((Integer[] s) -> s[0]));
163 Integer[] bestLengthFields = lengthFields[lengthFields.length - 1];
164 this.performanceLength = bestLengthFields[0].toString();
165
166
167 String regexAllExceptIndexesFound = String.format(
168 EngineYaml.FORMAT_INDEX,
169 "(?!"+ String.join("|", arrayFoundIndexes) +"7331)\\d*"
170 );
171 String indexesInUrlFixed = this.indexesInUrl.replaceAll(regexAllExceptIndexesFound, "1");
172
173
174 String regexAllIndexesExceptBest = String.format(
175 EngineYaml.FORMAT_INDEX,
176 "(?!"+ bestLengthFields[1] +"7331)\\d*"
177 );
178 this.indexesInUrl = indexesInUrlFixed.replaceAll(regexAllIndexesExceptBest, "1");
179
180 return Integer.toString(bestLengthFields[1]);
181 }
182
183
184
185
186 @Override
187 public String getPerformanceLength() {
188 return this.performanceLength;
189 }
190
191 @Override
192 public String getName() {
193 return "Union";
194 }
195
196 public String getVisibleIndex() {
197 return this.visibleIndex;
198 }
199
200 public void setVisibleIndex(String visibleIndex) {
201 this.visibleIndex = visibleIndex;
202 }
203
204 public void setSourceIndexesFound(String sourceIndexesFound) {
205 this.sourceIndexesFound = sourceIndexesFound;
206 }
207
208 public int getNbIndexesFound() {
209 return this.nbIndexesFound;
210 }
211
212 public void setNbIndexesFound(int nbIndexesFound) {
213 this.nbIndexesFound = nbIndexesFound;
214 }
215
216 public String getIndexesInUrl() {
217 return this.indexesInUrl;
218 }
219
220 public void setIndexesInUrl(String indexesInUrl) {
221 this.indexesInUrl = indexesInUrl;
222 }
223 }