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