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.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;  // matching index
29
    protected String sourceIndexesFound = StringUtils.EMPTY;  // matching page source
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 1 1. checkApplicability : negated conditional → NO_COVERAGE
        if (this.injectionModel.getMediatorUtils().preferencesUtil().isStrategyUnionDisabled()) {
41
            LOGGER.log(LogLevelUtil.CONSOLE_INFORM, AbstractStrategy.FORMAT_SKIP_STRATEGY_DISABLED, this.getName());
42
            return;
43
        }
44
45 1 1. checkApplicability : removed call to com/jsql/model/injection/strategy/StrategyUnion::logChecking → NO_COVERAGE
        this.logChecking();
46
47
        // Define visibleIndex, i.e, 2 in "...union select 1,2,...", if 2 is found in HTML body
48
        this.indexesInUrl = new SuspendableGetIndexes(this.injectionModel).run();
49 1 1. checkApplicability : negated conditional → NO_COVERAGE
        if (StringUtils.isNotEmpty(this.indexesInUrl)) {
50
            this.visibleIndex = this.getVisibleIndex(this.sourceIndexesFound);
51
        }
52
        
53 1 1. checkApplicability : negated conditional → NO_COVERAGE
        this.isApplicable = StringUtils.isNotEmpty(this.indexesInUrl)
54 2 1. checkApplicability : changed conditional boundary → NO_COVERAGE
2. checkApplicability : negated conditional → NO_COVERAGE
            && Integer.parseInt(this.injectionModel.getMediatorStrategy().getUnion().getPerformanceLength()) > 0
55 1 1. checkApplicability : negated conditional → NO_COVERAGE
            && StringUtils.isNotBlank(this.visibleIndex);
56
        
57 1 1. checkApplicability : negated conditional → NO_COVERAGE
        if (this.isApplicable) {
58
            LOGGER.log(
59
                LogLevelUtil.CONSOLE_SUCCESS,
60
                "{} [{}] at index [{}] showing [{}] characters",
61 1 1. lambda$checkApplicability$0 : replaced return value with null for com/jsql/model/injection/strategy/StrategyUnion::lambda$checkApplicability$0 → NO_COVERAGE
                () -> I18nUtil.valueByKey(AbstractStrategy.KEY_LOG_VULNERABLE),
62
                this::getName,
63 1 1. lambda$checkApplicability$1 : replaced return value with null for com/jsql/model/injection/strategy/StrategyUnion::lambda$checkApplicability$1 → NO_COVERAGE
                () -> this.visibleIndex,
64 1 1. lambda$checkApplicability$2 : replaced return value with null for com/jsql/model/injection/strategy/StrategyUnion::lambda$checkApplicability$2 → NO_COVERAGE
                () -> this.performanceLength
65
            );
66 1 1. checkApplicability : removed call to com/jsql/model/injection/strategy/StrategyUnion::allow → NO_COVERAGE
            this.allow();
67
        } else {
68 1 1. checkApplicability : removed call to com/jsql/model/injection/strategy/StrategyUnion::unallow → NO_COVERAGE
            this.unallow();
69
        }
70
    }
71
72
    @Override
73
    public void allow(int... i) {
74 1 1. allow : removed call to com/jsql/model/InjectionModel::appendAnalysisReport → NO_COVERAGE
        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 1 1. allow : removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE
        this.injectionModel.sendToViews(new Seal.MarkStrategyVulnerable(this));
82
    }
83
84
    @Override
85
    public void unallow(int... i) {
86 1 1. unallow : removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE
        this.injectionModel.sendToViews(new Seal.MarkStrategyInvulnerable(this));
87
    }
88
89
    @Override
90
    public String inject(String sqlQuery, String startPosition, AbstractSuspendable stoppable, String metadataInjectionProcess) {
91 1 1. inject : replaced return value with "" for com/jsql/model/injection/strategy/StrategyUnion::inject → NO_COVERAGE
        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 2 1. activateWhenApplicable : negated conditional → NO_COVERAGE
2. activateWhenApplicable : negated conditional → NO_COVERAGE
        if (this.injectionModel.getMediatorStrategy().getStrategy() == null && this.isApplicable()) {
100
            LOGGER.log(
101
                LogLevelUtil.CONSOLE_INFORM,
102
                "{} [{}]",
103 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"),
104
                this::getName
105
            );
106 1 1. activateWhenApplicable : removed call to com/jsql/model/injection/strategy/MediatorStrategy::setStrategy → NO_COVERAGE
            this.injectionModel.getMediatorStrategy().setStrategy(this);
107 1 1. activateWhenApplicable : removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE
            this.injectionModel.sendToViews(new Seal.ActivateStrategy(this));
108
        }
109
    }
110
    
111
    /**
112
     * Runnable class, search the most efficient index.<br>
113
     * Some indexes will display a lots of characters, others won't,
114
     * so sort them by order of efficiency:<br>
115
     * find the one that displays the most number of characters.
116
     * @return Integer index with most efficiency and visible in source code
117
     */
