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