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.injection.strategy.blind.callable.AbstractCallableBit;
10 import com.jsql.model.suspendable.AbstractSuspendable;
11 import com.jsql.util.LogLevelUtil;
12 import org.apache.logging.log4j.LogManager;
13 import org.apache.logging.log4j.Logger;
14
15 import java.util.ArrayList;
16 import java.util.List;
17 import java.util.concurrent.CompletionService;
18 import java.util.concurrent.ExecutionException;
19 import java.util.concurrent.ExecutorCompletionService;
20 import java.util.concurrent.ExecutorService;
21 import java.util.concurrent.atomic.AtomicInteger;
22
23 public abstract class AbstractInjectionBit<T extends AbstractCallableBit<T>> {
24
25
26
27
28 private static final Logger LOGGER = LogManager.getRootLogger();
29
30
31
32 protected List<String> falsyBit;
33 protected List<String> falsyBin;
34
35
36
37 protected List<String> truthyBit;
38 protected List<String> truthyBin;
39
40 public enum BlindOperator {
41 AND, OR, STACK, NO_MODE
42 }
43
44 protected final InjectionModel injectionModel;
45 protected final BlindOperator blindOperator;
46
47 protected AbstractInjectionBit(InjectionModel injectionModel, BlindOperator blindOperator) {
48 this.injectionModel = injectionModel;
49 this.blindOperator = blindOperator;
50 this.falsyBit = this.injectionModel.getMediatorVendor().getVendor().instance().getFalsyBit();
51 this.truthyBit = this.injectionModel.getMediatorVendor().getVendor().instance().getTruthyBit();
52 this.falsyBin = this.injectionModel.getMediatorVendor().getVendor().instance().getFalsyBin();
53 this.truthyBin = this.injectionModel.getMediatorVendor().getVendor().instance().getTruthyBin();
54 }
55
56
57
58
59
60 public abstract boolean isInjectable() throws StoppedByUserSlidingException;
61
62 public abstract void initNextChar(
63 String sqlQuery,
64 List<char[]> bytes,
65 AtomicInteger indexChar,
66 CompletionService<T> taskCompletionService,
67 AtomicInteger countTasksSubmitted,
68 T currentCallable
69 );
70
71 public abstract char[] initMaskAsciiChar(List<char[]> bytes, T currentCallable);
72
73
74
75
76 public abstract String getInfoMessage();
77
78
79
80
81
82
83
84 public String inject(String sqlQuery, AbstractSuspendable suspendable) throws StoppedByUserSlidingException {
85
86
87 List<char[]> bytes = new ArrayList<>();
88 var indexChar = new AtomicInteger(0);
89
90
91 ExecutorService taskExecutor = this.injectionModel.getMediatorUtils().getThreadUtil().getExecutor("CallableAbstractBoolean");
92 CompletionService<T> taskCompletionService = new ExecutorCompletionService<>(taskExecutor);
93
94 var countTasksSubmitted = new AtomicInteger(0);
95 var countBadAsciiCode = new AtomicInteger(0);
96
97 this.initNextChar(sqlQuery, bytes, indexChar, taskCompletionService, countTasksSubmitted, null);
98
99
100
101 while (countTasksSubmitted.get() > 0) {
102 if (suspendable.isSuspended()) {
103 String result = this.stop(bytes, taskExecutor);
104 throw new StoppedByUserSlidingException(result);
105 }
106
107 try {
108 var currentCallable = taskCompletionService.take().get();
109 countTasksSubmitted.decrementAndGet();
110
111
112
113 var isComplete = this.injectCharacter(bytes, countTasksSubmitted, countBadAsciiCode, currentCallable);
114 if (isComplete || currentCallable.isBinary()) {
115 this.initNextChar(sqlQuery, bytes, indexChar, taskCompletionService, countTasksSubmitted, currentCallable);
116 }
117
118 String result = AbstractInjectionBit.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 for (char[] c: bytes) {
139 try {
140 var charCode = Integer.parseInt(new String(c), 2);
141 var str = Character.toString((char) charCode);
142 result.append(str);
143 } catch (NumberFormatException err) {
144
145 }
146 }
147 return result.toString();
148 }
149
150 protected boolean injectCharacter(List<char[]> bytes, AtomicInteger countTasksSubmitted, AtomicInteger countBadAsciiCode, T currentCallable) throws InjectionFailureException {
151
152
153 char[] maskAsciiChar = this.initMaskAsciiChar(bytes, currentCallable);
154 var asciiCodeBit = new String(maskAsciiChar);
155 var isComplete = false;
156
157
158 if (asciiCodeBit.matches("^[01]{8}$")) {
159 var asciiCode = Integer.parseInt(asciiCodeBit, 2);
160 if (asciiCode == 127 || asciiCode == 0) {
161 if (countTasksSubmitted.get() != 0 && countBadAsciiCode.get() > 15) {
162 throw new InjectionFailureException("Boolean false positive, stopping...");
163 }
164 countBadAsciiCode.incrementAndGet();
165 }
166
167 currentCallable.setCharText(Character.toString((char) asciiCode));
168
169 var interaction = new Request();
170 interaction.setMessage(Interaction.MESSAGE_BINARY);
171 interaction.setParameters(
172 asciiCodeBit
173 + "="
174 + currentCallable.getCharText()
175 .replace("\\n", "\\\\\\n")
176 .replace("\\r", "\\\\\\r")
177 .replace("\\t", "\\\\\\t")
178 );
179 this.injectionModel.sendToViews(interaction);
180 isComplete = true;
181 }
182 return isComplete;
183 }
184
185 private String stop(List<char[]> bytes, ExecutorService taskExecutor) {
186 this.injectionModel.getMediatorUtils().getThreadUtil().shutdown(taskExecutor);
187
188
189 var result = new StringBuilder();
190
191 for (char[] c: bytes) {
192 try {
193 var charCode = Integer.parseInt(new String(c), 2);
194 var str = Character.toString((char) charCode);
195 result.append(str);
196 } catch (NumberFormatException err) {
197
198
199 }
200 }
201 return result.toString();
202 }
203
204
205
206
207
208
209 public String callUrl(String urlString, String metadataInjectionProcess) {
210 return this.injectionModel.injectWithoutIndex(urlString, metadataInjectionProcess);
211 }
212
213 public String callUrl(String urlString, String metadataInjectionProcess, AbstractCallableBit<?> callableBoolean) {
214 return this.injectionModel.injectWithoutIndex(urlString, metadataInjectionProcess, callableBoolean);
215 }
216
217 public BlindOperator getBooleanMode() {
218 return this.blindOperator;
219 }
220
221 protected static char[] getBitsUnset() {
222 return new char[]{ '0', 'x', 'x', 'x', 'x', 'x', 'x', 'x' };
223 }
224 }