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