Exemplo n.º 1
0
class Scenario(object):
    def __init__(self, scenario_name):
        self.file_manager = FileManager()
        #Variables
        self.scenario_name = scenario_name
        self.scenario_id = get_unique_id(length=8)
        now = datetime.now()
        self.creation_date = now.strftime("%d/%m/%Y %H:%M:%S")
        self.last_accessed = self.creation_date[:]
        self.exploit_info = ExploitInfo("", "", "")
        self.vulnerability_info = VulnerabilityInfo("", "", "", "")
        self.machines = dict()

    def setExploitInfo(self, exploit_info):
        """
        Sets the exploit info for this scenario
        :param exploit_info: Object which carries the exploit info
        """
        self.exploit_info = exploit_info

    def setVulnerabilityInfo(self, vulnerability_info):
        """
        Sets the vulnerability info for this scenario
        :param vulnerability_info: Object which carries the vulnerability info
        """
        self.vulnerability_info = vulnerability_info

    def addVM(self, vm):
        """
        Adds a new virtual machine to this scenario
        :param vm: Object which carries the virtual machine data
        """
        self.machines[vm.name] = vm

    def dictionary(self):
        """
        Generates a dictionary for the Scenario object
        :return: A dictionary with Scenario data
        """
        scenario_dict = dict()
        scenario_dict["scenario_name"] = self.scenario_name
        scenario_dict["scenario_id"] = self.scenario_id
        scenario_dict["creation_date"] = self.creation_date
        scenario_dict["last_accessed"] = self.last_accessed
        scenario_dict["exploit_info"] = self.exploit_info.dictionary(
        ) if self.exploit_info else dict()
        scenario_dict[
            "vulnerability_info"] = self.vulnerability_info.dictionary(
            ) if self.vulnerability_info else dict()
        scenario_dict["machines"] = dict()
        for name in self.machines:
            scenario_dict["machines"][name] = self.machines[name].dictionary()
        return scenario_dict

    def generateScenario(self, scenario_name):
        """
        Generates a scenario JSON file
        :param scenario_name: String with the scenario name
        :return: JSON file containing all the scenario data
        """
        json_dict = self.dictionary()
        json_name = self.scenario_name + ".json"
        with open(
                self.file_manager.getScenariosPath() / scenario_name / "JSON" /
                json_name, 'w') as outfile:
            json.dump(json_dict, outfile)
        json_string = json.dumps(json_dict, indent=2)
        print(json_string)
        return json_string
