예제 #1
0
class CampaignExportManager:

    db = Database()

    def export_campaign_database(self, username, cid):
        # check user is admin
        # check campaign exists
        # check user has read access to campaign

        return

    def generate_database_(self):
        # get information (func)
        # check database export directory exists
        # check file doesn't exist
        # create campaign_name_unixtime
        # create database
        # encrypt
        # return file, return password
        return

    def get_information(self):
        return

    def database_file_storage_check(self):
        return
예제 #2
0
class AppManager:
    db = None

    def __init__(self):
        self.db = Database()

    @staticmethod
    def check_software_version():
        # Returns "True" if the software is behind GitHubs master version file.
        url = "https://raw.githubusercontent.com/Ziconius/FudgeC2/master/version.txt"
        try:
            request_result = requests.get(url, timeout=0.5)
            master = request_result.content.decode()
            with open("../version.txt", 'r') as v_file:
                local_version_number = str(v_file.read())
                if LooseVersion(master) > LooseVersion(local_version_number):
                    return True
                else:
                    return False
        except Exception as exception_text:
            print(exception_text)
            return False

    @staticmethod
    def get_software_verision_number():
        try:
            with open("../version.txt", 'r') as v_file:
                local_version_number = str(v_file.read())
                return local_version_number
        except Exception as exception_text:
            print(exception_text)
            return "0.0.0"

    def campaign_create_campaign(self, user, form):
        # Responsible for validating admin account, and campaign title exists.
        if self.db.user.User_IsUserAdminAccount(user) is True:
            if 'title' in form and 'description' in form:
                if form['title'].strip() != "":
                    if self.db.campaign.create_campaign(user, form['title'].strip(), form['description'].strip()) is True:
                        return True, "Campaign created successfully."
                    else:
                        return False, "Unknown error."
                else:
                    return False, "You must supply both title and description values."
            else:
                return False, "You must supply both title and description values."
        else:
            return False, "You do not have admin permissions to create a campaign."

    def campaign_get_campaign_name_from_cid(self, cid):
        return self.db.campaign.Get_CampaignNameFromCID(cid)

    # TODO: Implement returning app logs to web app.
    def get_application_logs(self, username):
        # is user admin if not return false.
        if self.db.user.User_IsUserAdminAccount(username):
            return self.db.get_application_logs()
        else:
            return []
예제 #3
0
class UserManagementController:
    db = Database()

    def AddUser(self, formdata=None, submitting_user=None):
        # -- Refacteror/Clean Add failure checks
        # -- Check for the keys in formdata, if none then return an error.
        # -- UserName/is_admin

        Result_Dict = {
            "action": "Add New User",
            "result": None,
            "reason": None
        }
        # TODO: Review if minimum lenght usernames should be permitted.
        if len(formdata['UserName']) < 3:
            Result_Dict['result'] = False
            Result_Dict['reason'] = "Username too short"
            return Result_Dict
        U = self.db.Get_UserObject(submitting_user)
        if U.admin:
            G = self.db.Get_UserObject(formdata['UserName'])
            admin = False
            if 'is_admin' in formdata:
                admin = True
            if G == None:
                N = 8
                pw = ''.join(
                    random.choices(string.ascii_uppercase + string.digits,
                                   k=N))
                self.db.Add_User(formdata['UserName'], pw, admin)
                Result_Dict['result'] = True
                Result_Dict['reason'] = str(
                    formdata['UserName'] + " now created. Password is: " + pw +
                    " <br> Take note of this, it will not be visable again.")
            else:
                Result_Dict['result'] = False
                Result_Dict['reason'] = "User already exists."
            # -- Validate

        return Result_Dict

    def AddUserToCampaign(self, Submitter, Users, Campaign, Rights=0):
        # -- Refactor with Try/Catch validating the Rights values.
        '''
        :param Submitter: string
        :param Users: Request.form (dict)
        :param Campaign: int
        :param Rights: int
        :return: bool
        '''
        # Remove Right kawgs.
        # Improve variable names
        # --
        if len(Users) < 1:
            return False
        if Users:
            for User in Users:
                S = self.db.Get_UserObject(Submitter)
                if S.admin:
                    U = self.db.Get_UserObject(User)
                    if U:
                        C = self.db.Verify_UserCanAccessCampaign(
                            S.user_email, Campaign)
                        if C:
                            self.db.User_SetCampaignAccessRights(
                                U.uid, Campaign, Users[User])
                else:
                    return False
            return True
