StrategyUnion.java

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.model.bean.util.Interaction;
6
import com.jsql.model.bean.util.Request;
7
import com.jsql.model.exception.JSqlException;
8
import com.jsql.model.injection.vendor.model.VendorYaml;
9
import com.jsql.model.suspendable.AbstractSuspendable;
10
import com.jsql.model.suspendable.SuspendableGetIndexes;
11
import com.jsql.util.I18nUtil;
12
import com.jsql.util.LogLevelUtil;
13
import com.jsql.util.StringUtil;
14
import org.apache.commons.lang3.StringUtils;
15
import org.apache.logging.log4j.LogManager;
16
import org.apache.logging.log4j.Logger;
17
18
import java.util.ArrayList;
19
import java.util.Arrays;
20
import java.util.Comparator;
21
import java.util.List;
22
import java.util.regex.Pattern;
23
24
public class StrategyUnion extends AbstractStrategy {
25
    
26
    /**
27
     * Log4j logger sent to view.
28
     */
29
    private static final Logger LOGGER = LogManager.getRootLogger();
30
31
    /**
32
     * i.e, 2 in "..union select 1,2,..", if 2 is found in HTML body.
33
     */
34
    protected String visibleIndex;
35
36
    /**
37
     * HTML body of page successfully responding to
38
     * multiple fields selection (select 1,2,3,..).
39
     */
40
    protected String sourceIndexesFound = StringUtils.EMPTY;
41
    private int nbIndexesFound = 0;
42
43
    private String performanceLength = "0";
44
    
45
    public StrategyUnion(InjectionModel injectionModel) {
46
        super(injectionModel);
47
    }
48
49
    @Override
50
    public void checkApplicability() throws JSqlException {
51 1 1. checkApplicability : negated conditional → NO_COVERAGE
        if (this.injectionModel.getMediatorUtils().getPreferencesUtil().isStrategyUnionDisabled()) {
52
            LOGGER.log(LogLevelUtil.CONSOLE_INFORM, AbstractStrategy.FORMAT_SKIP_STRATEGY_DISABLED, this.getName());
53
            return;
54
        }
55
56 1 1. checkApplicability : removed call to com/jsql/model/injection/strategy/StrategyUnion::logChecking → NO_COVERAGE
        this.logChecking();
57
58 1 1. checkApplicability : removed call to com/jsql/model/InjectionModel::setIndexesInUrl → NO_COVERAGE
        this.injectionModel.setIndexesInUrl(new SuspendableGetIndexes(this.injectionModel).run());
59
60
        // Define visibleIndex, i.e, 2 in "..union select 1,2,..", if 2 is found in HTML body
61 1 1. checkApplicability : negated conditional → NO_COVERAGE
        if (StringUtils.isNotEmpty(this.injectionModel.getIndexesInUrl())) {
62
            this.visibleIndex = this.getVisibleIndex(this.sourceIndexesFound);
63
        }
64
        
65 1 1. checkApplicability : negated conditional → NO_COVERAGE
        this.isApplicable = StringUtils.isNotEmpty(this.injectionModel.getIndexesInUrl())
66 2 1. checkApplicability : changed conditional boundary → NO_COVERAGE
2. checkApplicability : negated conditional → NO_COVERAGE
            && Integer.parseInt(this.injectionModel.getMediatorStrategy().getUnion().getPerformanceLength()) > 0
67 1 1. checkApplicability : negated conditional → NO_COVERAGE
            && StringUtils.isNotBlank(this.visibleIndex);
68
        
69 1 1. checkApplicability : negated conditional → NO_COVERAGE
        if (this.isApplicable) {
70
            LOGGER.log(
71
                LogLevelUtil.CONSOLE_SUCCESS,
72
                "{} [{}] at index [{}] showing [{}] characters",
73 1 1. lambda$checkApplicability$0 : replaced return value with null for com/jsql/model/injection/strategy/StrategyUnion::lambda$checkApplicability$0 → NO_COVERAGE
                () -> I18nUtil.valueByKey("LOG_VULNERABLE"),
74
                this::getName,
75 1 1. lambda$checkApplicability$1 : replaced return value with null for com/jsql/model/injection/strategy/StrategyUnion::lambda$checkApplicability$1 → NO_COVERAGE
                () -> this.visibleIndex,
76 1 1. lambda$checkApplicability$2 : replaced return value with null for com/jsql/model/injection/strategy/StrategyUnion::lambda$checkApplicability$2 → NO_COVERAGE
                () -> this.performanceLength
77
            );
78 1 1. checkApplicability : removed call to com/jsql/model/injection/strategy/StrategyUnion::allow → NO_COVERAGE
            this.allow();
79
        } else {
80 1 1. checkApplicability : removed call to com/jsql/model/injection/strategy/StrategyUnion::unallow → NO_COVERAGE
            this.unallow();
81
        }
82
    }
83
84
    @Override
85
    public void allow(int... i) {
86 1 1. allow : removed call to com/jsql/model/InjectionModel::appendAnalysisReport → NO_COVERAGE
        this.injectionModel.appendAnalysisReport(
87
            StringUtil.formatReport(LogLevelUtil.COLOR_BLU, "### Strategy: " + this.getName())
88
            + this.injectionModel.getReportWithIndexes(
89
                this.injectionModel.getMediatorVendor().getVendor().instance().sqlUnion(StringUtil.formatReport(LogLevelUtil.COLOR_GREEN, "<query>"), "0", true),
90
                "metadataInjectionProcess"
91
            )
92
        );
93 1 1. allow : removed call to com/jsql/model/injection/strategy/StrategyUnion::markVulnerability → NO_COVERAGE
        this.markVulnerability(Interaction.MARK_UNION_VULNERABLE);
94
    }
95
96
    @Override
97
    public void unallow(int... i) {
98 1 1. unallow : removed call to com/jsql/model/injection/strategy/StrategyUnion::markVulnerability → NO_COVERAGE
        this.markVulnerability(Interaction.MARK_UNION_INVULNERABLE);
99
    }
100
101
    @Override
102
    public String inject(String sqlQuery, String startPosition, AbstractSuspendable stoppable, String metadataInjectionProcess) {
103 1 1. inject : replaced return value with "" for com/jsql/model/injection/strategy/StrategyUnion::inject → NO_COVERAGE
        return this.injectionModel.injectWithIndexes(
104
            this.injectionModel.getMediatorVendor().getVendor().instance().sqlUnion(sqlQuery, startPosition, false),
105
            metadataInjectionProcess
106
        );
107
    }
108
109
    @Override
110
    public void activateWhenApplicable() {
111 2 1. activateWhenApplicable : negated conditional → NO_COVERAGE
2. activateWhenApplicable : negated conditional → NO_COVERAGE
        if (this.injectionModel.getMediatorStrategy().getStrategy() == null && this.isApplicable()) {
112
            LOGGER.log(
113
                LogLevelUtil.CONSOLE_INFORM,
114
                "{} [{}]",
115 1 1. lambda$activateWhenApplicable$3 : replaced return value with null for com/jsql/model/injection/strategy/StrategyUnion::lambda$activateWhenApplicable$3 → NO_COVERAGE
                () -> I18nUtil.valueByKey("LOG_USING_STRATEGY"),
116
                this::getName
117
            );
118 1 1. activateWhenApplicable : removed call to com/jsql/model/injection/strategy/MediatorStrategy::setStrategy → NO_COVERAGE
            this.injectionModel.getMediatorStrategy().setStrategy(this);
119
120
            var request = new Request();
121 1 1. activateWhenApplicable : removed call to com/jsql/model/bean/util/Request::setMessage → NO_COVERAGE
            request.setMessage(Interaction.MARK_UNION_STRATEGY);
122 1 1. activateWhenApplicable : removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE
            this.injectionModel.sendToViews(request);
123
        }
124
    }
125
    
126
    /**
127
     * Runnable class, search the most efficient index.<br>
128
     * Some indexes will display a lots of characters, others won't,
129
     * so sort them by order of efficiency:<br>
130
     * find the one that displays the most number of characters.
131
     * @return Integer index with most efficiency and visible in source code
132
     */
133
    public String getVisibleIndex(String firstSuccessPageSource) {
134
        // Parse all indexes found
135
        // Fix #4007 (initialize firstSuccessPageSource to empty String instead of null)
136
        String regexAllIndexes = String.format(VendorYaml.FORMAT_INDEX, "(\\d+?)");
137
        var regexSearch = Pattern.compile("(?s)"+ regexAllIndexes).matcher(firstSuccessPageSource);
138
        
139
        List<String> foundIndexes = new ArrayList<>();
140 1 1. getVisibleIndex : negated conditional → NO_COVERAGE
        while (regexSearch.find()) {
141
            foundIndexes.add(regexSearch.group(1));
142
        }
143
144
        String[] indexes = foundIndexes.toArray(new String[0]);
145
146
        // Make url shorter, replace useless indexes from 1337[index]7331 to 1
147
        String regexAllExceptIndexesFound = String.format(
148
            VendorYaml.FORMAT_INDEX,
149
            "(?!"+ String.join("|", indexes) +"7331)\\d*"
150
        );
151
        String indexesInUrl = this.injectionModel.getIndexesInUrl().replaceAll(regexAllExceptIndexesFound, "1");
152
153
        // Replace correct indexes from 1337(index)7331 to
154
        // ==> ${lead}(index)######...######
155
        // Search for index that displays the most #
156
        String performanceQuery = this.injectionModel.getMediatorVendor().getVendor().instance().sqlCapacity(indexes);
157
        String performanceSourcePage = this.injectionModel.injectWithoutIndex(performanceQuery, "union#size");
158
159
        // Build a 2D array of string with:
160
        //     column 1: index
161
        //     column 2: # found, so #######...#######
162
        regexSearch = Pattern.compile("(?s)"+ DataAccess.LEAD +"(\\d+)("+ VendorYaml.CALIBRATOR_SQL +"+)").matcher(performanceSourcePage);
163
        List<String[]> performanceResults = new ArrayList<>();
164 1 1. getVisibleIndex : negated conditional → NO_COVERAGE
        while (regexSearch.find()) {
165
            performanceResults.add(new String[]{regexSearch.group(1), regexSearch.group(2)});
166
        }
167
168 1 1. getVisibleIndex : negated conditional → NO_COVERAGE
        if (performanceResults.isEmpty()) {
169
            this.performanceLength = "0";
170 1 1. getVisibleIndex : replaced return value with "" for com/jsql/model/injection/strategy/StrategyUnion::getVisibleIndex → NO_COVERAGE
            return null;
171
        }
172
        
173
        // Switch from previous array to 2D integer array
174
        //     column 1: length of #######...#######
175
        //     column 2: index
176
        var lengthFields = new Integer[performanceResults.size()][2];
177
        
178 2 1. getVisibleIndex : changed conditional boundary → NO_COVERAGE
2. getVisibleIndex : negated conditional → NO_COVERAGE
        for (var i = 0 ; i < performanceResults.size() ; i++) {
179
            lengthFields[i] = new Integer[] {
180 1 1. getVisibleIndex : Replaced integer addition with subtraction → NO_COVERAGE
                performanceResults.get(i)[1].length() + performanceResults.get(i)[0].length(),
181
                Integer.parseInt(performanceResults.get(i)[0])
182
            };
183
        }
184
185
        // Sort by length of #######...#######
186 2 1. getVisibleIndex : removed call to java/util/Arrays::sort → NO_COVERAGE
2. lambda$getVisibleIndex$4 : replaced Integer return value with 0 for com/jsql/model/injection/strategy/StrategyUnion::lambda$getVisibleIndex$4 → NO_COVERAGE
        Arrays.sort(lengthFields, Comparator.comparing((Integer[] s) -> s[0]));
187 1 1. getVisibleIndex : Replaced integer subtraction with addition → NO_COVERAGE
        Integer[] bestLengthFields = lengthFields[lengthFields.length - 1];
188
        this.performanceLength = bestLengthFields[0].toString();
189
190
        // Reduce all others indexes
191
        String regexAllIndexesExceptBest = String.format(
192
            VendorYaml.FORMAT_INDEX,
193
            "(?!"+ bestLengthFields[1] +"7331)\\d*"
194
        );
195
        indexesInUrl = indexesInUrl.replaceAll(regexAllIndexesExceptBest, "1");
196
        
197 1 1. getVisibleIndex : removed call to com/jsql/model/InjectionModel::setIndexesInUrl → NO_COVERAGE
        this.injectionModel.setIndexesInUrl(indexesInUrl);
198
        
199 1 1. getVisibleIndex : replaced return value with "" for com/jsql/model/injection/strategy/StrategyUnion::getVisibleIndex → NO_COVERAGE
        return Integer.toString(bestLengthFields[1]);
200
    }
201
    
202
    
203
    // Getters and setters
204
    
205
    @Override
206
    public String getPerformanceLength() {
207 1 1. getPerformanceLength : replaced return value with "" for com/jsql/model/injection/strategy/StrategyUnion::getPerformanceLength → NO_COVERAGE
        return this.performanceLength;
208
    }
209
    
210
    @Override
211
    public String getName() {
212 1 1. getName : replaced return value with "" for com/jsql/model/injection/strategy/StrategyUnion::getName → NO_COVERAGE
        return "Union";
213
    }
214
215
    public String getVisibleIndex() {
216 1 1. getVisibleIndex : replaced return value with "" for com/jsql/model/injection/strategy/StrategyUnion::getVisibleIndex → NO_COVERAGE
        return this.visibleIndex;
217
    }
218
219
    public void setVisibleIndex(String visibleIndex) {
220
        this.visibleIndex = visibleIndex;
221
    }
222
223
    public void setSourceIndexesFound(String sourceIndexesFound) {
224
        this.sourceIndexesFound = sourceIndexesFound;
225
    }
226
227
    public int getNbIndexesFound() {
228 1 1. getNbIndexesFound : replaced int return with 0 for com/jsql/model/injection/strategy/StrategyUnion::getNbIndexesFound → NO_COVERAGE
        return this.nbIndexesFound;
229
    }
230
231
    public void setNbIndexesFound(int nbIndexesFound) {
232
        this.nbIndexesFound = nbIndexesFound;
233
    }
234
}

