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

Mutations

60

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

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

95

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

96

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

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

97

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

101

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

111

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

114

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

143

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

146

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

155

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

160

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

178

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

182

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

186

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

193

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

197

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