InjectionBlindBit.java

1
package com.jsql.model.injection.strategy.blind;
2
3
import com.jsql.model.InjectionModel;
4
import com.jsql.model.exception.StoppedByUserSlidingException;
5
import com.jsql.model.injection.strategy.blind.callable.CallableBlindBit;
6
import com.jsql.model.injection.strategy.blind.patch.Diff;
7
import com.jsql.model.injection.strategy.blind.patch.DiffMatchPatch;
8
import com.jsql.util.LogLevelUtil;
9
import org.apache.commons.lang3.StringUtils;
10
import org.apache.logging.log4j.LogManager;
11
import org.apache.logging.log4j.Logger;
12
13
import java.util.ArrayList;
14
import java.util.Collection;
15
import java.util.List;
16
import java.util.concurrent.ExecutionException;
17
import java.util.concurrent.ExecutorService;
18
import java.util.concurrent.Future;
19
20
/**
21
 * A blind attack class using concurrent threads.
22
 */
23
public class InjectionBlindBit extends AbstractInjectionMonobit<CallableBlindBit> {
24
25
    private static final Logger LOGGER = LogManager.getRootLogger();
26
27
    private String sourceReferencePage;  // Source code of the TRUE web page (usually ?id=1)
28
29
    /**
30
     * List of string differences found in all the FALSE queries, compared
31
     * to the reference page. Each FALSE pages should contain
32
     * at least one same string, which shouldn't be present in all
33
     * the TRUE queries.
34
     */
35
    private List<Diff> falseDiffs = new ArrayList<>();
36
    private List<Diff> trueDiffs = new ArrayList<>();
37
38
    /**
39
     * Create blind attack initialization.
40
     * If every false diffs are not in true diffs and every true diffs are in
41
     * true diffs, then Blind attack is confirmed.
42
     */
43
    public InjectionBlindBit(InjectionModel injectionModel, BlindOperator blindOperator) {
44
        super(injectionModel, blindOperator);
45
46
        List<String> falsys = this.injectionModel.getMediatorVendor().getVendor().instance().getFalsyBit();
47 2 1. <init> : negated conditional → NO_COVERAGE
2. <init> : negated conditional → NO_COVERAGE
        if (falsys.isEmpty() || this.injectionModel.isStoppedByUser()) {
48
            return;
49
        }
50
        
51
        // Call the SQL request which must be TRUE (usually ?id=1)
52
        this.sourceReferencePage = this.callUrl(StringUtils.EMPTY, "bit#ref:"+ blindOperator.toString().toLowerCase());
53
54
        // Concurrent calls to the FALSE statements,
55
        // it will use inject() from the model
56
        ExecutorService taskExecutor = this.injectionModel.getMediatorUtils().getThreadUtil().getExecutor("CallableGetBlindBitTagFalse");
57
        Collection<CallableBlindBit> callablesFalsys = new ArrayList<>();
58
        for (String falsy: falsys) {
59
            callablesFalsys.add(new CallableBlindBit(
60
                falsy,
61
                injectionModel,
62
                this,
63
                blindOperator,
64
                "bit#falsy"
65
            ));
66
        }
67
        
68
        // Delete junk from the results of FALSE statements,
69
        // keep only diffs found in each and every FALSE pages.
70
        // Allow the user to stop the loop
71
        try {
72
            List<Future<CallableBlindBit>> futuresFalsys = taskExecutor.invokeAll(callablesFalsys);
73 1 1. <init> : removed call to com/jsql/util/ThreadUtil::shutdown → NO_COVERAGE
            this.injectionModel.getMediatorUtils().getThreadUtil().shutdown(taskExecutor);
74
            for (Future<CallableBlindBit> futureFalsy: futuresFalsys) {
75 1 1. <init> : negated conditional → NO_COVERAGE
                if (this.injectionModel.isStoppedByUser()) {
76
                    return;
77
                }
78 1 1. <init> : negated conditional → NO_COVERAGE
                if (this.falseDiffs.isEmpty()) {
79
                    this.falseDiffs = futureFalsy.get().getDiffsWithReference();  // Init diffs
80
                } else {
81
                    this.falseDiffs.retainAll(futureFalsy.get().getDiffsWithReference());  // Clean un-matching diffs
82
                }
83
            }
84
        } catch (ExecutionException e) {
85
            LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
86
        } catch (InterruptedException e) {
87
            LOGGER.log(LogLevelUtil.IGNORE, e, e);
88 1 1. <init> : removed call to java/lang/Thread::interrupt → NO_COVERAGE
            Thread.currentThread().interrupt();
89
        }
90
91 1 1. <init> : negated conditional → NO_COVERAGE
        if (this.injectionModel.isStoppedByUser()) {
92
            return;
93
        }
94
        
95 1 1. <init> : removed call to com/jsql/model/injection/strategy/blind/InjectionBlindBit::cleanTrueDiffs → NO_COVERAGE
        this.cleanTrueDiffs(injectionModel, blindOperator);
96
    }
97
98
    private void cleanTrueDiffs(InjectionModel injectionModel, BlindOperator blindOperator) {
99
        ExecutorService taskExecutor = this.injectionModel.getMediatorUtils().getThreadUtil().getExecutor("CallableGetBlindBitTagTrue");
100
        Collection<CallableBlindBit> callablesTruthys = new ArrayList<>();
101
        List<String> truthys = this.injectionModel.getMediatorVendor().getVendor().instance().getTruthyBit();
102
        for (String truthy: truthys) {
103
            callablesTruthys.add(new CallableBlindBit(
104
                truthy,
105
                injectionModel,
106
                this,
107
                blindOperator,
108
                "bit#truthy"
109
            ));
110
        }
111
112
        // Remove TRUE diffs in the FALSE diffs as FALSE statement shouldn't contain any TRUE diff.
113
        try {
114
            List<Future<CallableBlindBit>> futuresTruthys = taskExecutor.invokeAll(callablesTruthys);
115 1 1. cleanTrueDiffs : removed call to com/jsql/util/ThreadUtil::shutdown → NO_COVERAGE
            this.injectionModel.getMediatorUtils().getThreadUtil().shutdown(taskExecutor);
116
            for (Future<CallableBlindBit> futureTruthy: futuresTruthys) {
117 1 1. cleanTrueDiffs : negated conditional → NO_COVERAGE
                if (this.injectionModel.isStoppedByUser()) {
118
                    return;
119
                }
120 1 1. cleanTrueDiffs : negated conditional → NO_COVERAGE
                if (this.trueDiffs.isEmpty()) {
121
                    this.trueDiffs = futureTruthy.get().getDiffsWithReference();  // Init diffs
122
                } else {
123
                    this.trueDiffs.retainAll(futureTruthy.get().getDiffsWithReference());  // Clean un-matching diffs
124
                }
125
                this.falseDiffs.removeAll(futureTruthy.get().getDiffsWithReference());
126
            }
127
        } catch (ExecutionException e) {
128
            LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
129
        } catch (InterruptedException e) {
130
            LOGGER.log(LogLevelUtil.IGNORE, e, e);
131 1 1. cleanTrueDiffs : removed call to java/lang/Thread::interrupt → NO_COVERAGE
            Thread.currentThread().interrupt();
132
        }
133
    }
134
135
    @Override
136
    public CallableBlindBit getCallableBitTest(String sqlQuery, int indexChar, int bit) {
137 1 1. getCallableBitTest : replaced return value with null for com/jsql/model/injection/strategy/blind/InjectionBlindBit::getCallableBitTest → NO_COVERAGE
        return new CallableBlindBit(
138
            sqlQuery,
139
            indexChar,
140
            bit,
141
            this.injectionModel,
142
            this,
143
            this.blindOperator,
144
            "bit#" + indexChar + "~" + bit
145
        );
146
    }
147
148
    @Override
149
    public boolean isInjectable() throws StoppedByUserSlidingException {
150 1 1. isInjectable : negated conditional → NO_COVERAGE
        if (this.injectionModel.isStoppedByUser()) {
151
            throw new StoppedByUserSlidingException();
152
        }
153
        var callable = new CallableBlindBit(
154
            this.injectionModel.getMediatorVendor().getVendor().instance().sqlBlindConfirm(),
155
            this.injectionModel,
156
            this,
157
            this.blindOperator,
158
            "bit#confirm"
159
        );
160
        try {
161
            callable.call();
162
        } catch (Exception e) {
163
            LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
164
        }
165 2 1. isInjectable : replaced boolean return with true for com/jsql/model/injection/strategy/blind/InjectionBlindBit::isInjectable → NO_COVERAGE
2. isInjectable : negated conditional → NO_COVERAGE
        return callable.isTrue()
166
            // when insertionChar = true then pages ref == truthy == falsy == confirm => falsy cleaned empty, truthy with opcode EQUAL not reliable
167 3 1. lambda$isInjectable$0 : negated conditional → NO_COVERAGE
2. lambda$isInjectable$0 : replaced boolean return with true for com/jsql/model/injection/strategy/blind/InjectionBlindBit::lambda$isInjectable$0 → NO_COVERAGE
3. isInjectable : negated conditional → NO_COVERAGE
            && this.trueDiffs.stream().anyMatch(diff -> !DiffMatchPatch.Operation.EQUAL.equals(diff.getOperation()))
168 3 1. lambda$isInjectable$1 : negated conditional → NO_COVERAGE
2. isInjectable : negated conditional → NO_COVERAGE
3. lambda$isInjectable$1 : replaced boolean return with true for com/jsql/model/injection/strategy/blind/InjectionBlindBit::lambda$isInjectable$1 → NO_COVERAGE
            || this.falseDiffs.stream().anyMatch(diff -> !DiffMatchPatch.Operation.EQUAL.equals(diff.getOperation()));
169
    }
170
171
    @Override
172
    public String getInfoMessage() {
173 1 1. getInfoMessage : replaced return value with "" for com/jsql/model/injection/strategy/blind/InjectionBlindBit::getInfoMessage → NO_COVERAGE
        return "- Strategy Blind bit: query True when Diffs are matching " + this.falseDiffs + "\n\n";
174
    }
175
    
176
    
177
    // Getter and setter
178
179
    public String getSourceReferencePage() {
180 1 1. getSourceReferencePage : replaced return value with "" for com/jsql/model/injection/strategy/blind/InjectionBlindBit::getSourceReferencePage → NO_COVERAGE
        return this.sourceReferencePage;
181
    }
182
    
183
    public List<Diff> getFalseDiffs() {
184 1 1. getFalseDiffs : replaced return value with Collections.emptyList for com/jsql/model/injection/strategy/blind/InjectionBlindBit::getFalseDiffs → NO_COVERAGE
        return this.falseDiffs;
185
    }
186
187
    public List<Diff> getTrueDiffs() {
188 1 1. getTrueDiffs : replaced return value with Collections.emptyList for com/jsql/model/injection/strategy/blind/InjectionBlindBit::getTrueDiffs → NO_COVERAGE
        return this.trueDiffs;
189
    }
190
}