Mutations

51

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

56

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

58

1.1
Location : checkApplicability
Killed by : none
removed call to com/jsql/model/InjectionModel::setIndexesInUrl → NO_COVERAGE

61

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

65

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

66

1.1
Location : checkApplicability
Killed by : none
changed conditional boundary → NO_COVERAGE

2.2
Location : checkApplicability
Killed by : none
negated conditional → NO_COVERAGE

67

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

69

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

73

1.1
Location : lambda$checkApplicability$0
Killed by : none
replaced return value with null for com/jsql/model/injection/strategy/StrategyUnion::lambda$checkApplicability$0 → NO_COVERAGE

75

1.1
Location : lambda$checkApplicability$1
Killed by : none
replaced return value with null for com/jsql/model/injection/strategy/StrategyUnion::lambda$checkApplicability$1 → NO_COVERAGE

76

1.1
Location : lambda$checkApplicability$2
Killed by : none
replaced return value with null for com/jsql/model/injection/strategy/StrategyUnion::lambda$checkApplicability$2 → NO_COVERAGE

78

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

80

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

86

1.1
Location : allow
Killed by : none
removed call to com/jsql/model/InjectionModel::appendAnalysisReport → NO_COVERAGE

93

1.1
Location : allow
Killed by : none
removed call to com/jsql/model/injection/strategy/StrategyUnion::markVulnerability → NO_COVERAGE

