def file_upload(workspace=None):
    """
    Upload a report file to Server and process that report with Faraday client plugins.
    """
    logger.info("Importing new plugin report in server...")
    # Authorization code copy-pasted from server/api/base.py
    ws = Workspace.query.filter_by(name=workspace).first()
    if not ws or not ws.active:
        # Don't raise a 403 to prevent workspace name enumeration
        abort(404, "Workspace disabled: %s" % workspace)

    if 'file' not in request.files:
        abort(400)

    try:
        validate_csrf(request.form.get('csrf_token'))
    except ValidationError:
        abort(403)

    report_file = request.files['file']

    if report_file:

        chars = string.ascii_uppercase + string.digits
        random_prefix = ''.join(random.choice(chars)
                                for x in range(12))  # nosec
        raw_report_filename = '{0}_{1}'.format(
            random_prefix, secure_filename(report_file.filename))

        try:
            file_path = os.path.join(CONST_FARADAY_HOME_PATH,
                                     'uploaded_reports', raw_report_filename)
            with open(file_path, 'wb') as output:
                output.write(report_file.read())
        except AttributeError:
            logger.warning(
                "Upload reports in WEB-UI not configurated, run Faraday client and try again..."
            )
            abort(
                make_response(
                    jsonify(
                        message=
                        "Upload reports not configurated: Run faraday client and start Faraday server again"
                    ), 500))
        else:
            logger.info("Get plugin for file: %s", file_path)
            plugin = report_analyzer.get_plugin(file_path)
            if not plugin:
                logger.info("Could not get plugin for file")
                abort(
                    make_response(jsonify(message="Invalid report file"), 400))
            else:
                logger.info("Plugin for file: %s Plugin: %s", file_path,
                            plugin.id)
                REPORTS_QUEUE.put(
                    (workspace, file_path, plugin.id, flask.g.user))
                return make_response(jsonify(message="ok"), 200)
    else:
        abort(make_response(jsonify(message="Missing report file"), 400))
Beispiel #2
0
    def test_file_upload(self, test_client, session, csrf_token, logged_user):
        ws = WorkspaceFactory.create(name="abc")
        session.add(ws)
        session.commit()
        path = TEST_DATA_PATH / 'nmap_plugin_with_api.xml'

        with path.open('rb') as report:
            file_contents = report.read()
        data = {
            'file': (BytesIO(file_contents), 'nmap_report.xml'),
            'csrf_token': csrf_token
        }

        res = test_client.post(
            self.check_url(f'/v2/ws/{ws.name}/upload_report'),
            data=data,
            use_json_data=False)

        assert res.status_code == 200
        assert len(REPORTS_QUEUE.queue) == 1
        queue_elem = REPORTS_QUEUE.get_nowait()
        assert queue_elem[0] == ws.name
        assert queue_elem[3].lower() == "nmap"
        assert queue_elem[4] == logged_user.id

        # I'm testing a method which lost referene of workspace and logged_user within the test
        ws_id = ws.id
        logged_user_id = logged_user.id

        from faraday.server.threads.reports_processor import ReportsManager
        false_thread = ReportsManager(None)
        false_thread.process_report(queue_elem[0], queue_elem[1],
                                    queue_elem[2], queue_elem[3],
                                    queue_elem[4])
        command = Command.query.filter(Command.workspace_id == ws_id).one()
        assert command
        assert command.creator_id == logged_user_id
        assert command.id == res.json["command_id"]
        assert command.end_date
        host = Host.query.filter(Host.workspace_id == ws_id).first()
        assert host
        assert host.creator_id == logged_user_id
        service = Service.query.filter(Service.workspace_id == ws_id).first()
        assert service
        assert service.creator_id == logged_user_id
Beispiel #3
0
 def test_bulk_create_endpoint_add_to_queue(self, session, workspace, test_client, logged_user):
     assert count(Host, workspace) == 0
     assert count(VulnerabilityGeneric, workspace) == 0
     url = f'/v3/ws/{workspace.name}/bulk_create'
     host_data_ = host_data.copy()
     service_data_ = service_data.copy()
     service_data_['vulnerabilities'] = [vuln_data]
     host_data_['services'] = [service_data_]
     host_data_['credentials'] = [credential_data]
     host_data_['vulnerabilities'] = [vuln_data]
     res = test_client.post(
         url,
         data=dict(hosts=[host_data_], command=command_data)
     )
     assert res.status_code == 201, res.json
     assert count(Command, workspace) == 1
     assert len(REPORTS_QUEUE.queue) == 1
     command = Command.query.filter(Command.workspace == workspace).one()
     queue_elem = REPORTS_QUEUE.get_nowait()
     assert queue_elem[0] == workspace.name
     assert queue_elem[1] == command.id
     assert queue_elem[3] is None
     assert queue_elem[4] == logged_user.id