예제 #4
0
class ImplantManagement:
    # -- The implant management class is responsible for performing pre-checks and validation before sending data
    # --    to the Implant class
    db = Database()
    Imp = ImplantSingleton.instance

    def _form_validated_obfucation_level_(self, form):
        if "obfuscation" in form:
            print(form)
            if int(form['obfuscation']):
                if int(form['obfuscation']) < 0:
                    return 0
                elif int(form['obfuscation']) > 3:
                    return 3
                else:
                    return int(form['obfuscation'])
        return None


    def _validate_command(self, command):
        # -- TODO: Check if type needs to be enforced.
        special_cmd = ["sys_info"]
        if command[0:2] == "::":
            preprocessed_command = command[2:].lower().strip()
            if preprocessed_command in special_cmd:
                postprocessed_command = ":: "+preprocessed_command
                return postprocessed_command, True
            return command, {"cmd_reg":{"result":False, "reason":"Unknown inbuilt command, i.e. '::'"}}
        return command, True


    def ImplantCommandRegistration(self, cid , username, form):
        # -- This should be refactored at a later date to support read/write changes to
        # --    granular controls on templates, and later specific implants
        #print("CID: ",cid,"\nUSR: "******"\nCMD: ",form)
        User = self.db.Verify_UserCanWriteCampaign(username,cid)
        if User == False:
            return {"cmd_reg":{"result":False,"reason":"You are not authorised to register commands in this campaign."}}

        # -- Get All implants or implants by name then send to 'implant.py'
        # -- email, unique implant key, cmd
        if "cmd" in form and "ImplantSelect" in form:
            # -- before checking the database assess the cmd that was input.
            processed_command, validated_command = self._validate_command(form['cmd'])
            if validated_command != True:
                return validated_command

            # -- If validated_command is True then continue as it IS a valid command. N.b it may not be a legitimate command, but it is considered valid here.
            if form['ImplantSelect'] == "ALL":
                ListOfImplants = self.db.Get_AllGeneratedImplantsFromCID(cid)
            else:
                ListOfImplants= self.db.Get_AllImplantIDFromTitle(form['ImplantSelect'])
            # -- Access if this can fail. If empty return error.
            if len(ListOfImplants) == 0:
                return {"cmd_reg":{"result":False,"reason":"No implants listed."}}
            for implant in ListOfImplants:
                # -- Create return from the Implant.AddCommand() method.
                self.Imp.AddCommand(username,cid,implant['unique_implant_id'], processed_command)
            return {"cmd_reg":{"result":True,"reason":"Command registered"}}
        return {"cmd_reg":{"result":False,"reason":"Incorrect implant given, or non-existent active implant."}}


    def CreateNewImplant(self,cid, form, user):
        # TODO: Create checks for conflicting ports.
        implant_configuration = {
            "title": None,
            "description": None,
            "url": None,
            "beacon": None,
            "inital_delay": None,
            "obfuscation_level": None,
            "protocol": {
                "comms_http": None,
                "comms_https": None,
                "comms_binary": None,
                "comms_dns": None
            }
        }
        User = self.db.Get_UserObject(user)
        if User.admin == 0:
            return False, "Insufficient privileges."
        CampPriv = self.db.Verify_UserCanWriteCampaign(user, cid)
        if CampPriv is False:
            return False, "User cannot write to this campaign."

        try:
            if "CreateImplant" in form:
                obfuscation_level = self._form_validated_obfucation_level_(form)
                if obfuscation_level is None:
                    raise ValueError('Missing, or invalid obfuscation levels')
                else:
                    implant_configuration['obfuscation_level'] = obfuscation_level

                # -- Test for initial callback delay
                if 'initial_delay' in form:
                    if int(form['initial_delay']) and int(form['initial_delay']) >= 0:
                        implant_configuration['initial_delay'] = form['initial_delay']
                    else:
                        raise ValueError("Initial delay must be positive integer.")
                else:
                    raise ValueError("Initial delay not submitted.")
                # -- Test for beacon delay
                if 'beacon_delay' in form:
                    if int(form['beacon_delay']) >= 1:
                        implant_configuration['beacon'] = form['beacon_delay']
                    else:
                        raise ValueError("Beacon delay must an integer greater than 1 second.")
                else:
                    raise ValueError("No beacon delay submitted.")

                if form['title'] == "" or form['url'] == "" or form['description'] == "":
                    raise ValueError('Mandatory values left blank')
                else:
                    implant_configuration['title'] = form['title']
                    implant_configuration['url'] = form['url']
                    implant_configuration['description'] = form['description']
                    implant_configuration['beacon'] = form['beacon_delay']

                a = {"comms_http": "http-port",
                     "comms_https": "https-port",
                     "comms_dns": "dns-port",
                     "comms_binary": "binary-port"}
                for element in a.keys():
                    print("::", element)
                    if element in form:
                        # print("@@", form[a[element]])
                        if int(form[a[element]]):
                            if int(form[a[element]]) > 0 or int(form[a[element]]) < 65536:
                                # print(int(form[a[element]]))
                                implant_configuration["protocol"][element] = int(form[a[element]])
                            else:
                                raise ValueError("Submitted port for {} is out of range".format(a[element]))
                        else:
                            # print(form[element])
                            raise ValueError("Ports must be submitted as an integer")

                protocol_set = False
                for proto in implant_configuration['protocol'].keys():
                    if implant_configuration['protocol'][proto] is None:
                        protocol_set = True
                if protocol_set is False:
                    raise ValueError('No protocol selected, ensure a protocol and port are selected.')

                # print("Final configuration:")
                # for element in implant_configuration.keys():
                #     print(element,": ",implant_configuration[element])

                a = self.db.Add_Implant(cid, implant_configuration)
                if a is True:
                    return True, "Implant created."
                else:
                    raise ValueError("Error creating entry. Ensure implant title is unique.")

        except Exception as E:
            return (False, E)

        return


    def Get_RegisteredImplantCommands(self, username, cid=0):
        # -- Return list of dictionaries, not SQLAlchemy Objects.
        if self.db.Verify_UserCanAccessCampaign(username, cid):
            Commands = self.db.Get_RegisteredImplantCommandsFromCID(cid)
            toDict = []
            for x in Commands:
                a = x.__dict__
                if '_sa_instance_state' in a:
                    del a['_sa_instance_state']
                toDict.append(a)
            return toDict
        else:
            return False


    def Get_CampaignLogs(self, username, cid):
        User = self.db.Verify_UserCanReadCampaign(username, cid)
        if User == False:
            return {
                "cmd_reg": {"result": False, "reason": "You are not authorised to view commands in this campaign."}}
        return self.db.Log_GetCampaignActions(cid)
