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