1 | package com.jsql.model.injection.strategy; | |
2 | ||
3 | import com.jsql.model.InjectionModel; | |
4 | import com.jsql.model.exception.JSqlException; | |
5 | import com.jsql.model.injection.vendor.model.VendorYaml; | |
6 | import com.jsql.model.suspendable.SuspendableGetCharInsertion; | |
7 | import com.jsql.model.suspendable.SuspendableGetVendor; | |
8 | import com.jsql.util.LogLevelUtil; | |
9 | import com.jsql.util.StringUtil; | |
10 | import org.apache.commons.lang3.StringUtils; | |
11 | import org.apache.logging.log4j.LogManager; | |
12 | import org.apache.logging.log4j.Logger; | |
13 | ||
14 | import java.util.AbstractMap.SimpleEntry; | |
15 | import java.util.Arrays; | |
16 | import java.util.List; | |
17 | import java.util.regex.Matcher; | |
18 | ||
19 | public class MediatorStrategy { | |
20 | ||
21 | /** | |
22 | * Log4j logger sent to view. | |
23 | */ | |
24 | private static final Logger LOGGER = LogManager.getRootLogger(); | |
25 | | |
26 | private final AbstractStrategy time; | |
27 | private final AbstractStrategy blindBit; | |
28 | private final AbstractStrategy blindBin; | |
29 | private final AbstractStrategy multibit; | |
30 | private final StrategyError error; | |
31 | private final AbstractStrategy union; | |
32 | private final AbstractStrategy stack; | |
33 | ||
34 | private final List<AbstractStrategy> strategies; | |
35 | | |
36 | /** | |
37 | * Current injection strategy. | |
38 | */ | |
39 | private AbstractStrategy strategy; | |
40 | ||
41 | private final InjectionModel injectionModel; | |
42 | | |
43 | public MediatorStrategy(InjectionModel injectionModel) { | |
44 | this.injectionModel = injectionModel; | |
45 | | |
46 | this.time = new StrategyTime(this.injectionModel); | |
47 | this.blindBit = new StrategyBlindBit(this.injectionModel); | |
48 | this.blindBin = new StrategyBlindBin(this.injectionModel); | |
49 | this.multibit = new StrategyMultibit(this.injectionModel); | |
50 | this.error = new StrategyError(this.injectionModel); | |
51 | this.union = new StrategyUnion(this.injectionModel); | |
52 | this.stack = new StrategyStack(this.injectionModel); | |
53 | ||
54 | this.strategies = Arrays.asList(this.time, this.blindBin, this.blindBit, this.multibit, this.error, this.stack, this.union); | |
55 | } | |
56 | | |
57 | public String getMeta() { | |
58 |
1
1. getMeta : negated conditional → NO_COVERAGE |
String strategyName = this.strategy == null ? StringUtils.EMPTY : this.strategy.toString().toLowerCase(); |
59 | var strategyMode = "default"; | |
60 |
1
1. getMeta : negated conditional → NO_COVERAGE |
if (this.injectionModel.getMediatorUtils().getPreferencesUtil().isDiosStrategy()) { |
61 | strategyMode = "dios"; | |
62 |
1
1. getMeta : negated conditional → NO_COVERAGE |
} else if (this.injectionModel.getMediatorUtils().getPreferencesUtil().isZipStrategy()) { |
63 | strategyMode = "zip"; | |
64 | } | |
65 |
1
1. getMeta : replaced return value with "" for com/jsql/model/injection/strategy/MediatorStrategy::getMeta → NO_COVERAGE |
return String.format("%s#%s", strategyName.replace(" ", "-"), strategyMode); |
66 | } | |
67 | | |
68 | /** | |
69 | * Build correct data for GET, POST, HEADER. | |
70 | * Each can be either raw data (no injection), SQL query without index requirement, | |
71 | * or SQL query with index requirement. | |
72 | * @param urlBase Beginning of the request data | |
73 | * @param isUsingIndex False if request doesn't use indexes | |
74 | * @param sqlTrail SQL statement | |
75 | * @return Final data | |
76 | */ | |
77 | public String buildPath(String urlBase, boolean isUsingIndex, String sqlTrail) { | |
78 | String result = urlBase; | |
79 |
1
1. buildPath : negated conditional → NO_COVERAGE |
if (urlBase.contains(InjectionModel.STAR)) { |
80 |
1
1. buildPath : negated conditional → NO_COVERAGE |
if (!isUsingIndex) { |
81 | result = urlBase.replace(InjectionModel.STAR, this.encodePath(sqlTrail)); | |
82 | } else { | |
83 | result = urlBase.replace( | |
84 | InjectionModel.STAR, | |
85 | this.encodePath( | |
86 | this.injectionModel.getIndexesInUrl().replaceAll( | |
87 | String.format(VendorYaml.FORMAT_INDEX, this.getSpecificUnion().getVisibleIndex()), | |
88 | Matcher.quoteReplacement(sqlTrail) // Oracle column can contain regex char $ => quoteReplacement() | |
89 | ) | |
90 | ) | |
91 | ); | |
92 | } | |
93 | } | |
94 |
1
1. buildPath : replaced return value with "" for com/jsql/model/injection/strategy/MediatorStrategy::buildPath → NO_COVERAGE |
return result; |
95 | } | |
96 | ||
97 | private String encodePath(String sqlTrail) { | |
98 | String sqlTrailEncoded = StringUtil.cleanSql(sqlTrail); | |
99 | ||
100 |
1
1. encodePath : negated conditional → NO_COVERAGE |
if (!this.injectionModel.getMediatorUtils().getPreferencesUtil().isUrlEncodingDisabled()) { |
101 | sqlTrailEncoded = sqlTrailEncoded | |
102 | .replace("'", "%27") | |
103 | .replace("(", "%28") | |
104 | .replace(")", "%29") | |
105 | .replace("{", "%7b") | |
106 | .replace("[", "%5b") | |
107 | .replace("]", "%5d") | |
108 | .replace("}", "%7d") | |
109 | .replace(">", "%3e") | |
110 | .replace("<", "%3c") | |
111 | .replace("?", "%3f") | |
112 | .replace("_", "%5f") | |
113 | .replace("\\", "%5c") | |
114 | .replace(",", "%2c"); | |
115 | } | |
116 | ||
117 | // URL forbidden characters | |
118 |
1
1. encodePath : replaced return value with "" for com/jsql/model/injection/strategy/MediatorStrategy::encodePath → NO_COVERAGE |
return (sqlTrailEncoded + this.injectionModel.getMediatorVendor().getVendor().instance().endingComment()) |
119 | .replace("\"", "%22") | |
120 | .replace("|", "%7c") | |
121 | .replace("`", "%60") | |
122 | .replace(StringUtils.SPACE, "%20") | |
123 | .replace("+", "%20"); | |
124 | } | |
125 | | |
126 | /** | |
127 | * Find the insertion character, test each strategy, inject metadata and list databases. | |
128 | * @param parameterToInject to be tested, null when injection point | |
129 | * @return true when successful injection | |
130 | * @throws JSqlException when no params integrity, process stopped by user, or injection failure | |
131 | */ | |
132 | public boolean testStrategies(SimpleEntry<String, String> parameterToInject) throws JSqlException { | |
133 | // Define insertionCharacter, i.e, -1 in "[..].php?id=-1 union select[..]", | |
134 | | |
135 | String parameterOriginalValue = null; | |
136 | | |
137 | // Fingerprint database | |
138 |
1
1. testStrategies : removed call to com/jsql/model/injection/vendor/MediatorVendor::setVendor → NO_COVERAGE |
this.injectionModel.getMediatorVendor().setVendor(this.injectionModel.getMediatorVendor().fingerprintVendor()); |
139 | | |
140 | // If not an injection point then find insertion character. | |
141 | // Force to 1 if no insertion char works and empty value from user, | |
142 | // Force to user's value if no insertion char works, | |
143 | // Force to insertion char otherwise. | |
144 | // parameterToInject null on true STAR injection | |
145 | // TODO Use also on Json injection where parameter == null | |
146 |
1
1. testStrategies : negated conditional → NO_COVERAGE |
if (parameterToInject != null) { |
147 | parameterOriginalValue = parameterToInject.getValue(); | |
148 | | |
149 | // Test for params integrity | |
150 | String characterInsertionByUser = this.injectionModel.getMediatorUtils().getParameterUtil().initStar(parameterToInject); | |
151 | | |
152 |
1
1. testStrategies : negated conditional → NO_COVERAGE |
String characterInsertion = this.injectionModel.getMediatorUtils().getPreferencesUtil().isNotSearchingCharInsertion() |
153 | ? characterInsertionByUser | |
154 | : new SuspendableGetCharInsertion(this.injectionModel).run(characterInsertionByUser); | |
155 |
1
1. testStrategies : negated conditional → NO_COVERAGE |
if (characterInsertion.contains(InjectionModel.STAR)) { // When injecting all parameters or JSON |
156 | parameterToInject.setValue(characterInsertion); | |
157 | } else { // When injecting last parameter | |
158 | parameterToInject.setValue(characterInsertion.replaceAll("(\\w)$", "$1+") + InjectionModel.STAR); | |
159 | } | |
160 |
1
1. testStrategies : negated conditional → NO_COVERAGE |
} else if (this.injectionModel.getMediatorUtils().getConnectionUtil().getUrlBase().contains(InjectionModel.STAR)) { |
161 | String characterInsertion = new SuspendableGetCharInsertion(this.injectionModel).run(StringUtils.EMPTY); | |
162 | String urlBase = this.injectionModel.getMediatorUtils().getConnectionUtil().getUrlBase(); | |
163 |
1
1. testStrategies : removed call to com/jsql/util/ConnectionUtil::setUrlBase → NO_COVERAGE |
this.injectionModel.getMediatorUtils().getConnectionUtil().setUrlBase( |
164 | // Space %20 for URL, do not use + | |
165 | urlBase.replace(InjectionModel.STAR, characterInsertion.replaceAll("(\\w)$", "$1%20") + InjectionModel.STAR) | |
166 | ); | |
167 | } | |
168 | ||
169 |
1
1. testStrategies : negated conditional → NO_COVERAGE |
if (this.injectionModel.getMediatorVendor().getVendorByUser() == this.injectionModel.getMediatorVendor().getAuto()) { |
170 | new SuspendableGetVendor(this.injectionModel).run(); | |
171 | } | |
172 | ||
173 | // Test each injection strategies: time < blind binary < blind bitwise < multibit < error < stack < union | |
174 |
1
1. testStrategies : removed call to com/jsql/model/injection/strategy/AbstractStrategy::checkApplicability → NO_COVERAGE |
this.time.checkApplicability(); |
175 |
1
1. testStrategies : removed call to com/jsql/model/injection/strategy/AbstractStrategy::checkApplicability → NO_COVERAGE |
this.blindBin.checkApplicability(); |
176 |
1
1. testStrategies : removed call to com/jsql/model/injection/strategy/AbstractStrategy::checkApplicability → NO_COVERAGE |
this.blindBit.checkApplicability(); |
177 | ||
178 |
1
1. testStrategies : negated conditional → NO_COVERAGE |
if (parameterToInject != null) { |
179 | // Multibit requires '0' | |
180 | // TODO char insertion 0' should also work on "where x='$param'" | |
181 | var backupCharacterInsertion = parameterToInject.getValue(); | |
182 | parameterToInject.setValue(InjectionModel.STAR); | |
183 |
1
1. testStrategies : removed call to com/jsql/model/injection/strategy/AbstractStrategy::checkApplicability → NO_COVERAGE |
this.multibit.checkApplicability(); |
184 | parameterToInject.setValue(backupCharacterInsertion); | |
185 | } else { | |
186 |
1
1. testStrategies : removed call to com/jsql/model/injection/strategy/AbstractStrategy::checkApplicability → NO_COVERAGE |
this.multibit.checkApplicability(); |
187 | } | |
188 | ||
189 |
1
1. testStrategies : removed call to com/jsql/model/injection/strategy/StrategyError::checkApplicability → NO_COVERAGE |
this.error.checkApplicability(); |
190 |
1
1. testStrategies : removed call to com/jsql/model/injection/strategy/AbstractStrategy::checkApplicability → NO_COVERAGE |
this.stack.checkApplicability(); |
191 |
1
1. testStrategies : removed call to com/jsql/model/injection/strategy/AbstractStrategy::checkApplicability → NO_COVERAGE |
this.union.checkApplicability(); |
192 | ||
193 | // Set most efficient strategy first: union > stack > error > multibit > blind bitwise > blind binary > time | |
194 |
1
1. testStrategies : removed call to com/jsql/model/injection/strategy/AbstractStrategy::activateWhenApplicable → NO_COVERAGE |
this.union.activateWhenApplicable(); |
195 |
1
1. testStrategies : removed call to com/jsql/model/injection/strategy/AbstractStrategy::activateWhenApplicable → NO_COVERAGE |
this.stack.activateWhenApplicable(); |
196 |
1
1. testStrategies : removed call to com/jsql/model/injection/strategy/StrategyError::activateWhenApplicable → NO_COVERAGE |
this.error.activateWhenApplicable(); |
197 |
1
1. testStrategies : removed call to com/jsql/model/injection/strategy/AbstractStrategy::activateWhenApplicable → NO_COVERAGE |
this.multibit.activateWhenApplicable(); |
198 |
1
1. testStrategies : removed call to com/jsql/model/injection/strategy/AbstractStrategy::activateWhenApplicable → NO_COVERAGE |
this.blindBit.activateWhenApplicable(); |
199 |
1
1. testStrategies : removed call to com/jsql/model/injection/strategy/AbstractStrategy::activateWhenApplicable → NO_COVERAGE |
this.blindBin.activateWhenApplicable(); |
200 |
1
1. testStrategies : removed call to com/jsql/model/injection/strategy/AbstractStrategy::activateWhenApplicable → NO_COVERAGE |
this.time.activateWhenApplicable(); |
201 | ||
202 |
1
1. testStrategies : negated conditional → NO_COVERAGE |
if (this.injectionModel.getMediatorStrategy().getStrategy() == null) { // no strategy found |
203 | // Restore initial parameter value on injection failure | |
204 | // Only when not true STAR injection | |
205 |
1
1. testStrategies : negated conditional → NO_COVERAGE |
if (parameterOriginalValue != null) { |
206 | parameterToInject.setValue(parameterOriginalValue.replace(InjectionModel.STAR, StringUtils.EMPTY)); | |
207 | } | |
208 | ||
209 | LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "No injection found"); | |
210 |
1
1. testStrategies : replaced boolean return with true for com/jsql/model/injection/strategy/MediatorStrategy::testStrategies → NO_COVERAGE |
return false; |
211 | } | |
212 | | |
213 |
1
1. testStrategies : replaced boolean return with false for com/jsql/model/injection/strategy/MediatorStrategy::testStrategies → NO_COVERAGE |
return true; |
214 | } | |
215 | | |
216 | | |
217 | // Getter and setter | |
218 | ||
219 | public AbstractStrategy getUnion() { | |
220 |
1
1. getUnion : replaced return value with null for com/jsql/model/injection/strategy/MediatorStrategy::getUnion → NO_COVERAGE |
return this.union; |
221 | } | |
222 | ||
223 | public StrategyUnion getSpecificUnion() { | |
224 |
1
1. getSpecificUnion : replaced return value with null for com/jsql/model/injection/strategy/MediatorStrategy::getSpecificUnion → NO_COVERAGE |
return (StrategyUnion) this.union; |
225 | } | |
226 | ||
227 | public StrategyError getError() { | |
228 |
1
1. getError : replaced return value with null for com/jsql/model/injection/strategy/MediatorStrategy::getError → NO_COVERAGE |
return this.error; |
229 | } | |
230 | ||
231 | public AbstractStrategy getBlindBit() { | |
232 |
1
1. getBlindBit : replaced return value with null for com/jsql/model/injection/strategy/MediatorStrategy::getBlindBit → NO_COVERAGE |
return this.blindBit; |
233 | } | |
234 | ||
235 | public AbstractStrategy getMultibit() { | |
236 |
1
1. getMultibit : replaced return value with null for com/jsql/model/injection/strategy/MediatorStrategy::getMultibit → SURVIVED |
return this.multibit; |
237 | } | |
238 | ||
239 | public AbstractStrategy getTime() { | |
240 |
1
1. getTime : replaced return value with null for com/jsql/model/injection/strategy/MediatorStrategy::getTime → NO_COVERAGE |
return this.time; |
241 | } | |
242 | ||
243 | public AbstractStrategy getStack() { | |
244 |
1
1. getStack : replaced return value with null for com/jsql/model/injection/strategy/MediatorStrategy::getStack → NO_COVERAGE |
return this.stack; |
245 | } | |
246 | ||
247 | public List<AbstractStrategy> getStrategies() { | |
248 |
1
1. getStrategies : replaced return value with Collections.emptyList for com/jsql/model/injection/strategy/MediatorStrategy::getStrategies → NO_COVERAGE |
return this.strategies; |
249 | } | |
250 | ||
251 | public AbstractStrategy getStrategy() { | |
252 |
1
1. getStrategy : replaced return value with null for com/jsql/model/injection/strategy/MediatorStrategy::getStrategy → SURVIVED |
return this.strategy; |
253 | } | |
254 | ||
255 | public void setStrategy(AbstractStrategy strategy) { | |
256 | this.strategy = strategy; | |
257 | } | |
258 | ||
259 | public AbstractStrategy getBlindBin() { | |
260 |
1
1. getBlindBin : replaced return value with null for com/jsql/model/injection/strategy/MediatorStrategy::getBlindBin → NO_COVERAGE |
return this.blindBin; |
261 | } | |
262 | } | |
Mutations | ||
58 |
1.1 |
|
60 |
1.1 |
|
62 |
1.1 |
|
65 |
1.1 |
|
79 |
1.1 |
|
80 |
1.1 |
|
94 |
1.1 |
|
100 |
1.1 |
|
118 |
1.1 |
|
138 |
1.1 |
|
146 |
1.1 |
|
152 |
1.1 |
|
155 |
1.1 |
|
160 |
1.1 |
|
163 |
1.1 |
|
169 |
1.1 |
|
174 |
1.1 |
|
175 |
1.1 |
|
176 |
1.1 |
|
178 |
1.1 |
|
183 |
1.1 |
|
186 |
1.1 |
|
189 |
1.1 |
|
190 |
1.1 |
|
191 |
1.1 |
|
194 |
1.1 |
|
195 |
1.1 |
|
196 |
1.1 |
|
197 |
1.1 |
|
198 |
1.1 |
|
199 |
1.1 |
|
200 |
1.1 |
|
202 |
1.1 |
|
205 |
1.1 |
|
210 |
1.1 |
|
213 |
1.1 |
|
220 |
1.1 |
|
224 |
1.1 |
|
228 |
1.1 |
|
232 |
1.1 |
|
236 |
1.1 |
|
240 |
1.1 |
|
244 |
1.1 |
|
248 |
1.1 |
|
252 |
1.1 |
|
260 |
1.1 |