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 }
105 } catch (InterruptedException e) {
106 LOGGER.log(LogLevelUtil.IGNORE, e, e);
107 Thread.currentThread().interrupt();
108 } catch (ExecutionException e) {
109 LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
110 } catch (InjectionFailureException e) {
111 LOGGER.log(LogLevelUtil.CONSOLE_ERROR, e.getMessage());
112 countTasksSubmitted.set(0);
113 }
114 }
115 return this.stop(bytes, taskExecutor);
116 }
117
118 private static String convert(List<char[]> bytes) {
119 var result = new StringBuilder();
120 for (char[] c: bytes) {
121 try {
122 var charCode = Integer.parseInt(new String(c), 2);
123 var str = Character.toString((char) charCode);
124 result.append(str);
125 } catch (NumberFormatException err) {
126
127 }
128 }
129 return result.toString();
130 }
131
132 protected boolean isCharCompleteWithCorruptCheck(
133 List<char[]> bytes,
134 AtomicInteger countBadAsciiCode,
135 T currentCallable
136 ) throws InjectionFailureException {
137
138
139 char[] maskAsciiChar = this.initMaskAsciiChar(bytes, currentCallable);
140 var asciiCodeBit = new String(maskAsciiChar);
141 var isComplete = false;
142
143
144 if (asciiCodeBit.matches("^[01]{8}$")) {
145 var asciiCode = Integer.parseInt(asciiCodeBit, 2);
146 if (asciiCode == 255 || asciiCode == 127 || asciiCode == 0) {
147 if (countBadAsciiCode.get() > 15) {
148 throw new InjectionFailureException("Boolean false positive, stopping...");
149 }
150 countBadAsciiCode.incrementAndGet();
151 }
152
153 currentCallable.setCharText(Character.toString((char) asciiCode));
154
155 this.injectionModel.sendToViews(new Seal.MessageBinary(
156 asciiCodeBit
157 + "="
158 + currentCallable.getCharText()
159 .replace("\n", "\\n")
160 .replace("\r", "\\r")
161 .replace("\t", "\\t")
162 ));
163 isComplete = true;
164 }
165 return isComplete;
166 }
167
168 private String stop(List<char[]> bytes, ExecutorService taskExecutor) {
169 this.injectionModel.getMediatorUtils().threadUtil().shutdown(taskExecutor);
170
171
172 var result = new StringBuilder();
173
174 for (char[] c: bytes) {
175 try {
176 var charCode = Integer.parseInt(new String(c), 2);
177 var str = Character.toString((char) charCode);
178 result.append(str);
179 } catch (NumberFormatException err) {
180
181
182 }
183 }
184 return result.toString();
185 }
186
187
188
189
190
191
192 public String callUrl(String urlString, String metadataInjectionProcess) {
193 return this.injectionModel.injectWithoutIndex(urlString, metadataInjectionProcess);
194 }
195
196 public String callUrl(String urlString, String metadataInjectionProcess, AbstractCallableBit<?> callableBoolean) {
197 return this.injectionModel.injectWithoutIndex(urlString, metadataInjectionProcess, callableBoolean);
198 }
199
200 public BlindOperator getBlindOperator() {
201 return this.blindOperator;
202 }
203
204 protected static char[] getBitsUnset() {
205 return new char[]{ '0', 'x', 'x', 'x', 'x', 'x', 'x', 'x' };
206 }
207 }