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

Mutations

61

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

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

96

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

97

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

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

98

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

102

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

112

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

115

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

144

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

147

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

156

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

161

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

179

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

183

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

187

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

194

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

198

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