forked from p15670423/monkey
Island: Roughly implement POST in new Configuration resource
+ lots of questions
This commit is contained in:
parent
5dd27eeea5
commit
138480f021
|
@ -1,21 +1,49 @@
|
||||||
|
import json
|
||||||
|
from dataclasses import dataclass
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
from itertools import chain
|
||||||
|
from typing import Mapping
|
||||||
|
|
||||||
from flask import jsonify, request
|
from flask import jsonify, request
|
||||||
|
|
||||||
|
from common.configuration.agent_configuration import AgentConfigurationSchema
|
||||||
|
from common.utils.exceptions import InvalidConfigurationError
|
||||||
|
from monkey_island.cc.repository import FileAgentConfigurationRepository
|
||||||
from monkey_island.cc.resources.AbstractResource import AbstractResource
|
from monkey_island.cc.resources.AbstractResource import AbstractResource
|
||||||
from monkey_island.cc.resources.request_authentication import jwt_required
|
from monkey_island.cc.resources.request_authentication import jwt_required
|
||||||
from monkey_island.cc.repository import FileAgentConfigurationRepository
|
|
||||||
|
|
||||||
class ConfigurationTypeEnum(Enum):
|
class ConfigurationTypeEnum(Enum):
|
||||||
ISLAND = "island"
|
ISLAND = "island"
|
||||||
AGENT = "agent"
|
AGENT = "agent"
|
||||||
|
|
||||||
|
|
||||||
|
class ImportStatuses:
|
||||||
|
UNSAFE_OPTION_VERIFICATION_REQUIRED = "unsafe_options_verification_required"
|
||||||
|
INVALID_CONFIGURATION = "invalid_configuration"
|
||||||
|
INVALID_CREDENTIALS = "invalid_credentials"
|
||||||
|
IMPORTED = "imported"
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ResponseContents:
|
||||||
|
import_status: str = ImportStatuses.IMPORTED
|
||||||
|
message: str = ""
|
||||||
|
status_code: int = 200
|
||||||
|
config: str = ""
|
||||||
|
config_schema: str = ""
|
||||||
|
|
||||||
|
def form_response(self):
|
||||||
|
return self.__dict__
|
||||||
|
|
||||||
|
|
||||||
class Configuration(AbstractResource):
|
class Configuration(AbstractResource):
|
||||||
urls = ["/api/configuration/<string:configuration_type>"]
|
urls = ["/api/configuration/<string:configuration_type>"]
|
||||||
|
|
||||||
@jwt_required
|
@jwt_required
|
||||||
def get(self, configuration_type: str):
|
def get(self, configuration_type: str):
|
||||||
# we probably still need this because of credential fields, HTTP ports, etc in the config?
|
# Q: we probably still need this because of credential fields, HTTP ports, etc in the
|
||||||
|
# config?
|
||||||
if configuration_type == ConfigurationTypeEnum.ISLAND:
|
if configuration_type == ConfigurationTypeEnum.ISLAND:
|
||||||
pass
|
pass
|
||||||
elif configuration_type == ConfigurationTypeEnum.AGENT:
|
elif configuration_type == ConfigurationTypeEnum.AGENT:
|
||||||
|
@ -23,9 +51,48 @@ class Configuration(AbstractResource):
|
||||||
return jsonify(configuration=configuration)
|
return jsonify(configuration=configuration)
|
||||||
|
|
||||||
@jwt_required
|
@jwt_required
|
||||||
def post(self):
|
def post(self, configuration_type: str):
|
||||||
pass
|
request_contents = json.loads(request.data)
|
||||||
|
configuration_json = json.loads(request_contents["config"])
|
||||||
|
Configuration._remove_metadata_from_config(configuration_json)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Q: encryption is moving to the frontend; also check this in the frontend?
|
||||||
|
if request_contents["unsafeOptionsVerified"]:
|
||||||
|
schema = AgentConfigurationSchema()
|
||||||
|
# Q: in what format/schema are we getting the config from the Island?
|
||||||
|
# Q: when does flattening the config go away?
|
||||||
|
configuration_object = schema.loads(configuration_json)
|
||||||
|
FileAgentConfigurationRepository.store_configuration(
|
||||||
|
configuration_object
|
||||||
|
) # check error handling
|
||||||
|
return ResponseContents().form_response()
|
||||||
|
else:
|
||||||
|
return ResponseContents(
|
||||||
|
config=json.dumps(configuration_json),
|
||||||
|
# Q: do we still need a separate config schema like this?
|
||||||
|
# config_schema=ConfigService.get_config_schema(),
|
||||||
|
import_status=ImportStatuses.UNSAFE_OPTION_VERIFICATION_REQUIRED,
|
||||||
|
).form_response()
|
||||||
|
except InvalidConfigurationError:
|
||||||
|
return ResponseContents(
|
||||||
|
import_status=ImportStatuses.INVALID_CONFIGURATION,
|
||||||
|
message="Invalid configuration supplied. "
|
||||||
|
"Maybe the format is outdated or the file has been corrupted.",
|
||||||
|
status_code=400,
|
||||||
|
).form_response()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
# Q: why is this really needed? besides the fact that it just doesn't belong in the config
|
||||||
|
# which is being saved in mongo? if nothing, can't we just wait to change the exploiters
|
||||||
|
# to plugins?
|
||||||
|
def _remove_metadata_from_config(configuration_json: Mapping):
|
||||||
|
for exploiter in chain(
|
||||||
|
configuration_json["propagation"]["exploitation"]["brute_force"],
|
||||||
|
configuration_json["propagation"]["exploitation"]["vulnerability"],
|
||||||
|
):
|
||||||
|
del exploiter["supported_os"]
|
||||||
|
|
||||||
@jwt_required
|
@jwt_required
|
||||||
def patch(self): # reset the config here?
|
def patch(self): # Q: reset the configuration here? or does that make more sense in delete?
|
||||||
pass
|
pass
|
||||||
|
|
Loading…
Reference in New Issue