98

1.1
Location : unallow
Killed by : none
removed call to com/jsql/model/injection/strategy/StrategyUnion::markVulnerability → NO_COVERAGE

103

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

111

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

2.2
Location : activateWhenApplicable
Killed by : none
negated conditional → NO_COVERAGE

115

1.1
Location : lambda$activateWhenApplicable$3
Killed by : none
replaced return value with null for com/jsql/model/injection/strategy/StrategyUnion::lambda$activateWhenApplicable$3 → NO_COVERAGE

118

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

121

1.1
Location : activateWhenApplicable
Killed by : none
removed call to com/jsql/model/bean/util/Request::setMessage → NO_COVERAGE

122

1.1
Location : activateWhenApplicable
Killed by : none
removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE

140

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

164

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

168

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

170

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

178

1.1
Location : getVisibleIndex
Killed by : none
changed conditional boundary → NO_COVERAGE

2.2
Location : getVisibleIndex
Killed by : none
negated conditional → NO_COVERAGE

180

1.1
Location : getVisibleIndex
Killed by : none
Replaced integer addition with subtraction → NO_COVERAGE

186

1.1
Location : getVisibleIndex
Killed by : none
removed call to java/util/Arrays::sort → NO_COVERAGE

2.2
Location : lambda$getVisibleIndex$4
Killed by : none
replaced Integer return value with 0 for com/jsql/model/injection/strategy/StrategyUnion::lambda$getVisibleIndex$4 → NO_COVERAGE

187

1.1
Location : getVisibleIndex
Killed by : none
Replaced integer subtraction with addition → NO_COVERAGE

197

1.1
Location : getVisibleIndex
Killed by : none
removed call to com/jsql/model/InjectionModel::setIndexesInUrl → NO_COVERAGE

199

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

207

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

212

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

216

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

228

1.1
Location : getNbIndexesFound
Killed by : none
replaced int return with 0 for com/jsql/model/injection/strategy/StrategyUnion::getNbIndexesFound → NO_COVERAGE

Active mutators

Tests examined


Report generated by PIT 1.19.1