CallableFile.java
package com.jsql.model.accessible;
import com.jsql.model.InjectionModel;
import com.jsql.model.exception.AbstractSlidingException;
import com.jsql.model.exception.InjectionFailureException;
import com.jsql.model.exception.LoopDetectedSlidingException;
import com.jsql.model.exception.StoppedByUserSlidingException;
import com.jsql.model.injection.vendor.model.Vendor;
import com.jsql.model.suspendable.SuspendableGetRows;
import com.jsql.util.LogLevelUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
/**
* Thread unit to read source of a file by SQL injection.
* User can interrupt the process and get a partial result of the file content.
*/
public class CallableFile implements Callable<CallableFile> {
private static final Logger LOGGER = LogManager.getRootLogger();
public static final String REQUIRE_STACK = "Read file requirement: stack query";
/**
* Path to the file to read.
*/
private final String pathFile;
/**
* Source of file.
*/
private String sourceFile = StringUtils.EMPTY;
/**
* Suspendable task that reads lines of the file by injection.
*/
private final SuspendableGetRows suspendableReadFile;
private final InjectionModel injectionModel;
/**
* Create Callable to read a file.
*/
public CallableFile(String pathFile, InjectionModel injectionModel) {
this.pathFile = pathFile;
this.injectionModel= injectionModel;
this.suspendableReadFile = new SuspendableGetRows(injectionModel);
}
@FunctionalInterface
private interface Readable {
String call() throws AbstractSlidingException;
}
/**
* Read a file on the server using SQL injection.
* Get partial result if user interrupts the process.
*/
@Override
public CallableFile call() throws Exception {
Map<Vendor, Readable> mapVendorReadable = new HashMap<>();
mapVendorReadable.put(this.injectionModel.getMediatorVendor().getMysql(), () -> this.injectionModel.getResourceAccess().getExploitMysql().getRead(this.pathFile));
mapVendorReadable.put(this.injectionModel.getMediatorVendor().getH2(), () -> this.injectionModel.getResourceAccess().getExploitH2().getRead(this.pathFile));
mapVendorReadable.put(this.injectionModel.getMediatorVendor().getSqlite(), () -> this.injectionModel.getResourceAccess().getExploitSqlite().getRead(this.pathFile));
mapVendorReadable.put(this.injectionModel.getMediatorVendor().getDerby(), () -> this.injectionModel.getResourceAccess().getExploitDerby().getRead(this.pathFile));
mapVendorReadable.put(this.injectionModel.getMediatorVendor().getHsqldb(), () -> this.injectionModel.getResourceAccess().getExploitHsqldb().getRead(this.pathFile));
mapVendorReadable.put(this.injectionModel.getMediatorVendor().getPostgres(), () -> this.injectionModel.getResourceAccess().getExploitPostgres().getRead(this.pathFile));
Readable readable = mapVendorReadable.entrySet().stream()
.filter(entry -> this.injectionModel.getMediatorVendor().getVendor() == entry.getKey())
.findFirst()
.orElse(new AbstractMap.SimpleEntry<>(null, () -> {
LOGGER.log(
LogLevelUtil.CONSOLE_DEFAULT,
"Read file not implemented for [{}], share a working example to GitHub to speed up release",
this.injectionModel.getMediatorVendor().getVendor()
);
return StringUtils.EMPTY;
}))
.getValue();
String resultToParse = StringUtils.EMPTY;
try {
resultToParse = readable.call();
} catch (InjectionFailureException e) {
// Usually thrown if File does not exist
LOGGER.log(LogLevelUtil.IGNORE, e);
} catch (LoopDetectedSlidingException | StoppedByUserSlidingException e) {
if (StringUtils.isNotEmpty(e.getSlidingWindowAllRows())) { // Get partial source
resultToParse = e.getSlidingWindowAllRows();
} else if (StringUtils.isNotEmpty(e.getSlidingWindowCurrentRows())) {
resultToParse = e.getSlidingWindowCurrentRows();
}
LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e);
}
this.sourceFile = resultToParse;
return this;
}
// Getters
public String getPathFile() {
return this.pathFile;
}
public String getSourceFile() {
return this.sourceFile;
}
public SuspendableGetRows getSuspendableReadFile() {
return this.suspendableReadFile;
}
}