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.engine.model.Engine;
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      public static final String READ_FILE_NOT_IMPLEMENTED = "Read file not implemented for [{}], share a working example on GitHub to speed up release";
29  
30      /**
31       * Path to the file to read.
32       */
33      private final String pathFile;
34  
35      /**
36       * Source of file.
37       */
38      private String sourceFile = StringUtils.EMPTY;
39      
40      /**
41       * Suspendable task that reads lines of the file by injection.
42       */
43      private final SuspendableGetRows suspendableReadFile;
44  
45      private final InjectionModel injectionModel;
46      
47      /**
48       * Create Callable to read a file.
49       */
50      public CallableFile(String pathFile, InjectionModel injectionModel) {
51          this.pathFile = pathFile;
52          this.injectionModel= injectionModel;
53          this.suspendableReadFile = new SuspendableGetRows(injectionModel);
54      }
55  
56      @FunctionalInterface
57      private interface Readable {
58          String call() throws AbstractSlidingException;
59      }
60  
61      /**
62       * Read a file on the server using SQL injection.
63       * Get partial result if user interrupts the process.
64       */
65      @Override
66      public CallableFile call() throws Exception {
67          Map<Engine, Readable> mapEngineReadable = new HashMap<>();
68          mapEngineReadable.put(this.injectionModel.getMediatorEngine().getMysql(), () -> this.injectionModel.getResourceAccess().getExploitMysql().getRead(this.pathFile));
69          mapEngineReadable.put(this.injectionModel.getMediatorEngine().getH2(), () -> this.injectionModel.getResourceAccess().getExploitH2().getRead(this.pathFile));
70          mapEngineReadable.put(this.injectionModel.getMediatorEngine().getSqlite(), () -> this.injectionModel.getResourceAccess().getExploitSqlite().getRead(this.pathFile));
71          mapEngineReadable.put(this.injectionModel.getMediatorEngine().getDerby(), () -> this.injectionModel.getResourceAccess().getExploitDerby().getRead(this.pathFile));
72          mapEngineReadable.put(this.injectionModel.getMediatorEngine().getHsqldb(), () -> this.injectionModel.getResourceAccess().getExploitHsqldb().getRead(this.pathFile));
73          mapEngineReadable.put(this.injectionModel.getMediatorEngine().getPostgres(), () -> this.injectionModel.getResourceAccess().getExploitPostgres().getRead(this.pathFile));
74          mapEngineReadable.put(this.injectionModel.getMediatorEngine().getSqlserver(), () -> this.injectionModel.getResourceAccess().getExploitSqlserver().getRead(this.pathFile));
75  
76          Readable readable = mapEngineReadable.entrySet().stream()
77              .filter(entry -> this.injectionModel.getMediatorEngine().getEngine() == entry.getKey())
78              .findFirst()
79              .orElse(new AbstractMap.SimpleEntry<>(null, () -> {
80                  LOGGER.log(
81                      LogLevelUtil.CONSOLE_DEFAULT,
82                      CallableFile.READ_FILE_NOT_IMPLEMENTED,
83                      this.injectionModel.getMediatorEngine().getEngine()
84                  );
85                  return StringUtils.EMPTY;
86              }))
87              .getValue();
88  
89          String resultToParse = StringUtils.EMPTY;
90          try {
91              resultToParse = readable.call();
92          } catch (InjectionFailureException e) {
93              // Usually thrown if File does not exist
94              LOGGER.log(LogLevelUtil.IGNORE, e);
95          } catch (LoopDetectedSlidingException | StoppedByUserSlidingException e) {
96              if (StringUtils.isNotEmpty(e.getSlidingWindowAllRows())) {  // Get partial source
97                  resultToParse = e.getSlidingWindowAllRows();
98              } else if (StringUtils.isNotEmpty(e.getSlidingWindowCurrentRows())) {
99                  resultToParse = e.getSlidingWindowCurrentRows();
100             }
101             LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
102         }
103 
104         this.sourceFile = resultToParse;
105         return this;
106     }
107 
108 
109     // Getters
110     
111     public String getPathFile() {
112         return this.pathFile;
113     }
114 
115     public String getSourceFile() {
116         return this.sourceFile;
117     }
118 
119     public SuspendableGetRows getSuspendableReadFile() {
120         return this.suspendableReadFile;
121     }
122 }