View Javadoc
1   package com.jsql.model.accessible;
2   
3   import com.jsql.model.InjectionModel;
4   import com.jsql.model.exception.AbstractSlidingException;
5   import com.jsql.model.exception.InjectionFailureException;
6   import com.jsql.model.exception.LoopDetectedSlidingException;
7   import com.jsql.model.exception.StoppedByUserSlidingException;
8   import com.jsql.model.injection.vendor.model.Vendor;
9   import com.jsql.model.suspendable.SuspendableGetRows;
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.AbstractMap;
16  import java.util.HashMap;
17  import java.util.Map;
18  import java.util.concurrent.Callable;
19  
20  /**
21   * Thread unit to read source of a file by SQL injection.
22   * User can interrupt the process and get a partial result of the file content.
23   */
24  public class CallableFile implements Callable<CallableFile> {
25      
26      private static final Logger LOGGER = LogManager.getRootLogger();
27      public static final String REQUIRE_STACK = "Read file requirement: stack query";
28  
29      /**
30       * Path to the file to read.
31       */
32      private final String pathFile;
33  
34      /**
35       * Source of file.
36       */
37      private String sourceFile = StringUtils.EMPTY;
38      
39      /**
40       * Suspendable task that reads lines of the file by injection.
41       */
42      private final SuspendableGetRows suspendableReadFile;
43  
44      private final InjectionModel injectionModel;
45      
46      /**
47       * Create Callable to read a file.
48       */
49      public CallableFile(String pathFile, InjectionModel injectionModel) {
50          this.pathFile = pathFile;
51          this.injectionModel= injectionModel;
52          this.suspendableReadFile = new SuspendableGetRows(injectionModel);
53      }
54  
55      @FunctionalInterface
56      private interface Readable {
57          String call() throws AbstractSlidingException;
58      }
59  
60      /**
61       * Read a file on the server using SQL injection.
62       * Get partial result if user interrupts the process.
63       */
64      @Override
65      public CallableFile call() throws Exception {
66          Map<Vendor, Readable> mapVendorReadable = new HashMap<>();
67          mapVendorReadable.put(this.injectionModel.getMediatorVendor().getMysql(), () -> this.injectionModel.getResourceAccess().getExploitMysql().getRead(this.pathFile));
68          mapVendorReadable.put(this.injectionModel.getMediatorVendor().getH2(), () -> this.injectionModel.getResourceAccess().getExploitH2().getRead(this.pathFile));
69          mapVendorReadable.put(this.injectionModel.getMediatorVendor().getSqlite(), () -> this.injectionModel.getResourceAccess().getExploitSqlite().getRead(this.pathFile));
70          mapVendorReadable.put(this.injectionModel.getMediatorVendor().getDerby(), () -> this.injectionModel.getResourceAccess().getExploitDerby().getRead(this.pathFile));
71          mapVendorReadable.put(this.injectionModel.getMediatorVendor().getHsqldb(), () -> this.injectionModel.getResourceAccess().getExploitHsqldb().getRead(this.pathFile));
72          mapVendorReadable.put(this.injectionModel.getMediatorVendor().getPostgres(), () -> this.injectionModel.getResourceAccess().getExploitPostgres().getRead(this.pathFile));
73  
74          Readable readable = mapVendorReadable.entrySet().stream()
75              .filter(entry -> this.injectionModel.getMediatorVendor().getVendor() == entry.getKey())
76              .findFirst()
77              .orElse(new AbstractMap.SimpleEntry<>(null, () -> {
78                  LOGGER.log(
79                      LogLevelUtil.CONSOLE_DEFAULT,
80                      "Read file not implemented for [{}], share a working example to GitHub to speed up release",
81                      this.injectionModel.getMediatorVendor().getVendor()
82                  );
83                  return StringUtils.EMPTY;
84              }))
85              .getValue();
86  
87          String resultToParse = StringUtils.EMPTY;
88          try {
89              resultToParse = readable.call();
90          } catch (InjectionFailureException e) {
91              // Usually thrown if File does not exist
92              LOGGER.log(LogLevelUtil.IGNORE, e);
93          } catch (LoopDetectedSlidingException | StoppedByUserSlidingException e) {
94              if (StringUtils.isNotEmpty(e.getSlidingWindowAllRows())) {  // Get partial source
95                  resultToParse = e.getSlidingWindowAllRows();
96              } else if (StringUtils.isNotEmpty(e.getSlidingWindowCurrentRows())) {
97                  resultToParse = e.getSlidingWindowCurrentRows();
98              }
99              LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e);
100         }
101 
102         this.sourceFile = resultToParse;
103         return this;
104     }
105 
106 
107     // Getters
108     
109     public String getPathFile() {
110         return this.pathFile;
111     }
112 
113     public String getSourceFile() {
114         return this.sourceFile;
115     }
116 
117     public SuspendableGetRows getSuspendableReadFile() {
118         return this.suspendableReadFile;
119     }
120 }