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