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 2.2 |
|
99 |
1.1 |
|
100 |
1.1 2.2 |
|
101 |
1.1 |
|
105 |
1.1 |
|
115 |
1.1 |
|
118 |
1.1 |
|
147 |
1.1 |
|
150 |
1.1 |
|
159 |
1.1 |
|
164 |
1.1 |
|
182 |
1.1 2.2 3.3 |
|
186 |
1.1 |
|
190 |
1.1 |
|
197 |
1.1 |
|
201 |
1.1 |