def executeCommand(apiclient, toolId, local=True, allowAnyCommand=False):
    """
     remote task
    Execute the tool with the given toolId on the given calendar name.
    Then execute the plugin corresponding.
    Any unhandled exception will result in a task-failed event in the class.

    Args:
        apiclient: the apiclient instance.
        toolId: the mongo Object id corresponding to the tool to execute.
        local: boolean, set the execution in a local context
    Raises:
        Terminated: if the task gets terminated
        OSError: if the output directory cannot be created (not if it already exists)
        Exception: if an exception unhandled occurs during the bash command execution.
        Exception: if a plugin considered a failure.
    """
    # Connect to given calendar
    APIClient.setInstance(apiclient)
    toolModel = Tool.fetchObject({"_id": ObjectId(toolId)})
    command_dict = toolModel.getCommand()
    if command_dict is None and toolModel.text != "":
        command_dict = {"plugin": toolModel.plugin_used, "timeout": 0}
    msg = ""
    success, comm, fileext = apiclient.getCommandLine(toolId)
    if not success:
        print(str(comm))
        toolModel.setStatus(["error"])
        return False, str(comm)

    outputRelDir = toolModel.getOutputDir(apiclient.getCurrentPentest())
    abs_path = os.path.dirname(os.path.abspath(__file__))
    toolFileName = toolModel.name+"_" + \
            str(time.time()) # ext already added in command
    outputDir = os.path.join(abs_path, "./results", outputRelDir)
    # Create the output directory
    try:
        os.makedirs(outputDir)
    except OSError as exc:
        if exc.errno == errno.EEXIST and os.path.isdir(outputDir):
            pass
        else:
            print(str(exc))
            toolModel.setStatus(["error"])
            return False, str(exc)
    outputDir = os.path.join(outputDir, toolFileName)
    comm = comm.replace("|outputDir|", outputDir)
    toolModel.updateInfos({"cmdline": comm})

    # Get tool's wave time limit searching the wave intervals
    if toolModel.wave == "Custom commands" or local:
        timeLimit = None
    else:
        timeLimit = getWaveTimeLimit(toolModel.wave)
    # adjust timeLimit if the command has a lower timeout
    if command_dict is not None and timeLimit is not None:
        timeLimit = min(
            datetime.now() + timedelta(0, int(command_dict.get("timeout", 0))),
            timeLimit)
    ##
    try:
        print(('TASK STARTED:' + toolModel.name))
        print("Will timeout at " + str(timeLimit))
        # Execute the command with a timeout
        returncode, stdout = Utils.execute(comm, timeLimit, True)
        if returncode == -1:
            toolModel.setStatus(["timedout"])
            return False, "timedout"
    except Exception as e:
        print(str(e))
        toolModel.setStatus(["error"])
        return False, str(e)
    # Execute found plugin if there is one
    outputfile = outputDir + fileext
    plugin = "auto-detect" if command_dict["plugin"] == "" else command_dict[
        "plugin"]
    msg = apiclient.importToolResult(toolId, plugin, outputfile)
    if msg != "Success":
        #toolModel.markAsNotDone()
        print(str(msg))
        toolModel.setStatus(["error"])
        return False, str(msg)

    # Delay
    if command_dict is not None:
        if float(command_dict.get("sleep_between", 0)) > 0.0:
            msg += " (will sleep for " + \
                str(float(command_dict.get("sleep_between", 0)))+")"
        print(msg)
        time.sleep(float(command_dict.get("sleep_between", 0)))
    return True, outputfile
Exemple #2
0
def pollex():
    """Send a command to execute for pollenisator-gui running instance
    """
    verbose = False
    if sys.argv[1] == "-v":
        verbose = True
        execCmd = shlex.join(sys.argv[2:])
    else:
        execCmd = shlex.join(sys.argv[1:])
    bin_name = shlex.split(execCmd)[0]
    if bin_name in [
            "echo", "print", "vim", "vi", "tmux", "nano", "code", "cd", "pwd",
            "cat"
    ]:
        return
    cmdName = os.path.splitext(os.path.basename(execCmd.split(" ")[0]))[0]
    apiclient = APIClient.getInstance()
    apiclient.tryConnection()
    cmdName += "::" + str(time.time()).replace(" ", "-")
    commands = Command.fetchObjects({"bin_path": {'$regex': bin_name}})
    choices = set()
    if commands is not None:
        for command in commands:
            choices.add(command.plugin)
    if len(choices) == 0:
        plugin = "Default"
    elif len(choices) == 1:
        plugin = choices.pop()
    else:
        choice = -1
        while choice == -1:
            print("Choose plugin:")
            for i, choice in enumerate(choices):
                print(f"{i+1}. {choice}")
            try:
                choice_str = input()
                choice = int(choice_str)
            except ValueError as e:
                print("You must type a valid number")
            if choice > len(choices) or choice < 1:
                choice = -1
                print("You must type a number between 1 and " +
                      str(len(choices)))
        plugin = list(choices)[choice - 1]
    print("INFO : Executing plugin " + str(plugin))
    success, comm, fileext = apiclient.getDesiredOutputForPlugin(
        execCmd, plugin)
    if not success:
        print("ERROR : An error as occured : " + str(comm))
        return
    with tempfile.TemporaryDirectory() as tmpdirname:
        outputFilePath = os.path.join(tmpdirname, cmdName)
        comm = comm.replace("|outputDir|", outputFilePath)
        if (verbose):
            print("Executing command : " + str(comm))
        returncode, stdout = Utils.execute(comm, None, True)
        #if stdout.strip() != "":
        #    print(stdout.strip())
        if not os.path.exists(outputFilePath):
            if os.path.exists(outputFilePath + fileext):
                outputFilePath += fileext
            else:
                print(
                    f"ERROR : Expected file was not generated {outputFilePath}"
                )
                return
        print(f"INFO : Uploading results {outputFilePath}")
        msg = apiclient.importExistingResultFile(
            outputFilePath, plugin,
            os.environ.get("POLLENISATOR_DEFAULT_TARGET", ""), comm)
        print(msg)