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