1 package com.jsql.model.injection.strategy.blind;
2
3 import com.jsql.model.InjectionModel;
4 import com.jsql.model.accessible.DataAccess;
5 import com.jsql.view.subscriber.Seal;
6 import com.jsql.model.exception.InjectionFailureException;
7 import com.jsql.model.exception.StoppedByUserSlidingException;
8 import com.jsql.model.injection.strategy.blind.callable.AbstractCallableBit;
9 import com.jsql.model.suspendable.AbstractSuspendable;
10 import com.jsql.util.LogLevelUtil;
11 import org.apache.logging.log4j.LogManager;
12 import org.apache.logging.log4j.Logger;
13
14 import java.util.ArrayList;
15 import java.util.List;
16 import java.util.concurrent.CompletionService;
17 import java.util.concurrent.ExecutionException;
18 import java.util.concurrent.ExecutorCompletionService;
19 import java.util.concurrent.ExecutorService;
20 import java.util.concurrent.atomic.AtomicInteger;
21
22 public abstract class AbstractInjectionBit<T extends AbstractCallableBit<T>> {
23
24 private static final Logger LOGGER = LogManager.getRootLogger();
25
26 public enum BlindOperator {
27 AND, OR, STACK, NO_MODE
28 }
29
30 protected final InjectionModel injectionModel;
31 protected final BlindOperator blindOperator;
32
33 protected AbstractInjectionBit(InjectionModel injectionModel, BlindOperator blindOperator) {
34 this.injectionModel = injectionModel;
35 this.blindOperator = blindOperator;
36 }
37
38
39
40
41
42 public abstract boolean isInjectable() throws StoppedByUserSlidingException;
43
44 public abstract void initNextChar(
45 String sqlQuery,
46 List<char[]> bytes,
47 AtomicInteger indexChar,
48 CompletionService<T> taskCompletionService,
49 AtomicInteger countTasksSubmitted,
50 AtomicInteger countBadAsciiCode,
51 T currentCallable
52 );
53
54 public abstract char[] initMaskAsciiChar(List<char[]> bytes, T currentCallable);
55
56
57
58
59 public abstract String getInfoMessage();
60
61
62
63
64
65
66
67 public String inject(String sqlQuery, AbstractSuspendable suspendable) throws StoppedByUserSlidingException {
68
69
70 List<char[]> bytes = new ArrayList<>();
71 var indexChar = new AtomicInteger(0);
72
73
74 ExecutorService taskExecutor = this.injectionModel.getMediatorUtils().threadUtil().getExecutor("CallableAbstractBoolean");
75 CompletionService<T> taskCompletionService = new ExecutorCompletionService<>(taskExecutor);
76
77 var countTasksSubmitted = new AtomicInteger(0);
78 var countBadAsciiCode = new AtomicInteger(0);
79
80 this.initNextChar(sqlQuery, bytes, indexChar, taskCompletionService, countTasksSubmitted, countBadAsciiCode, null);
81
82
83
84 while (countTasksSubmitted.get() > 0) {
85 if (suspendable.isSuspended()) {
86 String result = this.stop(bytes, taskExecutor);
87 throw new StoppedByUserSlidingException(result);
88 }
89
90 try {
91 var currentCallable = taskCompletionService.take().get();
92 countTasksSubmitted.decrementAndGet();
93
94
95
96 var isComplete = this.isCharCompleteWithCorruptCheck(bytes, countBadAsciiCode, currentCallable);
97 if (isComplete || currentCallable.isBinary()) {
98 this.initNextChar(sqlQuery, bytes, indexChar, taskCompletionService, countTasksSubmitted, countBadAsciiCode, currentCallable);
99 }
100
101 String result = AbstractInjectionBit.convert(bytes);
102 if (result.matches("(?s).*"+ DataAccess.TRAIL_RGX +".*")) {
103 countTasksSubmitted.set(0);
104 break;
105 }
106 } catch (InterruptedException e) {
107 LOGGER.log(LogLevelUtil.IGNORE, e, e);
108 Thread.currentThread().interrupt();
109 } catch (ExecutionException e) {
110 LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
111 } catch (InjectionFailureException e) {
112 LOGGER.log(LogLevelUtil.CONSOLE_ERROR, e.getMessage());
113 break;
114 }
115 }
116 return this.stop(bytes, taskExecutor);
117 }
118
119 private static String convert(List<char[]> bytes) {
120 var result = new StringBuilder();
121 for (char[] c: bytes) {
122 try {
123 var charCode = Integer.parseInt(new String(c), 2);
124 var str = Character.toString((char) charCode);
125 result.append(str);
126 } catch (NumberFormatException err) {
127
128 }
129 }
130 return result.toString();
131 }
132
133 protected boolean isCharCompleteWithCorruptCheck(
134 List<char[]> bytes,
135 AtomicInteger countBadAsciiCode,
136 T currentCallable
137 ) throws InjectionFailureException {
138
139
140 char[] maskAsciiChar = this.initMaskAsciiChar(bytes, currentCallable);
141 var asciiCodeBit = new String(maskAsciiChar);
142 var isComplete = false;
143
144
145 if (asciiCodeBit.matches("^[01]{8}$")) {
146 var asciiCode = Integer.parseInt(asciiCodeBit, 2);
147 if (asciiCode == 127 || asciiCode == 0) {
148 if (countBadAsciiCode.get() > 15) {
149 throw new InjectionFailureException("Boolean false positive, stopping...");
150 }
151 countBadAsciiCode.incrementAndGet();
152 }
153
154 currentCallable.setCharText(Character.toString((char) asciiCode));
155
156 this.injectionModel.sendToViews(new Seal.MessageBinary(
157 asciiCodeBit
158 + "="
159 + currentCallable.getCharText()
160 .replace("\n", "\\n")
161 .replace("\r", "\\r")
162 .replace("\t", "\\t")
163 ));
164 isComplete = true;
165 }
166 return isComplete;
167 }
168
169 private String stop(List<char[]> bytes, ExecutorService taskExecutor) {
170 this.injectionModel.getMediatorUtils().threadUtil().shutdown(taskExecutor);
171
172
173 var result = new StringBuilder();
174
175 for (char[] c: bytes) {
176 try {
177 var charCode = Integer.parseInt(new String(c), 2);
178 var str = Character.toString((char) charCode);
179 result.append(str);
180 } catch (NumberFormatException err) {
181
182
183 }
184 }
185 return result.toString();
186 }
187
188
189
190
191
192
193 public String callUrl(String urlString, String metadataInjectionProcess) {
194 return this.injectionModel.injectWithoutIndex(urlString, metadataInjectionProcess);
195 }
196
197 public String callUrl(String urlString, String metadataInjectionProcess, AbstractCallableBit<?> callableBoolean) {
198 return this.injectionModel.injectWithoutIndex(urlString, metadataInjectionProcess, callableBoolean);
199 }
200
201 public BlindOperator getBlindOperator() {
202 return this.blindOperator;
203 }
204
205 protected static char[] getBitsUnset() {
206 return new char[]{ '0', 'x', 'x', 'x', 'x', 'x', 'x', 'x' };
207 }
208 }