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.patch.Diff;
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  public class InjectionMultibit extends AbstractInjectionBinary<CallableMultibit> {
21  
22      /**
23       * Log4j logger sent to view.
24       */
25      private static final Logger LOGGER = LogManager.getRootLogger();
26  
27      private String sourceReference;
28  
29      private List<Diff> diffsCommonWithAllIds = new ArrayList<>();
30      private final List<List<Diff>> diffsById = new ArrayList<>();
31  
32      public InjectionMultibit(InjectionModel injectionModel, BinaryMode blindMode) {
33          super(injectionModel, blindMode);
34          
35          if (this.injectionModel.isStoppedByUser()) {
36              return;
37          }
38  
39          this.sourceReference = this.callUrl("8", "multi#ref");
40          ExecutorService taskExecutor = this.injectionModel.getMediatorUtils().getThreadUtil().getExecutor("CallableGetMultibitIds");
41          Collection<CallableMultibit> callablesId = new ArrayList<>();
42  
43          for (int i = 0; i < 8 ; i++) {
44              callablesId.add(
45                  new CallableMultibit(
46                      String.valueOf(i),
47                      this,
48                      "multi#ref~" + i
49                  )
50              );
51          }
52  
53          try {
54              List<Future<CallableMultibit>> futuresId = taskExecutor.invokeAll(callablesId);
55              this.injectionModel.getMediatorUtils().getThreadUtil().shutdown(taskExecutor);
56  
57              for (Future<CallableMultibit> futureId: futuresId) {
58                  List<Diff> diffsWithReference = futureId.get().getDiffsWithReference();
59                  if (this.diffsCommonWithAllIds.isEmpty()) {
60                      this.diffsCommonWithAllIds = new ArrayList<>(diffsWithReference);
61                  } else {
62                      this.diffsCommonWithAllIds.retainAll(diffsWithReference);
63                  }
64                  this.diffsById.add(diffsWithReference);
65              }
66  
67              for (List<Diff> diffById : this.diffsById) {
68                  diffById.removeAll(this.diffsCommonWithAllIds);
69              }
70          } catch (ExecutionException e) {
71              LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
72          } catch (InterruptedException e) {
73              LOGGER.log(LogLevelUtil.IGNORE, e, e);
74              Thread.currentThread().interrupt();
75          }
76      }
77  
78      public CallableMultibit getCallableTest(String sqlQuery, int indexCharacter, int block) {
79          return new CallableMultibit(
80              sqlQuery,
81              indexCharacter,
82              block,
83              this.injectionModel,
84              this,
85              "multi#" + indexCharacter + "." + block
86          );
87      }
88  
89      @Override
90      public boolean isInjectable() throws StoppedByUserSlidingException {
91          if (this.injectionModel.isStoppedByUser()) {
92              throw new StoppedByUserSlidingException();
93          }
94          var callableBlock1 = new CallableMultibit("'a'", 1, 1, this.injectionModel, this, "multi#confirm.1");
95          var callableBlock2 = new CallableMultibit("'a'", 1, 2, this.injectionModel, this, "multi#confirm.2");
96          var callableBlock3 = new CallableMultibit("'a'", 1, 3, this.injectionModel, this, "multi#confirm.3");
97          callableBlock1.call();
98          callableBlock2.call();
99          callableBlock3.call();
100         return callableBlock1.getIdPage() == 3 && callableBlock2.getIdPage() == 0 && callableBlock3.getIdPage() == 1;
101     }
102 
103     @Override
104     public String getInfoMessage() {
105         return "- Strategy Multibit: query 3 bits when Diffs match index in " + this.diffsById + "\n\n";
106     }
107 
108     @Override
109     public void initNextChars(
110         String sqlQuery,
111         List<char[]> bytes,
112         AtomicInteger indexCharacter,
113         CompletionService<CallableMultibit> taskCompletionService,
114         AtomicInteger countTasksSubmitted
115     ) {
116         indexCharacter.incrementAndGet();
117         bytes.add(new char[]{ '0', 'x', 'x', 'x', 'x', 'x', 'x', 'x' });
118         for (int block: new int[]{ 1, 2, 3 }) {
119             taskCompletionService.submit(
120                 this.getCallableTest(
121                     sqlQuery,
122                     indexCharacter.get(),
123                     block
124                 )
125             );
126             countTasksSubmitted.addAndGet(1);
127         }
128     }
129 
130     @Override
131     public char[] initBinaryMask(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.block == 1) {
143             this.convertIdPageToBits(currentCallable.idPage, bits, 0, 1, 2);
144         } else if (currentCallable.block == 2) {
145             this.convertIdPageToBits(currentCallable.idPage, bits, 3, 4, 5);
146         } else if (currentCallable.block == 3) {
147             this.convertIdPageToBits(currentCallable.idPage, 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 
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 }