InjectionCharInsertion.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.AbstractCallableBit;
6
import com.jsql.model.injection.strategy.blind.callable.CallableCharInsertion;
7
import com.jsql.model.injection.strategy.blind.patch.Diff;
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 InjectionCharInsertion {
24
    
25
    private static final Logger LOGGER = LogManager.getRootLogger();
26
27
    // Source code of the FALSE web page (e.g. ?id=-123456789)
28
    private String blankFalseMark;
29
30
    /**
31
     * List of string differences found in all the FALSE queries, compared
32
     * to the reference page (aka opcodes). 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> constantTrueMark = new ArrayList<>();
37
    protected final InjectionModel injectionModel;
38
    private final String prefixSuffix;
39
    private final List<String> falsy;
40
    
41
    /**
42
     * Create blind attack initialization.
43
     * If every false test are not in true mark and every true test are in
44
     * true test, then blind attack is confirmed.
45
     */
46
    public InjectionCharInsertion(InjectionModel injectionModel, String falseCharInsertion, String prefixSuffix) {
47
        this.injectionModel = injectionModel;
48
        this.prefixSuffix = prefixSuffix;
49
        
50
        List<String> truthy = this.injectionModel.getMediatorEngine().getEngine().instance().getTruthyBit();
51
        this.falsy = this.injectionModel.getMediatorEngine().getEngine().instance().getFalsyBit();
52
        
53
        // No blind
54 2 1. <init> : negated conditional → NO_COVERAGE
2. <init> : negated conditional → NO_COVERAGE
        if (truthy.isEmpty() || this.injectionModel.isStoppedByUser()) {
55
            return;
56
        }
57
        
58
        // Call the SQL request which must be FALSE (usually ?id=-123456879)
59
        this.blankFalseMark = this.callUrl(falseCharInsertion, "prefix:" + prefixSuffix);
60
61
        // Concurrent calls to the FALSE statements,
62
        // it will use inject() from the model
63
        ExecutorService taskExecutor = this.injectionModel.getMediatorUtils().threadUtil().getExecutor("CallableCharInsertionTagTrue");
64
        Collection<CallableCharInsertion> listCallableTagTrue = new ArrayList<>();
65
        
66
        for (String urlTest: truthy) {
67
            listCallableTagTrue.add(
68
                new CallableCharInsertion(
69
                    prefixSuffix.replace(InjectionModel.STAR, String.join(
70
                        StringUtils.SPACE,
71
                        // todo should also work with AND
72
                        StringUtils.SPACE + this.injectionModel.getMediatorEngine().getEngine().instance().getModelYaml().getStrategy().getBinary().getModeOr(),
73
                        urlTest
74
                    )),
75
                    this,
76
                    "prefix#true"
77
                )
78
            );
79
        }
80
        
81
        // Delete junk from the results of FALSE statements,
82
        // keep only opcodes found in each and every FALSE pages.
83
        // Allow the user to stop the loop
84
        try {
85
            List<Future<CallableCharInsertion>> listTagTrue = taskExecutor.invokeAll(listCallableTagTrue);
86 1 1. <init> : removed call to com/jsql/util/ThreadUtil::shutdown → NO_COVERAGE
            this.injectionModel.getMediatorUtils().threadUtil().shutdown(taskExecutor);
87 2 1. <init> : changed conditional boundary → NO_COVERAGE
2. <init> : negated conditional → NO_COVERAGE
            for (var i = 1 ; i < listTagTrue.size() ; i++) {
88 1 1. <init> : negated conditional → NO_COVERAGE
                if (this.injectionModel.isStoppedByUser()) {
89
                    return;
90
                }
91
92 1 1. <init> : negated conditional → NO_COVERAGE
                if (this.constantTrueMark.isEmpty()) {
93
                    this.constantTrueMark = listTagTrue.get(i).get().getOpcodes();
94
                } else {
95
                    this.constantTrueMark.retainAll(listTagTrue.get(i).get().getOpcodes());
96
                }
97
            }
98
        } catch (ExecutionException e) {
99
            LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
100
        } catch (InterruptedException e) {
101
            LOGGER.log(LogLevelUtil.IGNORE, e, e);
102 1 1. <init> : removed call to java/lang/Thread::interrupt → NO_COVERAGE
            Thread.currentThread().interrupt();
103
        }
104
        
105 1 1. <init> : removed call to com/jsql/model/injection/strategy/blind/InjectionCharInsertion::initFalseMarks → NO_COVERAGE
        this.initFalseMarks();
106
    }
107
    
108
    private void initFalseMarks() {
109
        // Concurrent calls to the TRUE statements,
110
        // it will use inject() from the model.
111
        ExecutorService taskExecutor = this.injectionModel.getMediatorUtils().threadUtil().getExecutor("CallableGetCharInsertionTagFalse");
112
        Collection<CallableCharInsertion> listCallableTagFalse = new ArrayList<>();
113
        
114
        for (String urlTest: this.falsy) {
115
            listCallableTagFalse.add(
116
                new CallableCharInsertion(
117
                    this.prefixSuffix.replace(InjectionModel.STAR, String.join(
118
                        StringUtils.SPACE,
119
                        StringUtils.SPACE + this.injectionModel.getMediatorEngine().getEngine().instance().getModelYaml().getStrategy().getBinary().getModeOr(),
120
                        urlTest
121
                    )),
122
                    this,
123
                    "prefix#false"
124
                )
125
            );
126
        }
127
        
128
        // Remove TRUE opcodes in the FALSE opcodes, because
129
        // a significant FALSE statement shouldn't contain any TRUE opcode.
130
        // Allow the user to stop the loop.
131
        try {
132
            List<Future<CallableCharInsertion>> listTagFalse = taskExecutor.invokeAll(listCallableTagFalse);
133 1 1. initFalseMarks : removed call to com/jsql/util/ThreadUtil::shutdown → NO_COVERAGE
            this.injectionModel.getMediatorUtils().threadUtil().shutdown(taskExecutor);
134
        
135
            for (Future<CallableCharInsertion> falseTag: listTagFalse) {
136 1 1. initFalseMarks : negated conditional → NO_COVERAGE
                if (this.injectionModel.isStoppedByUser()) {
137
                    return;
138
                }
139
                this.constantTrueMark.removeAll(falseTag.get().getOpcodes());
140
            }
141
        } catch (ExecutionException e) {
142
            LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
143
        } catch (InterruptedException e) {
144
            LOGGER.log(LogLevelUtil.IGNORE, e, e);
145 1 1. initFalseMarks : removed call to java/lang/Thread::interrupt → NO_COVERAGE
            Thread.currentThread().interrupt();
146
        }
147
    }
148
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 blindTest = new CallableCharInsertion(
154
            this.prefixSuffix.replace(InjectionModel.STAR, String.join(
155
                StringUtils.SPACE,
156
                StringUtils.SPACE + this.injectionModel.getMediatorEngine().getEngine().instance().getModelYaml().getStrategy().getBinary().getModeOr(),
157
                this.injectionModel.getMediatorEngine().getEngine().instance().sqlBlindConfirm()
158
            )),
159
            this,
160
            "prefix#confirm"
161
        );
162
        try {
163
            blindTest.call();
164
        } catch (Exception e) {
165
            LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
166
        }
167 3 1. isInjectable : replaced boolean return with true for com/jsql/model/injection/strategy/blind/InjectionCharInsertion::isInjectable → NO_COVERAGE
2. isInjectable : negated conditional → NO_COVERAGE
3. isInjectable : negated conditional → NO_COVERAGE
        return blindTest.isTrue() && !this.constantTrueMark.isEmpty();
168
    }