Beispiel #4
0
def file_upload(workspace=None):
    """
    Upload a report file to Server and process that report with Faraday client plugins.
    """
    logger.info("Importing new plugin report in server...")
    # Authorization code copy-pasted from server/api/base.py
    ws = Workspace.query.filter_by(name=workspace).first()
    if not ws or not ws.active:
        # Don't raise a 403 to prevent workspace name enumeration
        abort(404, f"Workspace disabled: {workspace}")

    if 'file' not in request.files:
        abort(400)

    try:
        validate_csrf(request.form.get('csrf_token'))
    except ValidationError:
        abort(403)

    report_file = request.files['file']

    if report_file:

        chars = string.ascii_uppercase + string.digits
        random_prefix = ''.join(random.choice(chars)
                                for x in range(12))  # nosec
        raw_report_filename = f'{random_prefix}_{secure_filename(report_file.filename)}'

        try:
            file_path = CONST_FARADAY_HOME_PATH / 'uploaded_reports' \
                        / raw_report_filename
            with file_path.open('wb') as output:
                output.write(report_file.read())
        except AttributeError:
            logger.warning(
                "Upload reports in WEB-UI not configurated, run Faraday client and try again..."
            )
            abort(
                make_response(
                    jsonify(
                        message=
                        "Upload reports not configurated: Run faraday client and start Faraday server again"
                    ), 500))
        else:
            logger.info(f"Get plugin for file: {file_path}")
            plugin = report_analyzer.get_plugin(file_path)
            if not plugin:
                logger.info("Could not get plugin for file")
                abort(
                    make_response(jsonify(message="Invalid report file"), 400))
            else:
                logger.info(
                    f"Plugin for file: {file_path} Plugin: {plugin.id}")
                workspace_instance = Workspace.query.filter_by(
                    name=workspace).one()
                command = Command()
                command.workspace = workspace_instance
                command.start_date = datetime.now()
                command.import_source = 'report'
                # The data will be updated in the bulk_create function
                command.tool = "In progress"
                command.command = "In progress"

                db.session.add(command)
                db.session.commit()

                REPORTS_QUEUE.put((workspace_instance.name, command.id,
                                   file_path, plugin.id, flask.g.user.id))
                return make_response(
                    jsonify(message="ok", command_id=command.id), 200)
    else:
        abort(make_response(jsonify(message="Missing report file"), 400))
Beispiel #5
0
    def post(self, workspace_name):
        """
        ---
          tags: ["Bulk"]
          description: Creates all faraday objects in bulk for a workspace
          requestBody:
            required: true
            content:
                application/json:
                    schema: BulkCreateSchema
          responses:
            201:tags:
              description: Created
              content:
                application/json:
                  schema: BulkCreateSchema
            401:
               $ref: "#/components/responses/UnauthorizedError"
            403:
               description: Disabled workspace
            404:
               description: Workspace not found
        """
        from faraday.server.threads.reports_processor import REPORTS_QUEUE  # pylint: disable=import-outside-toplevel

        if flask_login.current_user.is_anonymous:
            agent = require_agent_token()
        data = self._parse_data(self._get_schema_instance({}), flask.request)
        json_data = flask.request.json
        if flask_login.current_user.is_anonymous:
            workspace = self._get_workspace(workspace_name)

            if not workspace or workspace not in agent.workspaces:
                flask.abort(404, f"No such workspace: {workspace_name}")

            if "execution_id" not in data:
                flask.abort(400, "argument expected: execution_id")

            execution_id = data["execution_id"]

            agent_execution: AgentExecution = AgentExecution.query.filter(
                AgentExecution.id == execution_id).one_or_none()

            if agent_execution is None:
                logger.exception(
                    NoResultFound(
                        f"No row was found for agent executor id {execution_id}"
                    ))
                flask.abort(400,
                            "Can not find an agent execution with that id")

            if workspace_name != agent_execution.workspace.name:
                logger.exception(
                    ValueError(
                        f"The {agent.name} agent has permission to workspace {workspace_name} and ask to write "
                        f"to workspace {agent_execution.workspace.name}"))
                flask.abort(400, "Trying to write to the incorrect workspace")

            params_data = agent_execution.parameters_data
            params = ', '.join(
                [f'{key}={value}' for (key, value) in params_data.items()])

            start_date = (data["command"].get("start_date") or agent_execution.command.start_date) \
                if "command" in data else agent_execution.command.start_date

            end_date = data["command"].get("end_date",
                                           None) if "command" in data else None

            data["command"] = {
                'id': agent_execution.command.id,
                'tool': agent.name,  # Agent name
                'command': agent_execution.executor.name,
                'user': '',
                'hostname': '',
                'params': params,
                'import_source': 'agent',
                'start_date': start_date
            }

            if end_date is not None:
                data["command"]["end_date"] = end_date

            command = Command.query.filter(
                Command.id == agent_execution.command.id).one_or_none()
            if command is None:
                logger.exception(
                    ValueError(
                        f"There is no command with {agent_execution.command.id}"
                    ))
                flask.abort(400, "Trying to update a not existent command")

            _update_command(command, data['command'])
            db.session.flush()
            if data['hosts']:
                json_data['command'] = data["command"]
                json_data['command']["start_date"] = data["command"][
                    "start_date"].isoformat()
                if 'end_date' in data["command"]:
                    json_data['command']["end_date"] = data["command"][
                        "end_date"].isoformat()

        else:
            workspace = self._get_workspace(workspace_name)
            command = Command(**(data['command']))
            command.workspace = workspace
            db.session.add(command)
            db.session.commit()
        if data['hosts']:
            # Create random file
            chars = string.ascii_uppercase + string.digits
            random_prefix = ''.join(random.choice(chars)
                                    for x in range(30))  # nosec
            json_file = f"{random_prefix}.json"
            file_path = CONST_FARADAY_HOME_PATH / 'uploaded_reports' \
                        / json_file
            with file_path.open('w') as output:
                json.dump(json_data, output)
            logger.info("Create tmp json file for bulk_create: %s", file_path)
            user_id = flask_login.current_user.id if not flask_login.current_user.is_anonymous else None
            REPORTS_QUEUE.put(
                (workspace.name, command.id, file_path, None, user_id))
        return flask.jsonify({
            "message":
            "Created",
            "command_id":
            None if command is None else command.id
        }), 201