Exemplo n.º 2
0
class VagrantManager(object):
    def __init__(self):
        self.file_manager = FileManager()
        self.vagrant_file = VagrantFile()
        self.scenario_manager = ScenarioManager()

    def createVagrantFiles(self, scenario_name):
        """
        Creates a vagrant file per machine in a scenario
        :param scenario_json: String with the scenario name
        :return: True if vagrant files were successfully created
        """
        self.file_manager.createMachineFolders(scenario_name)
        scenario_json = self.scenario_manager.getScenario(scenario_name)
        for machine_name in scenario_json["machines"]:
            machine = scenario_json["machines"][machine_name]
            machine_path = self.file_manager.getScenariosPath(
            ) / scenario_name / "Machines" / machine_name
            print(
                self.vagrant_file.vagrantFilePerMachine(machine, machine_path))
        result = {"result": True}
        return result

    def runVagrantUp(self, scenario_name):
        """
        Executes the vagrant up command for each machine in the scenario
        :param scenario_name: String with the scenario name
        :return: True if the vagrant up commands were successfully executed
        """
        self.createVagrantFiles(scenario_name)
        scenario_json = self.scenario_manager.getScenario(scenario_name)
        for machine_name in scenario_json["machines"]:
            machine_path = self.file_manager.getScenariosPath(
            ) / scenario_name / "Machines" / machine_name
            if not os.path.exists(machine_path):  # Proceed if path exists
                return
            os.chdir(machine_path)
            process = subprocess.Popen(['vagrant', 'up'],
                                       stdout=subprocess.PIPE,
                                       universal_newlines=True)
            while True:
                output = process.stdout.readline()
                if output == '' and process.poll() is not None:
                    break
                if output:
                    print(output.strip())
        result = {"result": True}
        return result

    def sendCommand(self,
                    scenario_name,
                    machine_name,
                    command,
                    default_timeout=5,
                    show_output=True):
        #First we need to move to the directory of the given machine
        machine_path = self.file_manager.getScenariosPath(
        ) / scenario_name / "Machines" / machine_name
        #using "vagrant ssh -c 'command' <machine>" will only try to execute that command and return, CHANGE THIS
        connect_command = "vagrant ssh -c '{}' {}".format(
            command, machine_name)
        sshProcess = subprocess.Popen(connect_command,
                                      cwd=machine_path,
                                      stdin=subprocess.PIPE,
                                      stdout=subprocess.PIPE,
                                      universal_newlines=True,
                                      shell=True,
                                      bufsize=0)
        #wait for the execution to finish, process running on different shell
        sshProcess.wait()
        sshProcess.stdin.close()
        return_code = sshProcess.returncode

        if show_output:
            for line in sshProcess.stdout:
                if line == "END\n":
                    break
                print(line, end="")

            for line in sshProcess.stdout:
                if line == "END\n":
                    break
                print(line, end="")

        return return_code

    def restartVM(self, machine_name):
        pass

    def haltVM(self, machine_name):
        pass

    def testNetworkPing(self,
                        scenario_name,
                        machine_name,
                        destination_machine_name,
                        count=1):

        if self.scenario_manager.scenarioExists(scenario_name):
            scenario_data = self.scenario_manager.getScenario(scenario_name)

            try:
                machines = scenario_data['machines']
                machine_to_ping = machines[destination_machine_name]
                machine_to_ping_network_settings = machine_to_ping[
                    'network_settings']
                destination_ip = machine_to_ping_network_settings['ip_address']
                ping_command = "ping -c {} {}".format(count, destination_ip)
                return_code = self.sendCommand(scenario_name, machine_name,
                                               ping_command)
                if return_code == 0:
                    print("Ping Succesful")
                    return True
                elif return_code == 1:
                    print("No answer from %s" % destination_machine_name)
                    return False
                else:
                    print("Another error as ocurred")
                    return False
            except KeyError:
                print("Machines not defined for this Scenario")
                return False
        else:
            print("Scenario %s not found" % scenario_name)
            return False

    def getAvailableBoxes(self):
        """
        Gets the available boxes in the Vagrant context
        :return: A list of string with the available boxes
        """
        # Variables
        boxes = {}
        boxNum = 0
        boxlist = subprocess.check_output("vagrant box list", shell=True)
        boxlist = str(boxlist)
        boxlist = re.sub(r"(^[b']|'|\s(.*?)\\n)", " ", boxlist)
        boxlist = boxlist.split(" ")
        boxlist = filter(None, boxlist)

        print("Loading available Vanilla VMs")

        for boxName in boxlist:
            boxNum = boxNum + 1
            boxes[boxNum] = boxName
            print("[ " + str(boxNum) + " ]" + boxName)
        return boxes