169
    
170
    public String callUrl(String urlString, String metadataInjectionProcess) {
171 1 1. callUrl : replaced return value with "" for com/jsql/model/injection/strategy/blind/InjectionCharInsertion::callUrl → NO_COVERAGE
        return this.injectionModel.injectWithoutIndex(urlString, metadataInjectionProcess);
172
    }
173
174
    public String callUrl(String urlString, String metadataInjectionProcess, AbstractCallableBit<?> callableBoolean) {
175 1 1. callUrl : replaced return value with "" for com/jsql/model/injection/strategy/blind/InjectionCharInsertion::callUrl → NO_COVERAGE
        return this.injectionModel.injectWithoutIndex(urlString, metadataInjectionProcess, callableBoolean);
176
    }
177
178
179
    // Getter
180
181
    public String getBlankFalseMark() {
182 1 1. getBlankFalseMark : replaced return value with "" for com/jsql/model/injection/strategy/blind/InjectionCharInsertion::getBlankFalseMark → NO_COVERAGE
        return this.blankFalseMark;
183
    }
184
    
185
    public List<Diff> getConstantTrueMark() {
186 1 1. getConstantTrueMark : replaced return value with Collections.emptyList for com/jsql/model/injection/strategy/blind/InjectionCharInsertion::getConstantTrueMark → NO_COVERAGE
        return this.constantTrueMark;
187
    }
188
}

Mutations

54

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

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

86

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

87

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

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

88

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

92

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

102

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

105

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

133

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

136

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

145

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

150

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

167

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

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

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

171

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

175

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

182

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

186

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

Active mutators

Tests examined


Report generated by PIT 1.22.1