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

Mutations

48

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

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

74

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

76

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

79

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

89

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

92

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

96

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

116

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

118

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

121

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

132

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

138

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

151

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

166

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

168

1.1
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

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

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

169

1.1
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

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

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

174

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

181

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

185

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

189

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.19.1