class ScenarioManager(object):
    def __init__(self):
        self.file_manager = FileManager()

    def createScenario(self, scenario_name):
        """
        Creates a new scenario which includes the folders and the scenario JSON file
        :param scenario_name: String with the scenario name
        :return: True if the new scenario was successfully created
        """
        #Folder creation moved to FileManager
        self.file_manager.createScenarioFolders(scenario_name)
        scenario = Scenario(scenario_name)
        scenario.generateScenario(scenario_name)
        result = {"result": True}
        return result

    def getScenarios(self):
        """
        Gets the available scenarios
        :return: A list of strings with the available scenarios
        """
        # Variables
        scenarios = os.listdir(self.file_manager.getScenariosPath())
        scenarios_dict = {"scenarios": scenarios}
        return scenarios_dict

    def scenarioExists(self, scenario_name):
        """
        Check if a scenario exists
        :param scenario_name: String with the scenario name
        :return: False if the scenario JSON file does not exist and the path to the JSON file if it exist
        """
        scenario_dir_path = self.file_manager.getScenariosPath(
        ) / scenario_name / "JSON"
        if not os.path.isdir(scenario_dir_path):
            print("Scenario %s directory not found" % scenario_name)
            return False
        else:
            scenario_json_path = scenario_dir_path / ''.join(
                [scenario_name, ".json"])
            if not os.path.exists(scenario_json_path):
                print("Scenario %s json not found" % scenario_name)
                return None
            else:
                return scenario_json_path

    def getScenario(self, scenario_name):
        """
        Gets the scenario as a JSON file
        :param scenario_name: String with the scenario name
        :return: JSON file with the scenario info
        """
        scenario_json_path = self.scenarioExists(scenario_name)
        if scenario_json_path:
            try:
                with open(scenario_json_path) as json_file:
                    scenario_json = json.load(json_file)
                    return scenario_json
            except:
                print("Something went wrong while retrieving Scenario JSON")

    def editScenario(self, scenario_json):
        """
        Edits a current scenario with a JSON file
        :param scenario_name: String with the scenario name
        :param scenario_json: JSON file with the new scenario
        :return: True if the scenario has been successfully edited, otherwise False
        """
        scenario_name = scenario_json["scenario_name"]
        scenario_json_path = self.scenarioExists(scenario_name)
        if scenario_json_path:
            with open(scenario_json_path, 'w+') as outfile:
                outfile.write(json.dumps(scenario_json, indent=2))
                outfile.close()
            #THIS IS A PLACEHOLDER
            #It will try to create the folders every time the scenario is edited
            #new_scenario_dict = json.loads(new_scenario)
            return True
        else:
            return False