118
    public String getVisibleIndex(String firstSuccessPageSource) {
119
        // Parse all indexes found
120
        // Fix #4007 (initialize firstSuccessPageSource to empty String instead of null)
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 1 1. getVisibleIndex : negated conditional → NO_COVERAGE
        while (regexSearch.find()) {
126
            listFoundIndexes.add(regexSearch.group(1));
127
        }
128
        String[] arrayFoundIndexes = listFoundIndexes.toArray(new String[0]);
129
130
        // Replace correct indexes from 1337(index)7331 to
131
        // ==> ${lead}(index)######...######
132
        // Search for index that displays the most #
133
        String performanceQuery = this.injectionModel.getMediatorEngine().getEngine().instance().sqlCapacity(arrayFoundIndexes);
134
        String performanceSourcePage = this.injectionModel.injectWithoutIndex(performanceQuery, "union#size");
135
136
        // Build a 2D array of string with:
137
        //     column 1: index
138
        //     column 2: # found, so #######...#######
139
        regexSearch = Pattern.compile("(?s)"+ DataAccess.LEAD +"(\\d+)("+ EngineYaml.CALIBRATOR_SQL +"+)").matcher(performanceSourcePage);
140
        List<String[]> performanceResults = new ArrayList<>();
141 1 1. getVisibleIndex : negated conditional → NO_COVERAGE
        while (regexSearch.find()) {
142
            performanceResults.add(new String[]{regexSearch.group(1), regexSearch.group(2)});
143
        }
144 1 1. getVisibleIndex : negated conditional → NO_COVERAGE
        if (performanceResults.isEmpty()) {
145
            this.performanceLength = "0";
146 1 1. getVisibleIndex : replaced return value with "" for com/jsql/model/injection/strategy/StrategyUnion::getVisibleIndex → NO_COVERAGE
            return null;
147
        }
148
        
149
        // Switch from previous array to 2D integer array
150
        // column 1: length of #######...#######
151
        // column 2: index
152
        var lengthFields = new Integer[performanceResults.size()][2];
153 2 1. getVisibleIndex : negated conditional → NO_COVERAGE
2. getVisibleIndex : changed conditional boundary → NO_COVERAGE
        for (var i = 0 ; i < performanceResults.size() ; i++) {
154
            lengthFields[i] = new Integer[] {
155
                performanceResults.get(i)[1].length()  // size of # range
156 1 1. getVisibleIndex : Replaced integer addition with subtraction → NO_COVERAGE
                + performanceResults.get(i)[0].length(),  // size of integer index
157
                Integer.parseInt(performanceResults.get(i)[0])
158
            };
159
        }
160
161
        // Sort by length of #######...#######
162 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]));
163 1 1. getVisibleIndex : Replaced integer subtraction with addition → NO_COVERAGE
        Integer[] bestLengthFields = lengthFields[lengthFields.length - 1];
164
        this.performanceLength = bestLengthFields[0].toString();
165
166
        // Make url shorter, replace useless indexes from 1337[index]7331 to 1
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
        // Reduce all others indexes
174
        String regexAllIndexesExceptBest = String.format(
175
            EngineYaml.FORMAT_INDEX,
176
            "(?!"+ bestLengthFields[1] +"7331)\\d*"
177
        );
178
        this.indexesInUrl = indexesInUrlFixed.replaceAll(regexAllIndexesExceptBest, "1");
179
180 1 1. getVisibleIndex : replaced return value with "" for com/jsql/model/injection/strategy/StrategyUnion::getVisibleIndex → NO_COVERAGE
        return Integer.toString(bestLengthFields[1]);
181
    }
182
    
183
    
184
    // Getters and setters
185
    
186
    @Override
187
    public String getPerformanceLength() {
188 1 1. getPerformanceLength : replaced return value with "" for com/jsql/model/injection/strategy/StrategyUnion::getPerformanceLength → NO_COVERAGE
        return this.performanceLength;
189
    }
190
    
191
    @Override
192
    public String getName() {
193 1 1. getName : replaced return value with "" for com/jsql/model/injection/strategy/StrategyUnion::getName → NO_COVERAGE
        return "Union";
194
    }
195
196
    public String getVisibleIndex() {
197 1 1. getVisibleIndex : replaced return value with "" for com/jsql/model/injection/strategy/StrategyUnion::getVisibleIndex → NO_COVERAGE
        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 1 1. getNbIndexesFound : replaced int return with 0 for com/jsql/model/injection/strategy/StrategyUnion::getNbIndexesFound → NO_COVERAGE
        return this.nbIndexesFound;
210
    }
211
212
    public void setNbIndexesFound(int nbIndexesFound) {
213
        this.nbIndexesFound = nbIndexesFound;
214
    }
215
216
    public String getIndexesInUrl() {
217 1 1. getIndexesInUrl : replaced return value with "" for com/jsql/model/injection/strategy/StrategyUnion::getIndexesInUrl → NO_COVERAGE
        return this.indexesInUrl;
218
    }
219
220
    public void setIndexesInUrl(String indexesInUrl) {
221
        this.indexesInUrl = indexesInUrl;
222
    }
223
}

Mutations

40

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

45

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

49

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

53

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

54

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

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

55

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

57

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

61

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

63

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

64

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

66

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

68

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

74

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

81

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

86

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

91

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

99

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

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

103

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

106

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

107

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

125

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

141

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

144

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

146

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

153

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

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

156

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

162

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

163

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

180

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

188

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

193

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

197

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

209

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

217

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

Active mutators

Tests examined


Report generated by PIT 1.22.1