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