예제 #5
0
from flask import Flask, render_template, flash, request, jsonify, g, current_app, url_for, redirect, make_response, send_file, send_from_directory
import base64
from uuid import uuid4
from FudgeC2.Implant.Implant import ImplantSingleton
from FudgeC2.Data.Database import Database

Imp = ImplantSingleton.instance
db = Database()

app = Flask(str(uuid4()))
app.config['SECRET_KEY'] = str(uuid4())


def ImplantManager(a):
    if "X-Implant" in a:
        print("Checked in implant is: ", a["X-Implant"])


@app.before_request
def before_request():
    # TODO: Implement IP whitelist and reject if connection if it is not a valid src IP.
    return


@app.after_request
def add_header(r):
    #r.headers["X-Command"] = a
    return r


# -- TODO: extracted and added into a new stager specific listener(?)
예제 #6
0
class ListenerManagement():
    # TODO: Add checks for failed/failing listeners (i.e. certs not configured & thread dies.)
    active_listener = 0
    listeners = {}
    db = Database()
    tls_cert = None
    tls_key = None

    def __init__(self, tls_listener_cert, tls_listener_key):
        # TODO: Implement checks to validate files at this point.
        self.tls_cert = tls_listener_cert
        self.tls_key = tls_listener_key

    def check_tls_certificates(self):
        cert_result = os.path.isfile(os.getcwd() + "/Storage/" + self.tls_cert)
        key_result = os.path.isfile(os.getcwd() + "/Storage/" + self.tls_key)
        if key_result is False or cert_result is False:
            print(
                "Warning: ListenerManagement.check_tls_certificates() has failed. Generate certificates."
            )
            return False
        else:
            return True

    def create_listener(self,
                        listener_name,
                        listener_type,
                        port=None,
                        auto_start=False,
                        url=None):
        # Listener States:
        # 0 : Stopped
        # 1 : Running
        # 2 : Awaiting Stop
        # 3 : Awaiting Start
        supported_listeners = ["http", "https"]
        a = self.__check_for_listener_duplicate_element(
            listener_name, "common_name")
        if a == False:
            return (False, "Existing listener name found.")
        a = self.__check_for_listener_duplicate_element(port, "port")
        if a == False:
            return (False, "Existing port found.")

        if listener_type in supported_listeners:
            if int(port):

                # TODO: Likely to contain bugs if deletion is implemented?
                id = "0000" + str(len(self.listeners))
                id = id[-4:]

                # --
                listener = {
                    "type": listener_type,
                    "port": port,
                    "state": int(0),
                    "id": id,
                    "common_name": listener_name
                }
                if auto_start == True:
                    listener["state"] = int(3)

                self.__validate_listener(listener)
                self.listeners[id] = listener

                if auto_start == True:
                    self.__review_listeners()
            else:
                return (False, "Please submit the port as an integer.")
            return (False, "Invalid listener configuration.")
        return (True, "Success")

    def listener_form_submission(self, user, form):
        # This will process the values submitted and decided what to call next
        #   these will require further management
        if not self.db.User_IsUserAdminAccount(user):
            return (False, "Insufficient privileges")
        # else:
        #     return (True, "Temp success value.")
        if 'state_change' in form:
            # print("State change requested")
            if self.listeners[form['state_change']]['state'] == 0:
                # print(form['state_change'])
                self.update_listener(form['state_change'], "start")
            elif self.listeners[form['state_change']]['state'] == 1:
                # print(form['state_change'])
                self.update_listener(form['state_change'], "stop")

        elif 'listener_name' in form and 'listener_protocol' in form and 'listener_port' in form:
            # print("Adding new listener")
            if 'auto_start' in form:
                auto_start = True
            else:
                auto_start = False
            a = self.create_listener(form['listener_name'],
                                     form['listener_protocol'].lower(),
                                     form['listener_port'], auto_start)
            return a

        return (True, "Implant started sucessfully.")

    # User action
    def update_listener(self, id, action):
        # print(id,action)
        if action == "stop":
            self.listeners[id]["state"] = 2
        if action == "start":
            self.listeners[id]["state"] = 3
        self.__review_listeners()
        return

    # Review Data
    def get_active_listeners(self, type=None):
        return self.listeners

    def __check_for_listener_duplicate_element(self, value, key):
        for listener_id in self.listeners.keys():
            if self.listeners[listener_id][key] == value:
                print(value, key)
                return False
        return True

    def __review_listeners(self):
        for listener_id in self.listeners.keys():
            if int(self.listeners[listener_id]['state']) == 2:
                self.__stop_listener(listener_id)
            if int(self.listeners[listener_id]['state']) == 3:
                self.__start_listener(listener_id)

    def __start_listener(self, id):
        self.listeners[id]['state'] = 1
        if self.listeners[id]['type'] == "http":
            self.__start_http_listener(self.listeners[id])
        elif self.listeners[id]['type'] == "https":
            self.__start_https_listener(self.listeners[id])
        elif self.listeners[id]['type'] == "dns":
            self.__start_dns_listener(self.listeners[id])
        return

    def __stop_listener(self, id):
        self.listeners[id]['state'] = 0
        return

    def __validate_listener(self, listener):
        # This will check for any conflicting arguments i.e. conflicting ports.
        return True

    # TODO: Refactor this code to remove as much code duplication.
    def __start_http_listener(self, obj):
        flask_listener_object = self.create_app("http")
        self.listeners[
            obj['id']]['listener_thread'] = _thread.start_new_thread(
                self.start_http_listener_thread, (
                    obj,
                    flask_listener_object,
                ))

    def __start_https_listener(self, obj):
        flask_listener_object = self.create_app("https")
        self.listeners[
            obj['id']]['listener_thread'] = _thread.start_new_thread(
                self.start_https_listener_thread, (
                    obj,
                    flask_listener_object,
                ))

    def __start_dns_listener(self, obj):
        # -- This listener is not implemented yet.
        return

    def __start_binary_listener(self, obj):
        # -- This listener is not implemented yet.
        return

    def create_app(self, listener_type):
        import FudgeC2.Listeners.HttpListener
        del sys.modules["FudgeC2.Listeners.HttpListener"]
        import FudgeC2.Listeners.HttpListener as HL
        HL.app.config['listener_type'] = listener_type
        return HL.app

    def start_http_listener_thread(self, obj, App):
        App.run(debug=False,
                use_reloader=False,
                host='0.0.0.0',
                port=obj['port'],
                threaded=True)

    def start_https_listener_thread(self, obj, App):
        path = os.getcwd() + "/Storage/"
        if self.check_tls_certificates():
            App.run(debug=False,
                    use_reloader=False,
                    host='0.0.0.0',
                    port=obj['port'],
                    threaded=True,
                    ssl_context=(path + self.tls_cert, path + self.tls_key))
        else:
            print()
            # -- User has not set up certificates in the Storage dir
            return False
예제 #7
0
 def __init__(self):
     self.db = Database()