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.util.LogLevelUtil; | |
6 | import org.apache.logging.log4j.LogManager; | |
7 | import org.apache.logging.log4j.Logger; | |
8 | ||
9 | import java.util.ArrayList; | |
10 | import java.util.Collection; | |
11 | import java.util.List; | |
12 | import java.util.concurrent.ExecutionException; | |
13 | import java.util.concurrent.ExecutorService; | |
14 | import java.util.concurrent.Future; | |
15 | ||
16 | /** | |
17 | * Time attack using parallel threads. | |
18 | * Waiting time in seconds, response time exceeded means query is false. | |
19 | * Noting that sleep() functions will add up for each line from request. | |
20 | * A sleep time of 5 will be executed only if the SELECT returns exactly one line. | |
21 | */ | |
22 | public class InjectionTime extends AbstractInjectionMonobit<CallableTime> { | |
23 | ||
24 | /** | |
25 | * Log4j logger sent to view. | |
26 | */ | |
27 | private static final Logger LOGGER = LogManager.getRootLogger(); | |
28 | ||
29 | /** | |
30 | * Time based works by default, many tests will change it to false if it isn't confirmed. | |
31 | */ | |
32 | private boolean isTimeInjectable = true; | |
33 | ||
34 | /** | |
35 | * Create time attack initialization. | |
36 | * If every false requests are under 5 seconds and every true are below 5 seconds, | |
37 | * then time attack is confirmed. | |
38 | */ | |
39 | public InjectionTime(InjectionModel injectionModel, BooleanMode booleanMode) { | |
40 | | |
41 | super(injectionModel, booleanMode); | |
42 | | |
43 | // No blind | |
44 |
2
1. <init> : negated conditional → NO_COVERAGE 2. <init> : negated conditional → NO_COVERAGE |
if (this.falsy.isEmpty() || this.injectionModel.isStoppedByUser()) { |
45 | return; | |
46 | } | |
47 | ||
48 | // Concurrent calls to the FALSE statements, | |
49 | // it will use inject() from the model | |
50 | ExecutorService taskExecutor = this.injectionModel.getMediatorUtils().getThreadUtil().getExecutor("CallableGetTimeTagFalse"); | |
51 | Collection<CallableTime> callablesFalseTest = new ArrayList<>(); | |
52 | | |
53 | for (String falseTest: this.falsy) { | |
54 | callablesFalseTest.add(new CallableTime( | |
55 | falseTest, | |
56 | injectionModel, | |
57 | this, | |
58 | booleanMode, | |
59 | "time#falsy" | |
60 | )); | |
61 | } | |
62 | | |
63 | // If one FALSE query makes less than X seconds, | |
64 | // then the test is a failure => exit | |
65 | // Allow the user to stop the loop | |
66 | try { | |
67 | List<Future<CallableTime>> futuresFalseTest = taskExecutor.invokeAll(callablesFalseTest); | |
68 |
1
1. <init> : removed call to com/jsql/util/ThreadUtil::shutdown → NO_COVERAGE |
this.injectionModel.getMediatorUtils().getThreadUtil().shutdown(taskExecutor); |
69 | ||
70 | for (Future<CallableTime> futureFalseTest: futuresFalseTest) { | |
71 | | |
72 |
1
1. <init> : negated conditional → NO_COVERAGE |
if (this.injectionModel.isStoppedByUser()) { |
73 | return; | |
74 | } | |
75 | | |
76 |
1
1. <init> : negated conditional → NO_COVERAGE |
if (futureFalseTest.get().isTrue()) { |
77 | | |
78 | this.isTimeInjectable = false; | |
79 | return; | |
80 | } | |
81 | } | |
82 | } catch (ExecutionException e) { | |
83 | LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e); | |
84 | } catch (InterruptedException e) { | |
85 | ||
86 | LOGGER.log(LogLevelUtil.IGNORE, e, e); | |
87 |
1
1. <init> : removed call to java/lang/Thread::interrupt → NO_COVERAGE |
Thread.currentThread().interrupt(); |
88 | } | |
89 | | |
90 |
1
1. <init> : removed call to com/jsql/model/injection/strategy/blind/InjectionTime::checkTrueTests → NO_COVERAGE |
this.checkTrueTests(booleanMode); |
91 | } | |
92 | ||
93 | private void checkTrueTests(BooleanMode booleanMode) { | |
94 | | |
95 | // Concurrent calls to the TRUE statements, | |
96 | // it will use inject() from the model | |
97 | ExecutorService taskExecutor = this.injectionModel.getMediatorUtils().getThreadUtil().getExecutor("CallableGetTimeTagTrue"); | |
98 | Collection<CallableTime> callablesTrueTest = new ArrayList<>(); | |
99 | | |
100 | for (String trueTest: this.truthy) { | |
101 | callablesTrueTest.add(new CallableTime( | |
102 | trueTest, | |
103 | this.injectionModel, | |
104 | this, | |
105 | booleanMode, | |
106 | "time#truthy" | |
107 | )); | |
108 | } | |
109 | ||
110 | // If one TRUE query makes more than X seconds, | |
111 | // then the test is a failure => exit. | |
112 | // Allow the user to stop the loop | |
113 | try { | |
114 | List<Future<CallableTime>> futuresTrueTest = taskExecutor.invokeAll(callablesTrueTest); | |
115 | ||
116 |
1
1. checkTrueTests : removed call to com/jsql/util/ThreadUtil::shutdown → NO_COVERAGE |
this.injectionModel.getMediatorUtils().getThreadUtil().shutdown(taskExecutor); |
117 | | |
118 | for (Future<CallableTime> futureTrueTest: futuresTrueTest) { | |
119 | | |
120 |
1
1. checkTrueTests : negated conditional → NO_COVERAGE |
if (this.injectionModel.isStoppedByUser()) { |
121 | return; | |
122 | } | |
123 | | |
124 |
1
1. checkTrueTests : negated conditional → NO_COVERAGE |
if (!futureTrueTest.get().isTrue()) { |
125 | | |
126 | this.isTimeInjectable = false; | |
127 | return; | |
128 | } | |
129 | } | |
130 | } catch (ExecutionException e) { | |
131 | LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e); | |
132 | } catch (InterruptedException e) { | |
133 | ||
134 | LOGGER.log(LogLevelUtil.IGNORE, e, e); | |
135 |
1
1. checkTrueTests : removed call to java/lang/Thread::interrupt → NO_COVERAGE |
Thread.currentThread().interrupt(); |
136 | } | |
137 | } | |
138 | ||
139 | @Override | |
140 | public CallableTime getCallableBitTest(String sqlQuery, int indexCharacter, int bit) { | |
141 |
1
1. getCallableBitTest : replaced return value with null for com/jsql/model/injection/strategy/blind/InjectionTime::getCallableBitTest → NO_COVERAGE |
return new CallableTime( |
142 | sqlQuery, | |
143 | indexCharacter, | |
144 | bit, | |
145 | this.injectionModel, | |
146 | this, | |
147 | this.booleanMode, | |
148 | "bit#" + indexCharacter + "~" + bit | |
149 | ); | |
150 | } | |
151 | ||
152 | @Override | |
153 | public boolean isInjectable() throws StoppedByUserSlidingException { | |
154 | | |
155 |
1
1. isInjectable : negated conditional → NO_COVERAGE |
if (this.injectionModel.isStoppedByUser()) { |
156 | throw new StoppedByUserSlidingException(); | |
157 | } | |
158 | | |
159 | var timeTest = new CallableTime( | |
160 | this.injectionModel.getMediatorVendor().getVendor().instance().sqlTestBooleanInitialization(), | |
161 | this.injectionModel, | |
162 | this, | |
163 | this.booleanMode, | |
164 | "time#confirm" | |
165 | ); | |
166 | | |
167 | try { | |
168 | timeTest.call(); | |
169 | } catch (Exception e) { | |
170 | LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e); | |
171 | } | |
172 | ||
173 |
3
1. isInjectable : replaced boolean return with true for com/jsql/model/injection/strategy/blind/InjectionTime::isInjectable → NO_COVERAGE 2. isInjectable : negated conditional → NO_COVERAGE 3. isInjectable : negated conditional → NO_COVERAGE |
return this.isTimeInjectable && timeTest.isTrue(); |
174 | } | |
175 | ||
176 | @Override | |
177 | public String getInfoMessage() { | |
178 |
1
1. getInfoMessage : replaced return value with "" for com/jsql/model/injection/strategy/blind/InjectionTime::getInfoMessage → NO_COVERAGE |
return "- Strategy Time: query True when delaying for 5s\n\n"; |
179 | } | |
180 | } | |
Mutations | ||
44 |
1.1 2.2 |
|
68 |
1.1 |
|
72 |
1.1 |
|
76 |
1.1 |
|
87 |
1.1 |
|
90 |
1.1 |
|
116 |
1.1 |
|
120 |
1.1 |
|
124 |
1.1 |
|
135 |
1.1 |
|
141 |
1.1 |
|
155 |
1.1 |
|
173 |
1.1 2.2 3.3 |
|
178 |
1.1 |