1 package com.jsql.model.injection.strategy.blind;
2
3 import com.jsql.model.InjectionModel;
4 import com.jsql.model.exception.InjectionFailureException;
5 import com.jsql.model.exception.StoppedByUserSlidingException;
6 import com.jsql.model.injection.strategy.blind.callable.CallableBlindBin;
7 import com.jsql.util.LogLevelUtil;
8 import org.apache.commons.lang3.StringUtils;
9 import org.apache.logging.log4j.LogManager;
10 import org.apache.logging.log4j.Logger;
11
12 import java.util.ArrayList;
13 import java.util.Collection;
14 import java.util.List;
15 import java.util.concurrent.CompletionService;
16 import java.util.concurrent.ExecutionException;
17 import java.util.concurrent.ExecutorService;
18 import java.util.concurrent.Future;
19 import java.util.concurrent.atomic.AtomicInteger;
20
21 import static name.fraser.neil.plaintext.diff_match_patch.Diff;
22 import static name.fraser.neil.plaintext.diff_match_patch.Operation;
23
24
25
26
27 public class InjectionBlindBin extends AbstractInjectionMonobit<CallableBlindBin> {
28
29 private static final Logger LOGGER = LogManager.getRootLogger();
30 private static final int LOW = 0;
31 private static final int HIGH = 127;
32
33 private String sourceReferencePage;
34
35
36
37
38
39
40
41 private List<Diff> falseDiffs = new ArrayList<>();
42 private List<Diff> trueDiffs = new ArrayList<>();
43
44
45
46
47
48
49 public InjectionBlindBin(InjectionModel injectionModel, BlindOperator blindOperator) {
50 super(injectionModel, blindOperator);
51
52 List<String> falsys = this.injectionModel.getMediatorVendor().getVendor().instance().getFalsyBin();
53 if (falsys.isEmpty() || this.injectionModel.isStoppedByUser()) {
54 return;
55 }
56
57
58 this.sourceReferencePage = this.callUrl(StringUtils.EMPTY, "bin#ref:"+ blindOperator.toString().toLowerCase());
59
60
61
62 ExecutorService taskExecutor = this.injectionModel.getMediatorUtils().getThreadUtil().getExecutor("CallableGetBlindBinTagFalse");
63 Collection<CallableBlindBin> callablesFalsys = new ArrayList<>();
64 for (String falsy: falsys) {
65 callablesFalsys.add(new CallableBlindBin(
66 falsy,
67 injectionModel,
68 this,
69 blindOperator,
70 -1, -1, -1,
71 "bin#falsy"
72 ));
73 }
74
75
76
77
78 try {
79 List<Future<CallableBlindBin>> futuresFalsys = taskExecutor.invokeAll(callablesFalsys);
80 this.injectionModel.getMediatorUtils().getThreadUtil().shutdown(taskExecutor);
81 for (Future<CallableBlindBin> futureFalsy: futuresFalsys) {
82 if (this.injectionModel.isStoppedByUser()) {
83 return;
84 }
85 if (this.falseDiffs.isEmpty()) {
86 this.falseDiffs = futureFalsy.get().getDiffsWithReference();
87 } else {
88 this.falseDiffs.retainAll(futureFalsy.get().getDiffsWithReference());
89 }
90 }
91 } catch (ExecutionException e) {
92 LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
93 } catch (InterruptedException e) {
94 LOGGER.log(LogLevelUtil.IGNORE, e, e);
95 Thread.currentThread().interrupt();
96 }
97
98 if (this.injectionModel.isStoppedByUser()) {
99 return;
100 }
101
102 this.cleanTrueDiffs(injectionModel, blindOperator);
103 }
104
105 private void cleanTrueDiffs(InjectionModel injectionModel, BlindOperator blindOperator) {
106 ExecutorService taskExecutor = this.injectionModel.getMediatorUtils().getThreadUtil().getExecutor("CallableGetBlindBinTagTrue");
107 Collection<CallableBlindBin> callablesTruthys = new ArrayList<>();
108 List<String> truthys = this.injectionModel.getMediatorVendor().getVendor().instance().getTruthyBin();
109 for (String truthy: truthys) {
110 callablesTruthys.add(new CallableBlindBin(
111 truthy,
112 injectionModel,
113 this,
114 blindOperator,
115 -1, -1, -1,
116 "bin#truthy"
117 ));
118 }
119
120
121 try {
122 List<Future<CallableBlindBin>> futuresTruthys = taskExecutor.invokeAll(callablesTruthys);
123 this.injectionModel.getMediatorUtils().getThreadUtil().shutdown(taskExecutor);
124 for (Future<CallableBlindBin> futureTruthy: futuresTruthys) {
125 if (this.injectionModel.isStoppedByUser()) {
126 return;
127 }
128 if (this.trueDiffs.isEmpty()) {
129 this.trueDiffs = futureTruthy.get().getDiffsWithReference();
130 } else {
131 this.trueDiffs.retainAll(futureTruthy.get().getDiffsWithReference());
132 }
133 this.falseDiffs.removeAll(futureTruthy.get().getDiffsWithReference());
134 }
135 } catch (ExecutionException e) {
136 LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
137 } catch (InterruptedException e) {
138 LOGGER.log(LogLevelUtil.IGNORE, e, e);
139 Thread.currentThread().interrupt();
140 }
141 }
142
143 @Override
144 public CallableBlindBin getCallableBitTest(String sqlQuery, int indexChar, int bit) {
145 return null;
146 }
147
148 @Override
149 public boolean isInjectable() throws StoppedByUserSlidingException {
150 if (this.injectionModel.isStoppedByUser()) {
151 throw new StoppedByUserSlidingException();
152 }
153 var blindTest = new CallableBlindBin(
154 this.injectionModel.getMediatorVendor().getVendor().instance().sqlBlindConfirm(),
155 this.injectionModel,
156 this,
157 this.blindOperator,
158 -1, -1, -1,
159 "bin#confirm"
160 );
161 try {
162 blindTest.call();
163 } catch (Exception e) {
164 LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
165 }
166 return blindTest.isTrue()
167
168 && this.trueDiffs.stream().anyMatch(diff -> !Operation.EQUAL.equals(diff.operation))
169 || this.falseDiffs.stream().anyMatch(diff -> !Operation.EQUAL.equals(diff.operation));
170 }
171
172 @Override
173 public void initNextChar(
174 String sqlQuery,
175 List<char[]> bytes,
176 AtomicInteger indexChar,
177 CompletionService<CallableBlindBin> taskCompletionService,
178 AtomicInteger countTasksSubmitted,
179 AtomicInteger countBadAsciiCode,
180 CallableBlindBin currentCallable
181 ) {
182 int low;
183 int mid;
184 int high;
185
186 if (currentCallable != null) {
187 low = currentCallable.getLow();
188 mid = currentCallable.getMid();
189 high = currentCallable.getHigh();
190
191 if (low >= high) {
192 if (this.isCorruptOrElseNextChar(bytes, indexChar, countBadAsciiCode, currentCallable, low)) {
193 return;
194 }
195 low = InjectionBlindBin.LOW;
196 high = InjectionBlindBin.HIGH;
197 } else if (currentCallable.isTrue()) {
198 low = mid + 1;
199 } else {
200 high = mid - 1;
201 }
202 } else {
203 low = InjectionBlindBin.LOW;
204 high = InjectionBlindBin.HIGH;
205 bytes.add(AbstractInjectionBit.getBitsUnset());
206 indexChar.incrementAndGet();
207 }
208
209 mid = low + (high - low) / 2;
210 taskCompletionService.submit(
211 new CallableBlindBin(
212 sqlQuery,
213 indexChar.get(),
214 this.injectionModel,
215 this,
216 this.blindOperator,
217 low, mid, high,
218 String.format("bin#%s~%s<%s<%s", indexChar, low, mid, high)
219 )
220 );
221 countTasksSubmitted.addAndGet(1);
222 }
223
224 private boolean isCorruptOrElseNextChar(List<char[]> bytes, AtomicInteger indexChar, AtomicInteger countBadAsciiCode, CallableBlindBin currentCallable, int low) {
225 if (low == 0 || low == 127) {
226 countBadAsciiCode.incrementAndGet();
227 } else {
228 low = currentCallable.isTrue() ? low : low - 1;
229 }
230 char[] asciiCodeMask = bytes.get(currentCallable.getCurrentIndex() - 1);
231 this.setAsciiCodeMask(asciiCodeMask, low);
232
233 try {
234 this.isCharCompleteWithCorruptCheck(bytes, countBadAsciiCode, currentCallable);
235 } catch (InjectionFailureException e) {
236 return true;
237 }
238
239 bytes.add(AbstractInjectionBit.getBitsUnset());
240 indexChar.incrementAndGet();
241 return false;
242 }
243
244 private void setAsciiCodeMask(char[] asciiCodeMask, int value) {
245 String binary = StringUtils.leftPad(Integer.toBinaryString((char) value), 8, "0");
246 for (int i = 0; i <= 7; i++) {
247 asciiCodeMask[i] = binary.charAt(i);
248 }
249 }
250
251 @Override
252 public char[] initMaskAsciiChar(List<char[]> bytes, CallableBlindBin currentCallable) {
253 return bytes.get(currentCallable.getCurrentIndex() - 1);
254 }
255
256 @Override
257 public String getInfoMessage() {
258 return "- Strategy Blind bin: query True when Diffs are matching " + this.falseDiffs + "\n\n";
259 }
260
261
262
263
264 public String getSourceReferencePage() {
265 return this.sourceReferencePage;
266 }
267
268 public List<Diff> getFalseDiffs() {
269 return this.falseDiffs;
270 }
271
272 public List<Diff> getTrueDiffs() {
273 return this.trueDiffs;
274 }
275 }