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

Mutations

64

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

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

99

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

100

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

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

101

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

105

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

115

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

118

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

147

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

150

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

159

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

164

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

182

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

186

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

190

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

197

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

201

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