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