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