Exemplo n.º 4
0
class ScenarioManager():
    def __init__(self, db_manager=DatabaseManager()):
        self.file_manager = FileManager()
        self.db_manager = db_manager
        self.scenarios_dict = self._initializeFromDatabase()

    def _initializeFromDirectory(self):
        """
        Initializes the scenario's runtime objects using data from the host folders.
        :return: Dictionary containing scenario's data
        """
        # Variables
        scenarios_dict = dict()
        scenarios = os.listdir(self.file_manager.getScenariosPath())
        for scenario_name in scenarios:
            json_name = ''.join([scenario_name, ".json"])
            with open(
                    self.file_manager.getScenarioJSONPath(scenario_name) /
                    json_name) as outfile:
                scenario_dict = json.load(outfile)
            scenario = Scenario(scenario_name).objectFromDictionary(
                scenario_dict)
            scenarios_dict[scenario_name] = scenario
        return scenarios_dict

    def _initializeFromDatabase(self):
        """
        Pre-populates the database with scenarios.
        :return: Dictionary containing scenario's data
        """
        # Variables
        scenarios_dict = dict()
        scenarios = self.db_manager.getScenarios()
        for raw_scenario in scenarios:
            del raw_scenario["_id"]
            scenario_name = raw_scenario["scenario_name"]
            scenario = Scenario(scenario_name).objectFromDictionary(
                raw_scenario)
            scenarios_dict[scenario_name] = scenario
        return scenarios_dict

    def newEmpty(self, scenario_name):
        """
        Creates a new scenario which includes the folders and the scenario JSON file
        :param scenario_name: String with the scenario name
        :return: Response object containing the status of the request
        """
        #Folder creation moved to FileManager
        response = Response()
        if scenario_name not in self.scenarios_dict:
            #self.file_manager.createScenarioFolders(scenario_name)
            scenario = Scenario(scenario_name)
            self.scenarios_dict[scenario_name] = scenario
            #self._saveScenarioAsJSON(scenario)
            self.db_manager.insertScenario(scenario.dictionary().copy())
            response.setResponse(True)
            response.setBody(scenario.dictionary())
        else:
            response.setResponse(False)
            response.setReason('Scenario already exist')
            response.setBody(dict())

        return response.dictionary()

    def getAll(self):
        """
        Gets the available scenarios
        :return: Response object containing the status of the request
        """
        # Variables
        scenarios_dict = {
            "scenarios": [
                self.scenarios_dict[s].scenario_name
                for s in self.scenarios_dict
            ]
        }
        response = Response()
        response.setResponse(True)
        response.setBody(scenarios_dict)
        return response.dictionary()

    def getOne(self, scenario_name):
        """
        Gets the scenario as a JSON file
        :param scenario_name: String with the scenario name
        :return: Response object containing the status of the request
        """
        response = Response()
        if scenario_name in self.scenarios_dict:
            response.setResponse(True)
            response.setBody(self.scenarios_dict[scenario_name].dictionary())
        else:
            response.setResponse(False)
            response.setReason('Scenario doesn\'t exist')
            response.setBody(dict())
        return response.dictionary()

    def editOne(self, scenario_json):
        """
        Edits a current scenario with a JSON file
        :param scenario_json: JSON file with the new scenario
        :return: Response object containing the status of the request
        """
        response = Response()
        print(scenario_json)
        scenario_name = scenario_json["scenario_name"]
        if scenario_name in self.scenarios_dict:

            if "machines" in scenario_json:
                for machine in scenario_json["machines"]:

                    if scenario_json["machines"][machine]["uuid"] == "":
                        new_uuid = uuid.uuid4()
                        new_uuid = str(new_uuid).replace('-', '')
                        print("Unique id: ", new_uuid)
                        scenario_json['machines'][machine]['uuid'] = new_uuid

            scenario_json = Scenario(scenario_name).objectFromDictionary(
                scenario_json)

            self.scenarios_dict[scenario_name] = scenario_json
            #self._saveScenarioAsJSON(new_scenario)
            self.db_manager.editScenario(scenario_json.dictionary().copy())
            response.setResponse(True)
            response.setBody(self.scenarios_dict[scenario_name].dictionary())
        else:
            response.setReason('Scenario doesn\'t exist')
            response.setResponse(False)

            response.setBody(dict())
        return response.dictionary()

    def deleteOne(self, scenario_name):
        """
        Deletes one scenario from the database.
        :param scenario_name: Scenario's name string
        :return: Response object containing the status of the request
        """
        response = Response()
        if scenario_name in self.scenarios_dict:
            deleted_scenario = self.scenarios_dict.pop(scenario_name)
            #self.file_manager.deleteScenariosFolder(scenario_name)
            self.db_manager.deleteScenario(scenario_name)
            response.setResponse(True)
            response.setBody(deleted_scenario.dictionary())
        else:
            response.setResponse(False)
            response.setReason('Scenario doesn\'t exist')
            response.setBody(dict())
        return response.dictionary()

    def scenarioExists(self, scenario_name):
        """
        Check if a scenario exists.
        :param scenario_name: String with the scenario name
        :return: False if the scenario JSON file does not exist and the path to the JSON file if it exist
        """
        scenario_dir_path = self.file_manager.getScenariosPath(
        ) / scenario_name / "JSON"
        if not os.path.isdir(scenario_dir_path):
            print("Scenario %s directory not found" % scenario_name)
            return False
        else:
            scenario_json_path = scenario_dir_path / ''.join(
                [scenario_name, ".json"])
            if not os.path.exists(scenario_json_path):
                print("Scenario %s json not found" % scenario_name)
                return None
            else:
                return scenario_json_path

    def _saveScenarioAsJSON(self, scenario):
        """
        Saves a scenario as a JSON file
        :param scenario: Scenario's name string
        :return: None
        """
        scenario_json_path = self.file_manager.getScenarioJSONPath(
            scenario.scenario_name) / ''.join(
                [scenario.scenario_name, ".json"])
        if scenario_json_path:
            with open(scenario_json_path, 'w+') as outfile:
                outfile.write(json.dumps(scenario.dictionary(), indent=2))
                outfile.close()
        return
