1 package com.jsql.model.injection.strategy.blind;
2
3 import com.jsql.model.InjectionModel;
4 import com.jsql.model.exception.StoppedByUserSlidingException;
5 import com.jsql.model.injection.strategy.blind.callable.CallableMultibit;
6 import com.jsql.util.LogLevelUtil;
7 import org.apache.commons.lang3.StringUtils;
8 import org.apache.logging.log4j.LogManager;
9 import org.apache.logging.log4j.Logger;
10
11 import java.util.ArrayList;
12 import java.util.Collection;
13 import java.util.List;
14 import java.util.concurrent.CompletionService;
15 import java.util.concurrent.ExecutionException;
16 import java.util.concurrent.ExecutorService;
17 import java.util.concurrent.Future;
18 import java.util.concurrent.atomic.AtomicInteger;
19
20 import static name.fraser.neil.plaintext.diff_match_patch.Diff;
21
22 public class InjectionMultibit extends AbstractInjectionBit<CallableMultibit> {
23
24
25
26
27 private static final Logger LOGGER = LogManager.getRootLogger();
28
29 private String sourceReference;
30
31 private List<Diff> diffsCommonWithAllIds = new ArrayList<>();
32 private final List<List<Diff>> diffsById = new ArrayList<>();
33
34 public InjectionMultibit(InjectionModel injectionModel, BlindOperator blindMode) {
35 super(injectionModel, blindMode);
36
37 if (this.injectionModel.isStoppedByUser()) {
38 return;
39 }
40
41 this.sourceReference = this.callUrl("8", "multi#ref");
42 ExecutorService taskExecutor = this.injectionModel.getMediatorUtils().getThreadUtil().getExecutor("CallableGetMultibitIds");
43 Collection<CallableMultibit> callablesId = new ArrayList<>();
44
45 for (int i = 0 ; i < 8 ; i++) {
46 callablesId.add(
47 new CallableMultibit(
48 String.valueOf(i),
49 this,
50 "multi#ref~" + i
51 )
52 );
53 }
54
55 try {
56 List<Future<CallableMultibit>> futuresId = taskExecutor.invokeAll(callablesId);
57 this.injectionModel.getMediatorUtils().getThreadUtil().shutdown(taskExecutor);
58
59 for (Future<CallableMultibit> futureId: futuresId) {
60 List<Diff> diffsWithReference = futureId.get().getDiffsWithReference();
61 if (this.diffsCommonWithAllIds.isEmpty()) {
62 this.diffsCommonWithAllIds = new ArrayList<>(diffsWithReference);
63 } else {
64 this.diffsCommonWithAllIds.retainAll(diffsWithReference);
65 }
66 this.diffsById.add(diffsWithReference);
67 }
68
69 for (List<Diff> diffById : this.diffsById) {
70 diffById.removeAll(this.diffsCommonWithAllIds);
71 }
72 } catch (ExecutionException e) {
73 LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
74 } catch (InterruptedException e) {
75 LOGGER.log(LogLevelUtil.IGNORE, e, e);
76 Thread.currentThread().interrupt();
77 }
78 }
79
80 public CallableMultibit getCallableTest(String sqlQuery, int indexChar, int block) {
81 return new CallableMultibit(
82 sqlQuery,
83 indexChar,
84 block,
85 this.injectionModel,
86 this,
87 "multi#" + indexChar + "." + block
88 );
89 }
90
91 @Override
92 public boolean isInjectable() throws StoppedByUserSlidingException {
93 if (this.injectionModel.isStoppedByUser()) {
94 throw new StoppedByUserSlidingException();
95 }
96 var callableBlock1 = new CallableMultibit("'a'", 1, 1, this.injectionModel, this, "multi#confirm.1");
97 var callableBlock2 = new CallableMultibit("'a'", 1, 2, this.injectionModel, this, "multi#confirm.2");
98 var callableBlock3 = new CallableMultibit("'a'", 1, 3, this.injectionModel, this, "multi#confirm.3");
99 callableBlock1.call();
100 callableBlock2.call();
101 callableBlock3.call();
102 return callableBlock1.getIdPage() == 3 && callableBlock2.getIdPage() == 0 && callableBlock3.getIdPage() == 1;
103 }
104
105 @Override
106 public String getInfoMessage() {
107 return "- Strategy Multibit: query 3 bits when Diffs match index in " + this.diffsById + "\n\n";
108 }
109
110 @Override
111 public void initNextChar(
112 String sqlQuery,
113 List<char[]> bytes,
114 AtomicInteger indexChar,
115 CompletionService<CallableMultibit> taskCompletionService,
116 AtomicInteger countTasksSubmitted,
117 CallableMultibit currentCallable
118 ) {
119 indexChar.incrementAndGet();
120 bytes.add(AbstractInjectionBit.getBitsUnset());
121 for (int block: new int[]{ 1, 2, 3 }) {
122 taskCompletionService.submit(
123 this.getCallableTest(
124 sqlQuery,
125 indexChar.get(),
126 block
127 )
128 );
129 countTasksSubmitted.addAndGet(1);
130 }
131 }
132
133 @Override
134 public char[] initMaskAsciiChar(List<char[]> bytes, CallableMultibit currentCallable) {
135
136 char[] asciiCodeMask = bytes.get(currentCallable.getCurrentIndex() - 1);
137 this.extractBitsFromBlock(currentCallable, asciiCodeMask);
138 return asciiCodeMask;
139 }
140
141
142
143
144 private void extractBitsFromBlock(CallableMultibit currentCallable, char[] bits) {
145 if (currentCallable.getBlock() == 1) {
146 this.convertIdPageToBits(currentCallable.getIdPage(), bits, 0, 1, 2);
147 } else if (currentCallable.getBlock() == 2) {
148 this.convertIdPageToBits(currentCallable.getIdPage(), bits, 3, 4, 5);
149 } else if (currentCallable.getBlock() == 3) {
150 this.convertIdPageToBits(currentCallable.getIdPage(), bits, -1, 6,7);
151 }
152 }
153
154
155
156
157 private void convertIdPageToBits(int idPage, char[] bits, int i1, int i2, int i3) {
158 String idPageBinary = Integer.toBinaryString(idPage);
159 String idPageBinaryPadded = StringUtils.leftPad(idPageBinary, 3, "0");
160 if (i1 > -1) {
161 bits[i1] = idPageBinaryPadded.charAt(0);
162 }
163 bits[i2] = idPageBinaryPadded.charAt(1);
164 bits[i3] = idPageBinaryPadded.charAt(2);
165 }
166
167
168
169
170 public String getSourceReference() {
171 return this.sourceReference;
172 }
173
174 public List<Diff> getDiffsCommonWithAllIds() {
175 return this.diffsCommonWithAllIds;
176 }
177
178 public List<List<Diff>> getDiffsById() {
179 return this.diffsById;
180 }
181 }