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.model.bean.util.Interaction;
6 import com.jsql.model.bean.util.Request;
7 import com.jsql.model.exception.InjectionFailureException;
8 import com.jsql.model.exception.StoppedByUserSlidingException;
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 AbstractInjectionBinary<T extends AbstractCallableBinary<T>> {
23
24
25
26
27 private static final Logger LOGGER = LogManager.getRootLogger();
28
29
30
31 protected final List<String> falsy;
32
33
34
35 protected final List<String> truthy;
36
37 public enum BinaryMode {
38 AND, OR, STACK, NO_MODE
39 }
40
41 protected final InjectionModel injectionModel;
42
43 protected final BinaryMode binaryMode;
44
45 protected AbstractInjectionBinary(InjectionModel injectionModel, BinaryMode binaryMode) {
46 this.injectionModel = injectionModel;
47 this.binaryMode = binaryMode;
48 this.falsy = this.injectionModel.getMediatorVendor().getVendor().instance().getFalsy();
49 this.truthy = this.injectionModel.getMediatorVendor().getVendor().instance().getTruthy();
50 }
51
52
53
54
55
56 public abstract boolean isInjectable() throws StoppedByUserSlidingException;
57
58 public abstract void initNextChars(
59 String sqlQuery,
60 List<char[]> bytes,
61 AtomicInteger indexCharacter,
62 CompletionService<T> taskCompletionService,
63 AtomicInteger countTasksSubmitted
64 );
65
66 public abstract char[] initBinaryMask(List<char[]> bytes, T currentCallable);
67
68
69
70
71 public abstract String getInfoMessage();
72
73
74
75
76
77
78
79 public String inject(String sqlQuery, AbstractSuspendable suspendable) throws StoppedByUserSlidingException {
80
81
82 List<char[]> bytes = new ArrayList<>();
83
84
85 var indexCharacter = new AtomicInteger(0);
86
87
88 ExecutorService taskExecutor = this.injectionModel.getMediatorUtils().getThreadUtil().getExecutor("CallableAbstractBoolean");
89
90 CompletionService<T> taskCompletionService = new ExecutorCompletionService<>(taskExecutor);
91
92 var countTasksSubmitted = new AtomicInteger(0);
93 var countBadAsciiCode = new AtomicInteger(0);
94
95 this.initNextChars(sqlQuery, bytes, indexCharacter, taskCompletionService, countTasksSubmitted);
96
97
98
99 while (countTasksSubmitted.get() > 0) {
100 if (suspendable.isSuspended()) {
101 String result = this.stop(bytes, taskExecutor);
102 throw new StoppedByUserSlidingException(result);
103 }
104
105 try {
106
107 var currentCallable = taskCompletionService.take().get();
108
109
110 countTasksSubmitted.decrementAndGet();
111
112
113
114
115 this.injectCharacter(bytes, countTasksSubmitted, countBadAsciiCode, currentCallable);
116 this.initNextChars(sqlQuery, bytes, indexCharacter, taskCompletionService, countTasksSubmitted);
117
118 String result = AbstractInjectionBinary.convert(bytes);
119 if (result.matches("(?s).*"+ DataAccess.TRAIL_RGX +".*")) {
120 countTasksSubmitted.set(0);
121 break;
122 }
123 } catch (InterruptedException e) {
124 LOGGER.log(LogLevelUtil.IGNORE, e, e);
125 Thread.currentThread().interrupt();
126 } catch (ExecutionException e) {
127 LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
128 } catch (InjectionFailureException e) {
129 LOGGER.log(LogLevelUtil.CONSOLE_ERROR, e.getMessage());
130 break;
131 }
132 }
133 return this.stop(bytes, taskExecutor);
134 }
135
136 private static String convert(List<char[]> bytes) {
137 var result = new StringBuilder();
138
139 for (char[] c: bytes) {
140 try {
141 var charCode = Integer.parseInt(new String(c), 2);
142 var str = Character.toString((char) charCode);
143 result.append(str);
144
145 } catch (NumberFormatException err) {
146
147
148 }
149 }
150 return result.toString();
151 }
152
153 private void injectCharacter(List<char[]> bytes, AtomicInteger countTasksSubmitted, AtomicInteger countBadAsciiCode, T currentCallable) throws InjectionFailureException {
154
155
156
157 char[] asciiCodeMask = this.initBinaryMask(bytes, currentCallable);
158 var asciiCodeBinary = new String(asciiCodeMask);
159
160
161 if (asciiCodeBinary.matches("^[01]{8}$")) {
162 var asciiCode = Integer.parseInt(asciiCodeBinary, 2);
163 if (asciiCode == 127 || asciiCode == 0) {
164 if (countTasksSubmitted.get() != 0 && countBadAsciiCode.get() > 15) {
165 throw new InjectionFailureException("Boolean false positive, stopping...");
166 }
167 countBadAsciiCode.incrementAndGet();
168 }
169
170 currentCallable.charText = Character.toString((char) asciiCode);
171
172 var interaction = new Request();
173 interaction.setMessage(Interaction.MESSAGE_BINARY);
174 interaction.setParameters(
175 asciiCodeBinary
176 + "="
177 + currentCallable.charText
178 .replace("\\n", "\\\\\\n")
179 .replace("\\r", "\\\\\\r")
180 .replace("\\t", "\\\\\\t")
181 );
182 this.injectionModel.sendToViews(interaction);
183 }
184 }
185
186 private String stop(List<char[]> bytes, ExecutorService taskExecutor) {
187 this.injectionModel.getMediatorUtils().getThreadUtil().shutdown(taskExecutor);
188
189
190 var result = new StringBuilder();
191
192 for (char[] c: bytes) {
193 try {
194 var charCode = Integer.parseInt(new String(c), 2);
195 var str = Character.toString((char) charCode);
196 result.append(str);
197
198 } catch (NumberFormatException err) {
199
200
201 }
202 }
203 return result.toString();
204 }
205
206
207
208
209
210
211 public String callUrl(String urlString, String metadataInjectionProcess) {
212 return this.injectionModel.injectWithoutIndex(urlString, metadataInjectionProcess);
213 }
214
215 public String callUrl(String urlString, String metadataInjectionProcess, AbstractCallableBinary<?> callableBoolean) {
216 return this.injectionModel.injectWithoutIndex(urlString, metadataInjectionProcess, callableBoolean);
217 }
218
219 public BinaryMode getBooleanMode() {
220 return this.binaryMode;
221 }
222 }