MediatorStrategy.java

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

Mutations

58

1.1
Location : getMeta
Killed by : none
negated conditional → NO_COVERAGE

62

1.1
Location : getMeta
Killed by : none
negated conditional → NO_COVERAGE

64

1.1
Location : getMeta
Killed by : none
negated conditional → NO_COVERAGE

68

1.1
Location : getMeta
Killed by : none
replaced return value with "" for com/jsql/model/injection/strategy/MediatorStrategy::getMeta → NO_COVERAGE

84

1.1
Location : buildPath
Killed by : none
negated conditional → NO_COVERAGE

85

1.1
Location : buildPath
Killed by : none
negated conditional → NO_COVERAGE

100

1.1
Location : buildPath
Killed by : none
replaced return value with "" for com/jsql/model/injection/strategy/MediatorStrategy::buildPath → NO_COVERAGE

107

1.1
Location : encodePath
Killed by : none
negated conditional → NO_COVERAGE

126

1.1
Location : encodePath
Killed by : none
replaced return value with "" for com/jsql/model/injection/strategy/MediatorStrategy::encodePath → NO_COVERAGE

147

1.1
Location : testStrategies
Killed by : none
removed call to com/jsql/model/injection/vendor/MediatorVendor::setVendor → NO_COVERAGE

155

1.1
Location : testStrategies
Killed by : none
negated conditional → NO_COVERAGE

162

1.1
Location : testStrategies
Killed by : none
negated conditional → NO_COVERAGE

166

1.1
Location : testStrategies
Killed by : none
negated conditional → NO_COVERAGE

171

1.1
Location : testStrategies
Killed by : none
negated conditional → NO_COVERAGE

175

1.1
Location : testStrategies
Killed by : none
removed call to com/jsql/util/ConnectionUtil::setUrlBase → NO_COVERAGE

181

1.1
Location : testStrategies
Killed by : none
negated conditional → NO_COVERAGE

187

1.1
Location : testStrategies
Killed by : none
removed call to com/jsql/model/injection/strategy/AbstractStrategy::checkApplicability → NO_COVERAGE

188

1.1
Location : testStrategies
Killed by : none
removed call to com/jsql/model/injection/strategy/AbstractStrategy::checkApplicability → NO_COVERAGE

190

1.1
Location : testStrategies
Killed by : none
negated conditional → NO_COVERAGE

196

1.1
Location : testStrategies
Killed by : none
removed call to com/jsql/model/injection/strategy/AbstractStrategy::checkApplicability → NO_COVERAGE

200

1.1
Location : testStrategies
Killed by : none
removed call to com/jsql/model/injection/strategy/AbstractStrategy::checkApplicability → NO_COVERAGE

203

1.1
Location : testStrategies
Killed by : none
removed call to com/jsql/model/injection/strategy/StrategyInjectionError::checkApplicability → NO_COVERAGE

204

1.1
Location : testStrategies
Killed by : none
removed call to com/jsql/model/injection/strategy/AbstractStrategy::checkApplicability → NO_COVERAGE

205

1.1
Location : testStrategies
Killed by : none
removed call to com/jsql/model/injection/strategy/AbstractStrategy::checkApplicability → NO_COVERAGE

208

1.1
Location : testStrategies
Killed by : none
removed call to com/jsql/model/injection/strategy/AbstractStrategy::activateWhenApplicable → NO_COVERAGE

209

1.1
Location : testStrategies
Killed by : none
removed call to com/jsql/model/injection/strategy/AbstractStrategy::activateWhenApplicable → NO_COVERAGE

210

1.1
Location : testStrategies
Killed by : none
removed call to com/jsql/model/injection/strategy/StrategyInjectionError::activateWhenApplicable → NO_COVERAGE

211

1.1
Location : testStrategies
Killed by : none
removed call to com/jsql/model/injection/strategy/AbstractStrategy::activateWhenApplicable → NO_COVERAGE

212

1.1
Location : testStrategies
Killed by : none
removed call to com/jsql/model/injection/strategy/AbstractStrategy::activateWhenApplicable → NO_COVERAGE

213

1.1
Location : testStrategies
Killed by : none
removed call to com/jsql/model/injection/strategy/AbstractStrategy::activateWhenApplicable → NO_COVERAGE

215

1.1
Location : testStrategies
Killed by : none
negated conditional → NO_COVERAGE

219

1.1
Location : testStrategies
Killed by : none
negated conditional → NO_COVERAGE

224

1.1
Location : testStrategies
Killed by : none
replaced boolean return with true for com/jsql/model/injection/strategy/MediatorStrategy::testStrategies → NO_COVERAGE

227

1.1
Location : testStrategies
Killed by : none
replaced boolean return with false for com/jsql/model/injection/strategy/MediatorStrategy::testStrategies → NO_COVERAGE

234

1.1
Location : getNormal
Killed by : none
replaced return value with null for com/jsql/model/injection/strategy/MediatorStrategy::getNormal → NO_COVERAGE

238

1.1
Location : getSpecificNormal
Killed by : none
replaced return value with null for com/jsql/model/injection/strategy/MediatorStrategy::getSpecificNormal → NO_COVERAGE

242

1.1
Location : getError
Killed by : none
replaced return value with null for com/jsql/model/injection/strategy/MediatorStrategy::getError → NO_COVERAGE

246

1.1
Location : getBlind
Killed by : none
replaced return value with null for com/jsql/model/injection/strategy/MediatorStrategy::getBlind → NO_COVERAGE

250

1.1
Location : getMultibit
Killed by : none
replaced return value with null for com/jsql/model/injection/strategy/MediatorStrategy::getMultibit → SURVIVED

254

1.1
Location : getTime
Killed by : none
replaced return value with null for com/jsql/model/injection/strategy/MediatorStrategy::getTime → NO_COVERAGE

258

1.1
Location : getStacked
Killed by : none
replaced return value with null for com/jsql/model/injection/strategy/MediatorStrategy::getStacked → NO_COVERAGE

262

1.1
Location : getStrategies
Killed by : none
replaced return value with Collections.emptyList for com/jsql/model/injection/strategy/MediatorStrategy::getStrategies → NO_COVERAGE

266

1.1
Location : getStrategy
Killed by : none
replaced return value with null for com/jsql/model/injection/strategy/MediatorStrategy::getStrategy → SURVIVED

Active mutators

Tests examined


Report generated by PIT 1.16.1