Exemplo n.º 5
0
class DatabaseManager():
    def __init__(self):
        self.file_manager = FileManager()
        self.url = ConfigManager().mongoURL()
        self.db_name = "soft_prac"
        self.scenarios_col_name = 'scenarios'
        self.exploits_col_name = 'exploits'
        self.vulnerabilities_col_name = 'vulnerabilities'
        self.client = pymongo.MongoClient(self.url)
        self.db = self.client[self.db_name]
        self.scenarios_col = self.db[self.scenarios_col_name]
        self.exploits_col = self.db[self.exploits_col_name]
        self.vulnerabilities_col = self.db[self.vulnerabilities_col_name]
        self.addScenariosToDB()
        self.addExploitsToDB()
        self.addVulnerabilitiesToDB()

    def _initializeScenariosFromDirectory(self):
        """
        Initializes the scenario's runtime objects using data from the host folders.
        :return: Dictionary containing scenario's data
        """
        # Variables
        scenarios_dict = dict()
        scenarios = os.listdir(self.file_manager.getScenariosPath())
        for scenario_name in scenarios:
            json_name = ''.join([scenario_name, ".json"])
            with open(
                    self.file_manager.getScenarioJSONPath(scenario_name) /
                    json_name) as outfile:
                scenario_dict = json.load(outfile)
            scenario = Scenario(scenario_name).objectFromDictionary(
                scenario_dict)
            scenarios_dict[scenario_name] = scenario
        return scenarios_dict

    def addScenariosToDB(self):
        """
        Pre-populates the database with scenarios.
        :return: None
        """
        scenarios_to_add = ['Scenario_1', 'Scenario_3']
        currentScenarios = self.getScenarios()
        scenarios_list = [
            scenario['scenario_name'] for scenario in currentScenarios
        ]
        scenarios_set = set(scenarios_list)
        for scenario_name in scenarios_to_add:
            if scenario_name not in scenarios_set:
                json_name = ''.join([scenario_name, ".json"])
                with open(
                        self.file_manager.getScenarioJSONPath(scenario_name) /
                        json_name) as outfile:
                    scenario_dict = json.load(outfile)
                scenario = Scenario(scenario_name).objectFromDictionary(
                    scenario_dict)
                self.insertScenario(scenario.dictionary().copy())
        return

    def addExploitsToDB(self):
        """
        Pre-populates the database with exploits.
        :return: None
        """
        exploits_to_add = [
            'Django_3_0_Cross-Site_Request_Forgery_Token_Bypass'
        ]
        currentExploits = self.getExploits()
        exploits_list = [exploit['name'] for exploit in currentExploits]
        exploits_set = set(exploits_list)
        for exploit_name in exploits_to_add:
            if exploit_name not in exploits_set:
                json_name = ''.join([exploit_name, ".json"])
                with open(
                        self.file_manager.getExploitJSONPath(exploit_name) /
                        json_name) as outfile:
                    exploit_dict = json.load(outfile)
                exploit = Exploit().objectFromDictionary(exploit_dict)
                self.insertExploit(exploit.dictionary().copy())
        return

    def addVulnerabilitiesToDB(self):
        """
        Pre-populates the database with vulnerabilities.
        :return: None
        """
        vulnerabilities_to_add = ['rConfig_3_9_searchColumn_SQL_Injection']
        currentVulnerabilities = self.getVulnerabilities()
        vulnerabilities_list = [
            vulnerability['name'] for vulnerability in currentVulnerabilities
        ]
        vulnerabilities_set = set(vulnerabilities_list)
        for vulnerability_name in vulnerabilities_to_add:
            if vulnerability_name not in vulnerabilities_set:
                json_name = ''.join([vulnerability_name, ".json"])
                with open(
                        self.file_manager.getVulnerabilityJSONPath(
                            vulnerability_name) / json_name) as outfile:
                    vulnerability_dict = json.load(outfile)
                vulnerability = Vulnerability().objectFromDictionary(
                    vulnerability_dict)
                self.insertVulnerability(vulnerability.dictionary().copy())
        return

    #CRUD: CREATE, READ, UPDATE and DELETE

    #Scenarios
    def insertScenario(self, scenario_json):
        """
        Inserts a scenario into the database.
        :param scenario_json: Scenario's JSON file to be inserted
        :return: Inserted document's id
        """
        doc = self.scenarios_col.insert_one(scenario_json)
        return doc.inserted_id

    def getScenarioNames(self):
        """
        Gets the scenario's names.
        :return: A list containing the scenarios names
        """
        return [doc['scenario_name'] for doc in self.scenarios_col.find()]

    def getScenarios(self):
        """
        Gets the scenarios from the databases.
        :return: A list containing scenarios in the database
        """
        return [doc for doc in self.scenarios_col.find()]

    def getScenario(self, scenario_name):
        """
        Gets a specific scenario from the database.
        :param scenario_name: Scenario's name string
        :return: A list containing the scenario retrieved from the database
        """
        query = {'scenario_name': scenario_name}
        return [doc for doc in self.scenarios_col.find(query)]

    def editScenario(self, scenario_json):
        """
        Edits a scenario in the database.
        :param scenario_json: JSON file containing scenario's data
        :return: Modified document's id
        """
        query = {'scenario_name': scenario_json['scenario_name']}
        new_doc = {"$set": scenario_json}
        doc = self.scenarios_col.update_one(query, new_doc)
        return doc.modified_count

    def deleteScenario(self, scenario_name):
        """
        Deletes a scenario from the database.
        :param scenario_name: Scenario's name string
        :return: Deleted document's id
        """
        query = {'scenario_name': scenario_name}
        doc = self.scenarios_col.delete_one(query)
        return doc.deleted_count

    #Exploits
    def insertExploit(self, exploit_json):
        """
        Inserts a scenario in the database.
        :param exploit_json: JSON file containing the exploit's data
        :return: Inserted document's id
        """
        doc = self.exploits_col.insert_one(exploit_json)
        return doc.inserted_id

    def getExploitNames(self):
        """
        Gets the exploits names from the database.
        :return: A list containing the exploits' names
        """
        return [doc['name'] for doc in self.exploits_col.find()]

    def getExploits(self):
        """
        Gets the exploits stored in the database.
        :return: A list containing the stored exploits' data
        """
        return [doc for doc in self.exploits_col.find()]

    def getExploit(self, exploit_name):
        """
        Gets an exploit from the database.
        :param exploit_name: Exploit's name string
        :return: A list containing the exploit data
        """
        query = {'name': exploit_name}
        return [doc for doc in self.exploits_col.find(query)]

    def editExploit(self, exploit_json):
        """
        Edits an exploit in the database.
        :param exploit_json: JSON file containing the exploit's data
        :return: Modified document's id
        """
        query = {'name': exploit_json['name']}
        new_doc = {"$set": exploit_json}
        doc = self.exploits_col.update_one(query, new_doc)
        return doc.modified_count

    def deleteExploit(self, exploit_name):
        """
        Deletes a exploit from the database.
        :param exploit_name: Exploit's name string
        :return: Deleted document's id
        """
        query = {'name': exploit_name}
        doc = self.exploits_col.delete_one(query)
        return doc.deleted_count

    #Vulnerabilities
    def insertVulnerability(self, vulnerability_json):
        """
        Inserts a vulnerability in the database.
        :param vulnerability_json: JSON file containing the vulnerability's data
        :return: Inserted document's id
        """
        doc = self.vulnerabilities_col.insert_one(vulnerability_json)
        return doc.inserted_id

    def getVulnerabilityNames(self):
        """
        Gets the vulnerabilities names from the database.
        :return: A list containing the vulnerability's names
        """
        return [doc['name'] for doc in self.vulnerabilities_col.find()]

    def getVulnerabilities(self):
        """
        Gets the vulnerabilities stored in the database.
        :return: A list containing the stored vulnerabilities' data
        """
        return [doc for doc in self.vulnerabilities_col.find()]

    def getVulnerability(self, vulnerability_name):
        """
        Gets a vulnerability from the database.
        :param vulnerability_name: Vulnerability's name string
        :return: A list containing the vulnerability's data
        """
        query = {'name': vulnerability_name}
        return [doc for doc in self.vulnerabilities_col.find(query)]

    def editVulnerability(self, vulnerability_json):
        """
        Edits a vulnerability in the database.
        :param vulnerability_json: JSON file containing the vulnerability's data
        :return: Modified document's id
        """
        query = {'name': vulnerability_json['name']}
        new_doc = {"$set": vulnerability_json}
        doc = self.vulnerabilities_col.update_one(query, new_doc)
        return doc.modified_count

    def deleteVulnerability(self, vulnerability_name):
        """
        Deletes a vulnerability from the database.
        :param vulnerability_name: Vulnerability's name string
        :return: Deleted document's id
        """
        query = {'name': vulnerability_name}
        doc = self.vulnerabilities_col.delete_one(query)
        return doc.deleted_count