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