Mutations

47

1.1
Location : <init>
Killed by : none
negated conditional → NO_COVERAGE

2.2
Location : <init>
Killed by : none
negated conditional → NO_COVERAGE

73

1.1
Location : <init>
Killed by : none
removed call to com/jsql/util/ThreadUtil::shutdown → NO_COVERAGE

75

1.1
Location : <init>
Killed by : none
negated conditional → NO_COVERAGE

78

1.1
Location : <init>
Killed by : none
negated conditional → NO_COVERAGE

88

1.1
Location : <init>
Killed by : none
removed call to java/lang/Thread::interrupt → NO_COVERAGE

91

1.1
Location : <init>
Killed by : none
negated conditional → NO_COVERAGE

95

1.1
Location : <init>
Killed by : none
removed call to com/jsql/model/injection/strategy/blind/InjectionBlindBit::cleanTrueDiffs → NO_COVERAGE

115

1.1
Location : cleanTrueDiffs
Killed by : none
removed call to com/jsql/util/ThreadUtil::shutdown → NO_COVERAGE

117

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

120

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

131

1.1
Location : cleanTrueDiffs
Killed by : none
removed call to java/lang/Thread::interrupt → NO_COVERAGE

137

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

150

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

165

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

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

167

1.1
Location : lambda$isInjectable$0
Killed by : none
negated conditional → NO_COVERAGE

2.2
Location : lambda$isInjectable$0
Killed by : none
replaced boolean return with true for com/jsql/model/injection/strategy/blind/InjectionBlindBit::lambda$isInjectable$0 → NO_COVERAGE

3.3
Location : isInjectable
Killed by : none
negated conditional → NO_COVERAGE

168

1.1
Location : lambda$isInjectable$1
Killed by : none
negated conditional → NO_COVERAGE

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

3.3
Location : lambda$isInjectable$1
Killed by : none
replaced boolean return with true for com/jsql/model/injection/strategy/blind/InjectionBlindBit::lambda$isInjectable$1 → NO_COVERAGE

173

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

180

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

184

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

188

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

Active mutators

Tests examined


Report generated by PIT 1.22.0