View Javadoc
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         // Bits for current url
134         char[] asciiCodeMask = bytes.get(currentCallable.getCurrentIndex() - 1);
135         this.extractBitsFromBlock(currentCallable, asciiCodeMask);
136         return asciiCodeMask;
137     }
138 
139     /**
140      * Extract 3 bits from callable for specific block
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      * Set bits by page id
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     // Getter
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 }