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.patch.Diff; | |
6 | import com.jsql.util.LogLevelUtil; | |
7 | import org.apache.commons.lang3.StringUtils; | |
8 | import org.apache.logging.log4j.LogManager; | |
9 | import org.apache.logging.log4j.Logger; | |
10 | ||
11 | import java.util.ArrayList; | |
12 | import java.util.Collection; | |
13 | import java.util.List; | |
14 | import java.util.concurrent.ExecutionException; | |
15 | import java.util.concurrent.ExecutorService; | |
16 | import java.util.concurrent.Future; | |
17 | ||
18 | /** | |
19 | * A blind attack class using concurrent threads. | |
20 | */ | |
21 | public class InjectionBlind extends AbstractInjectionMonobit<CallableBlind> { | |
22 | | |
23 | /** | |
24 | * Log4j logger sent to view. | |
25 | */ | |
26 | private static final Logger LOGGER = LogManager.getRootLogger(); | |
27 | ||
28 | // Source code of the TRUE web page (usually ?id=1) | |
29 | private String sourceReferencePage; | |
30 | ||
31 | /** | |
32 | * List of string differences found in all the FALSE queries, compared | |
33 | * to the reference page. 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> falseDiffs = new ArrayList<>(); | |
38 | ||
39 | /** | |
40 | * Create blind attack initialization. | |
41 | * If every false diffs are not in true diffs and every true diffs are in | |
42 | * true diffs, then Blind attack is confirmed. | |
43 | * @param blindMode | |
44 | */ | |
45 | public InjectionBlind(InjectionModel injectionModel, BooleanMode blindMode) { | |
46 | | |
47 | super(injectionModel, blindMode); | |
48 | | |
49 | // No blind | |
50 |
2
1. <init> : negated conditional → NO_COVERAGE 2. <init> : negated conditional → NO_COVERAGE |
if (this.falsy.isEmpty() || this.injectionModel.isStoppedByUser()) { |
51 | return; | |
52 | } | |
53 | | |
54 | // Call the SQL request which must be TRUE (usually ?id=1) | |
55 | this.sourceReferencePage = this.callUrl(StringUtils.EMPTY, "blind#ref"); | |
56 | ||
57 | // Concurrent calls to the FALSE statements, | |
58 | // it will use inject() from the model | |
59 | ExecutorService taskExecutor = this.injectionModel.getMediatorUtils().getThreadUtil().getExecutor("CallableGetBlindTagFalse"); | |
60 | Collection<CallableBlind> callablesFalseTest = new ArrayList<>(); | |
61 | | |
62 | for (String falseTest: this.falsy) { | |
63 | callablesFalseTest.add(new CallableBlind( | |
64 | falseTest, | |
65 | injectionModel, | |
66 | this, | |
67 | blindMode, | |
68 | "blind#falsy" | |
69 | )); | |
70 | } | |
71 | | |
72 | // Delete junk from the results of FALSE statements, | |
73 | // keep only diffs found in each and every FALSE pages. | |
74 | // Allow the user to stop the loop | |
75 | try { | |
76 | List<Future<CallableBlind>> futuresFalseTest = taskExecutor.invokeAll(callablesFalseTest); | |
77 |
1
1. <init> : removed call to com/jsql/util/ThreadUtil::shutdown → NO_COVERAGE |
this.injectionModel.getMediatorUtils().getThreadUtil().shutdown(taskExecutor); |
78 | ||
79 | for (Future<CallableBlind> futureFalseTest: futuresFalseTest) { | |
80 | ||
81 |
1
1. <init> : negated conditional → NO_COVERAGE |
if (this.injectionModel.isStoppedByUser()) { |
82 | return; | |
83 | } | |
84 | ||
85 |
1
1. <init> : negated conditional → NO_COVERAGE |
if (this.falseDiffs.isEmpty()) { |
86 | this.falseDiffs = futureFalseTest.get().getDiffsWithReference(); // Init diffs | |
87 | } else { | |
88 | this.falseDiffs.retainAll(futureFalseTest.get().getDiffsWithReference()); // Clean un-matching diffs | |
89 | } | |
90 | } | |
91 | } catch (ExecutionException e) { | |
92 | LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e); | |
93 | } catch (InterruptedException e) { | |
94 | | |
95 | LOGGER.log(LogLevelUtil.IGNORE, e, e); | |
96 |
1
1. <init> : removed call to java/lang/Thread::interrupt → NO_COVERAGE |
Thread.currentThread().interrupt(); |
97 | } | |
98 | ||
99 |
1
1. <init> : negated conditional → NO_COVERAGE |
if (this.injectionModel.isStoppedByUser()) { |
100 | return; | |
101 | } | |
102 | | |
103 |
1
1. <init> : removed call to com/jsql/model/injection/strategy/blind/InjectionBlind::cleanTrueDiffs → NO_COVERAGE |
this.cleanTrueDiffs(injectionModel, blindMode); |
104 | } | |
105 | ||
106 | private void cleanTrueDiffs(InjectionModel injectionModel, BooleanMode blindMode) { | |
107 | | |
108 | // Concurrent calls to the TRUE statements, | |
109 | // it will use inject() from the model. | |
110 | ExecutorService taskExecutor = this.injectionModel.getMediatorUtils().getThreadUtil().getExecutor("CallableGetBlindTagTrue"); | |
111 | ||
112 | Collection<CallableBlind> callablesTrueTest = new ArrayList<>(); | |
113 | | |
114 | for (String trueTest: this.truthy) { | |
115 | callablesTrueTest.add(new CallableBlind( | |
116 | trueTest, | |
117 | injectionModel, | |
118 | this, | |
119 | blindMode, | |
120 | "blind#truthy" | |
121 | )); | |
122 | } | |
123 | | |
124 | // Remove TRUE diffs in the FALSE diffs, because | |
125 | // a significant FALSE statement shouldn't contain any TRUE diff. | |
126 | // Allow the user to stop the loop. | |
127 | try { | |
128 | List<Future<CallableBlind>> futuresTrueTest = taskExecutor.invokeAll(callablesTrueTest); | |
129 |
1
1. cleanTrueDiffs : removed call to com/jsql/util/ThreadUtil::shutdown → NO_COVERAGE |
this.injectionModel.getMediatorUtils().getThreadUtil().shutdown(taskExecutor); |
130 | | |
131 | for (Future<CallableBlind> futureTrueTest: futuresTrueTest) { | |
132 | | |
133 |
1
1. cleanTrueDiffs : negated conditional → NO_COVERAGE |
if (this.injectionModel.isStoppedByUser()) { |
134 | return; | |
135 | } | |
136 | this.falseDiffs.removeAll(futureTrueTest.get().getDiffsWithReference()); | |
137 | } | |
138 | } catch (ExecutionException e) { | |
139 | LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e); | |
140 | } catch (InterruptedException e) { | |
141 | | |
142 | LOGGER.log(LogLevelUtil.IGNORE, e, e); | |
143 |
1
1. cleanTrueDiffs : removed call to java/lang/Thread::interrupt → NO_COVERAGE |
Thread.currentThread().interrupt(); |
144 | } | |
145 | } | |
146 | ||
147 | @Override | |
148 | public CallableBlind getCallableBitTest(String sqlQuery, int indexCharacter, int bit) { | |
149 |
1
1. getCallableBitTest : replaced return value with null for com/jsql/model/injection/strategy/blind/InjectionBlind::getCallableBitTest → NO_COVERAGE |
return new CallableBlind( |
150 | sqlQuery, | |
151 | indexCharacter, | |
152 | bit, | |
153 | this.injectionModel, | |
154 | this, | |
155 | this.booleanMode, | |
156 | "bit#" + indexCharacter + "~" + bit | |
157 | ); | |
158 | } | |
159 | ||
160 | @Override | |
161 | public boolean isInjectable() throws StoppedByUserSlidingException { | |
162 | | |
163 |
1
1. isInjectable : negated conditional → NO_COVERAGE |
if (this.injectionModel.isStoppedByUser()) { |
164 | throw new StoppedByUserSlidingException(); | |
165 | } | |
166 | | |
167 | var blindTest = new CallableBlind( | |
168 | this.injectionModel.getMediatorVendor().getVendor().instance().sqlTestBooleanInitialization(), | |
169 | this.injectionModel, | |
170 | this, | |
171 | this.booleanMode, | |
172 | "blind#confirm" | |
173 | ); | |
174 | | |
175 | try { | |
176 | blindTest.call(); | |
177 | } catch (Exception e) { | |
178 | LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e); | |
179 | } | |
180 | ||
181 |
3
1. isInjectable : replaced boolean return with true for com/jsql/model/injection/strategy/blind/InjectionBlind::isInjectable → NO_COVERAGE 2. isInjectable : negated conditional → NO_COVERAGE 3. isInjectable : negated conditional → NO_COVERAGE |
return blindTest.isTrue() && !this.falseDiffs.isEmpty(); |
182 | } | |
183 | ||
184 | @Override | |
185 | public String getInfoMessage() { | |
186 |
1
1. getInfoMessage : replaced return value with "" for com/jsql/model/injection/strategy/blind/InjectionBlind::getInfoMessage → NO_COVERAGE |
return "- Strategy Blind: query True when Diffs are matching " + this.falseDiffs + "\n\n"; |
187 | } | |
188 | | |
189 | | |
190 | // Getter and setter | |
191 | ||
192 | public String getSourceReferencePage() { | |
193 |
1
1. getSourceReferencePage : replaced return value with "" for com/jsql/model/injection/strategy/blind/InjectionBlind::getSourceReferencePage → NO_COVERAGE |
return this.sourceReferencePage; |
194 | } | |
195 | | |
196 | public List<Diff> getFalseDiffs() { | |
197 |
1
1. getFalseDiffs : replaced return value with Collections.emptyList for com/jsql/model/injection/strategy/blind/InjectionBlind::getFalseDiffs → NO_COVERAGE |
return this.falseDiffs; |
198 | } | |
199 | } | |
Mutations | ||
50 |
1.1 2.2 |
|
77 |
1.1 |
|
81 |
1.1 |
|
85 |
1.1 |
|
96 |
1.1 |
|
99 |
1.1 |
|
103 |
1.1 |
|
129 |
1.1 |
|
133 |
1.1 |
|
143 |
1.1 |
|
149 |
1.1 |
|
163 |
1.1 |
|
181 |
1.1 2.2 3.3 |
|
186 |
1.1 |
|
193 |
1.1 |
|
197 |
1.1 |