def check_python_version(): """Checks if Python version is supported by Cuckoo. @raise CuckooStartupError: if version is not supported. """ if sys.version_info[:2] < (3, 5): raise CuckooStartupError("You are running an incompatible version " "of Python, please use >= 3.5")
def check_configs(): """Checks if config files exist. @raise CuckooStartupError: if config files do not exist. """ configs = ( "auxiliary.conf", "avd.conf", "cuckoo.conf", "esx.conf", "kvm.conf", "memory.conf", "physical.conf", "processing.conf", "qemu.conf", "reporting.conf", "virtualbox.conf", "vmware.conf", "vpn.conf", "vsphere.conf", "xenserver.conf", ) for config in [os.path.join(CUCKOO_ROOT, "conf", f) for f in configs]: if not os.path.exists(config): raise CuckooStartupError("Config file does not exist at " "path: {0}".format(config)) return True
def init_rooter(): """If required, check whether the rooter is running and whether we can connect to it.""" # The default configuration doesn't require the rooter to be ran. if not routing.vpn.enabled and \ not routing.tor.enabled and \ not routing.inetsim.enabled and \ not routing.socks5.enabled and \ routing.routing.route == "none": return s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM) try: s.connect(cuckoo.cuckoo.rooter) except socket.error as e: if e.strerror == "No such file or directory": raise CuckooStartupError( "The rooter is required but it is either not running or it " "has been configured to a different Unix socket path. " "(In order to disable the use of rooter, please set route " "and internet to none in cuckoo.conf and enabled to no in " "routing.conf).") if e.strerror == "Connection refused": raise CuckooStartupError( "The rooter is required but we can't connect to it as the " "rooter is not actually running. " "(In order to disable the use of rooter, please set route " "and internet to none in routing.conf).") if e.strerror == "Permission denied": raise CuckooStartupError( "The rooter is required but we can't connect to it due to " "incorrect permissions. Did you assign it the correct group? " "(In order to disable the use of rooter, please set route " "and internet to none in routing.conf).") raise CuckooStartupError("Unknown rooter error: %s" % e) rooter("cleanup_rooter") # Do not forward any packets unless we have explicitly stated so. rooter("forward_drop") rooter("state_disable") rooter("state_enable")
def create_structure(): """Creates Cuckoo directories.""" folders = ["db", "log", "storage", "storage/analyses", "storage/binaries"] try: create_folders(root=CUCKOO_ROOT, folders=folders) except CuckooOperationalError as e: raise CuckooStartupError(e)
def check_user_permissions(as_root: bool = False): if as_root: log.warning( "You running part of CAPE as non 'cape' user! That breaks permissions on temp folder and log folder." ) return if gt.getuser() != "cape": raise CuckooStartupError( f"Running as not 'cape' user breaks permissions! Run with cape user! Also fix permission on tmppath path: chown cape:cape {cuckoo.cuckoo.tmppath}\n log folder: chown cape:cape {os.path.join(CUCKOO_ROOT, 'logs')}" ) # Check permission for tmp folder if cuckoo.cuckoo.tmppath and not os.access(cuckoo.cuckoo.tmppath, os.W_OK): raise CuckooStartupError( f"Fix permission on\n tmppath path: chown cape:cape {cuckoo.cuckoo.tmppath}\n log folder: chown cape:cape {os.path.join(CUCKOO_ROOT, 'logs')}" )
def check_python_version(): """Checks if Python version is supported by Cuckoo. @raise CuckooStartupError: if version is not supported. """ version = sys.version.split()[0] if version < "2.6" or version >= "3": raise CuckooStartupError( "You are running an incompatible version of Python, please use 2.6 or 2.7" )
def check_working_directory(): """Checks if working directories are ready. @raise CuckooStartupError: if directories are not properly configured. """ if not os.path.exists(CUCKOO_ROOT): raise CuckooStartupError( f"You specified a non-existing root directory: {CUCKOO_ROOT}") cwd = os.path.join(os.getcwd(), "cuckoo.py") if not os.path.exists(cwd): raise CuckooStartupError( "You are not running Cuckoo from it's root directory") # Check permission for tmpfs if enabled if cuckoo.tmpfs.enabled and not os.access(cuckoo.tmpfs.path, os.W_OK): raise CuckooStartupError( f"Fix permission on tmpfs path: chown cape:cape {cuckoo.tmpfs.path}" )
def init_binaries(): """Inform the user about the need to periodically look for new analyzer binaries. These include the Windows monitor etc.""" dirpath = os.path.join(CUCKOO_ROOT, "data", "monitor", "latest") # Checks whether the "latest" symlink is available as well as whether # it points to an existing directory. if not os.path.exists(dirpath): raise CuckooStartupError( "The binaries used for Windows analysis are updated regularly, " "independently from the release line. It appears that you're " "not up-to-date. This can happen when you've just installed " "Cuckoo or when you've updated your Cuckoo version by pulling " "the latest changes from our Git repository. In order to get " "up-to-date, please run the following " "command: `./utils/community.py -wafb monitor` or " "`./utils/community.py -waf` if you'd also like to download " "over 300 Cuckoo signatures.") # If "latest" is a file and not a symbolic link, check if it's destination # directory is available. if os.path.isfile(dirpath): monitor = os.path.basename(open(dirpath, "rb").read().strip()) dirpath = os.path.join(CUCKOO_ROOT, "data", "monitor", monitor) else: dirpath = None if dirpath and not os.path.isdir(dirpath): raise CuckooStartupError( "The binaries used for Windows analysis are updated regularly, " "independently from the release line. It appears that you're " "not up-to-date. This can happen when you've just installed " "Cuckoo or when you've updated your Cuckoo version by pulling " "the latest changes from our Git repository. In order to get " "up-to-date, please run the following " "command: `./utils/community.py -wafb monitor` or " "`./utils/community.py -waf` if you'd also like to download " "over 300 Cuckoo signatures.")
def create_structure(): """Creates Cuckoo directories.""" folders = [ "log", "storage", os.path.join("storage", "analyses"), os.path.join("storage", "binaries"), os.path.join("data", "feeds"), ] try: create_folders(root=CUCKOO_ROOT, folders=folders) except CuckooOperationalError as e: raise CuckooStartupError(e)
def check_configs(): """Checks if config files exist. @raise CuckooStartupError: if config files do not exist. """ configs = [os.path.join(CUCKOO_ROOT, "conf", "cuckoo.conf"), os.path.join(CUCKOO_ROOT, "conf", "reporting.conf"), os.path.join(CUCKOO_ROOT, "conf", "auxiliary.conf")] for config in configs: if not os.path.exists(config): raise CuckooStartupError("Config file does not exist at " "path: {0}".format(config)) return True
def check_dependencies(): """Checks if dependencies are installed. @raise CuckooStartupError: if dependencies aren't met. """ check_python_version() dependencies = ["sqlite3"] for dependency in dependencies: try: __import__(dependency) except ImportError as e: raise CuckooStartupError("Unable to import \"%s\"" % dependency) return True
def check_signatures(): """Checks if user pulled in community signature modules @raise CuckooStartupError: if community signature modules not installed. """ sigpath = os.path.join(CUCKOO_ROOT, "modules", "signatures") bad = False if os.path.exists(sigpath): path, dirs, files = os.walk(sigpath).next() if len(files) < 20: bad = True else: bad = True if bad: raise CuckooStartupError("Signature modules are not installed. Please run: utils/community.py --force --rewrite --all")
def create_structure(): """Creates Cuckoo directories.""" folders = [ "log", "storage", os.path.join("storage", "analyses"), os.path.join("storage", "binaries"), os.path.join("data", "feeds"), os.path.join("data", "guacrecordings"), ] try: create_folders(root=CUCKOO_ROOT, folders=folders) except CuckooOperationalError as e: raise CuckooStartupError( f"Can't create folders. Ensure that you executed CAPE with proper USER! Maybe should be cape user?. %s", str(e))
def check_configs(): """Checks if config files exist. @raise CuckooStartupError: if config files do not exist. """ configs = [ os.path.join(CUCKOO_ROOT, "conf", "cuckoo.conf"), os.path.join(CUCKOO_ROOT, "conf", "reporting.conf"), os.path.join(CUCKOO_ROOT, "conf", "auxiliary.conf"), ] for config in configs: if not os.path.exists(config): raise CuckooStartupError("Config file does not exist at path: {0}".format(config)) if cuckoo.resultserver.ip in ("127.0.0.1", "localhost"): log.error("Bad resultserver address. You need to listen on virtual machines range. Ex: 10.0.0.1 not 127.0.0.1") return True
def init_yara(): """Generates index for yara signatures.""" categories = ("binaries", "urls", "memory", "CAPE", "macro") log.debug("Initializing Yara...") # Generate root directory for yara rules. yara_root = os.path.join(CUCKOO_ROOT, "data", "yara") # We divide yara rules in three categories. # CAPE adds a fourth # Loop through all categories. for category in categories: # Check if there is a directory for the given category. category_root = os.path.join(yara_root, category) if not os.path.exists(category_root): log.warning("Missing Yara directory: %s?", category_root) continue rules, indexed = {}, [] for category_root, _, filenames in os.walk(category_root, followlinks=True): for filename in filenames: if not filename.endswith((".yar", ".yara")): continue filepath = os.path.join(category_root, filename) try: # TODO Once Yara obtains proper Unicode filepath support we # can remove this check. See also this Github issue: # https://github.com/VirusTotal/yara-python/issues/48 assert len(str(filepath)) == len(filepath) except (UnicodeEncodeError, AssertionError): log.warning("Can't load Yara rules at %r as Unicode filepaths are " "currently not supported in combination with Yara!", filepath) continue rules["rule_%s_%d" % (category, len(rules))] = filepath indexed.append(filename) # Need to define each external variable that will be used in the # future. Otherwise Yara will complain. externals = { "filename": "", } try: File.yara_rules[category] = yara.compile(filepaths=rules, externals=externals) except yara.Error as e: raise CuckooStartupError("There was a syntax error in one or more Yara rules: %s" % e) # ToDo for Volatility3 yarascan # The memory.py processing module requires a yara file with all of its # rules embedded in it, so create this file to remain compatible. # if category == "memory": # f = open(os.path.join(yara_root, "index_memory.yar"), "w") # for filename in sorted(indexed): # f.write('include "%s"\n' % os.path.join(category_root, filename)) indexed = sorted(indexed) for entry in indexed: if (category, entry) == indexed[-1]: log.debug("\t `-- %s %s", category, entry) else: log.debug("\t |-- %s %s", category, entry)
def init_routing(): """Initialize and check whether the routing information is correct.""" # Check whether all VPNs exist if configured and make their configuration # available through the vpns variable. Also enable NAT on each interface. if vpn.vpn.enabled: for name in vpn.vpn.vpns.split(","): name = name.strip() if not name: continue if not hasattr(vpn, name): raise CuckooStartupError( "Could not find VPN configuration for %s" % name ) entry = vpn.get(name) #add = 1 #if not rooter("nic_available", entry.interface): #raise CuckooStartupError( # "The network interface that has been configured for " # "VPN %s is not available." % entry.name #) # add = 0 if not rooter("rt_available", entry.rt_table): raise CuckooStartupError( "The routing table that has been configured for " "VPN %s is not available." % entry.name ) vpns[entry.name] = entry # Disable & enable NAT on this network interface. Disable it just # in case we still had the same rule from a previous run. rooter("disable_nat", entry.interface) rooter("enable_nat", entry.interface) # Populate routing table with entries from main routing table. if cuckoo.routing.auto_rt: rooter("flush_rttable", entry.rt_table) rooter("init_rttable", entry.rt_table, entry.interface) # Check whether the default VPN exists if specified. if cuckoo.routing.route not in ("none", "internet", "tor", "inetsim"): if not vpn.vpn.enabled: raise CuckooStartupError( "A VPN has been configured as default routing interface for " "VMs, but VPNs have not been enabled in vpn.conf" ) if cuckoo.routing.route not in vpns: raise CuckooStartupError( "The VPN defined as default routing target has not been " "configured in vpn.conf." ) # Check whether the dirty line exists if it has been defined. if cuckoo.routing.internet != "none": if not rooter("nic_available", cuckoo.routing.internet): raise CuckooStartupError( "The network interface that has been configured as dirty " "line is not available." ) if not rooter("rt_available", cuckoo.routing.rt_table): raise CuckooStartupError( "The routing table that has been configured for dirty " "line interface is not available." ) # Disable & enable NAT on this network interface. Disable it just # in case we still had the same rule from a previous run. rooter("disable_nat", cuckoo.routing.internet) rooter("enable_nat", cuckoo.routing.internet) # Populate routing table with entries from main routing table. if cuckoo.routing.auto_rt: rooter("flush_rttable", cuckoo.routing.rt_table) rooter("init_rttable", cuckoo.routing.rt_table, cuckoo.routing.internet) # Check if tor interface exists, if yes then enable nat if cuckoo.routing.tor and cuckoo.routing.tor_interface: if not rooter("nic_available", cuckoo.routing.tor_interface): raise CuckooStartupError( "The network interface that has been configured as tor " "line is not available." ) # Disable & enable NAT on this network interface. Disable it just # in case we still had the same rule from a previous run. rooter("disable_nat", cuckoo.routing.tor_interface) rooter("enable_nat", cuckoo.routing.tor_interface) # Populate routing table with entries from main routing table. if cuckoo.routing.auto_rt: rooter("flush_rttable", cuckoo.routing.rt_table) rooter("init_rttable", cuckoo.routing.rt_table, cuckoo.routing.internet) # Check if inetsim interface exists, if yes then enable nat, if interface is not the same as tor #if cuckoo.routing.inetsim_interface and cuckoo.routing.inetsim_interface != cuckoo.routing.tor_interface: # Check if inetsim interface exists, if yes then enable nat if cuckoo.routing.inetsim and cuckoo.routing.inetsim_interface: if not rooter("nic_available", cuckoo.routing.inetsim_interface): raise CuckooStartupError( "The network interface that has been configured as inetsim " "line is not available." ) # Disable & enable NAT on this network interface. Disable it just # in case we still had the same rule from a previous run. rooter("disable_nat", cuckoo.routing.inetsim_interface) rooter("enable_nat", cuckoo.routing.inetsim_interface) # Populate routing table with entries from main routing table. if cuckoo.routing.auto_rt: rooter("flush_rttable", cuckoo.routing.rt_table) rooter("init_rttable", cuckoo.routing.rt_table, cuckoo.routing.internet)
def init_routing(): """Initialize and check whether the routing information is correct.""" # Check whether all VPNs exist if configured and make their configuration # available through the vpns variable. Also enable NAT on each interface. if routing.socks5.enabled: for name in routing.socks5.proxies.split(","): name = name.strip() if not name: continue if not hasattr(routing, name): raise CuckooStartupError("Could not find socks5 configuration for %s" % name) entry = routing.get(name) socks5s[entry.name] = entry if routing.vpn.enabled: for name in routing.vpn.vpns.split(","): name = name.strip() if not name: continue if not hasattr(routing, name): raise CuckooStartupError("Could not find VPN configuration for %s" % name) entry = routing.get(name) # add = 1 # if not rooter("nic_available", entry.interface): # raise CuckooStartupError( # "The network interface that has been configured for " # "VPN %s is not available." % entry.name # ) # add = 0 if not rooter("rt_available", entry.rt_table): raise CuckooStartupError("The routing table that has been configured for VPN %s is not available." % entry.name) vpns[entry.name] = entry # Disable & enable NAT on this network interface. Disable it just # in case we still had the same rule from a previous run. rooter("disable_nat", entry.interface) rooter("enable_nat", entry.interface) # Populate routing table with entries from main routing table. if routing.routing.auto_rt: rooter("flush_rttable", entry.rt_table) rooter("init_rttable", entry.rt_table, entry.interface) # If we are storage and webgui only but using as default route one of the workers exitnodes if repconf.distributed.master_storage_only: return # Check whether the default VPN exists if specified. if routing.routing.route not in ("none", "internet", "tor", "inetsim"): if not routing.vpn.enabled: raise CuckooStartupError( "A VPN has been configured as default routing interface for VMs, but VPNs have not been enabled in routing.conf" ) if routing.routing.route not in vpns and routing.routing.route not in socks5s: raise CuckooStartupError( "The VPN/Socks5 defined as default routing target has not been configured in routing.conf. You should use name field" ) # Check whether the dirty line exists if it has been defined. if routing.routing.internet != "none": if not rooter("nic_available", routing.routing.internet): raise CuckooStartupError("The network interface that has been configured as dirty line is not available.") if not rooter("rt_available", routing.routing.rt_table): raise CuckooStartupError("The routing table that has been configured for dirty line interface is not available.") # Disable & enable NAT on this network interface. Disable it just # in case we still had the same rule from a previous run. rooter("disable_nat", routing.routing.internet) rooter("enable_nat", routing.routing.internet) # Populate routing table with entries from main routing table. if routing.routing.auto_rt: rooter("flush_rttable", routing.routing.rt_table) rooter("init_rttable", routing.routing.rt_table, routing.routing.internet) # Check if tor interface exists, if yes then enable nat if routing.tor.enabled and routing.tor.interface: if not rooter("nic_available", routing.tor.interface): raise CuckooStartupError("The network interface that has been configured as tor line is not available.") # Disable & enable NAT on this network interface. Disable it just # in case we still had the same rule from a previous run. rooter("disable_nat", routing.tor.interface) rooter("enable_nat", routing.tor.interface) # Populate routing table with entries from main routing table. if routing.routing.auto_rt: rooter("flush_rttable", routing.routing.rt_table) rooter("init_rttable", routing.routing.rt_table, routing.routing.internet) # Check if inetsim interface exists, if yes then enable nat, if interface is not the same as tor # if routing.inetsim.interface and cuckoo.routing.inetsim_interface != routing.tor.interface: # Check if inetsim interface exists, if yes then enable nat if routing.inetsim.enabled and routing.inetsim.interface: if not rooter("nic_available", routing.inetsim.interface): raise CuckooStartupError("The network interface that has been configured as inetsim line is not available.") # Disable & enable NAT on this network interface. Disable it just # in case we still had the same rule from a previous run. rooter("disable_nat", routing.inetsim.interface) rooter("enable_nat", routing.inetsim.interface) # Populate routing table with entries from main routing table. if routing.routing.auto_rt: rooter("flush_rttable", routing.routing.rt_table) rooter("init_rttable", routing.routing.rt_table, routing.routing.internet)
def checkConfigs(): '''check for config file and define variables''' config = os.path.join(CUCKOO_ROOT,"cuckooinbox","cuckooinbox.conf") if not os.path.exists(config): raise CuckooStartupError("Config file does not exist at path: %s" % config)