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