def process(self, context, output): try: filename = output['filename'] self.gzip_file = os.path.join( get_path_in_data_folder("logs"), f"{context.session.guid}/screenshot_{filename}.gz" ) self.decompressed_file = os.path.join( get_path_in_data_folder("logs"), f"{context.session.guid}/screenshot_{filename}.jpg" ) file_chunk = output['data'] with open(self.gzip_file, 'ab+') as reassembled_gzip_data: reassembled_gzip_data.write(b64decode(file_chunk)) if output['current_chunk_n'] == (output['chunk_n'] + 1): try: with open(self.decompressed_file, 'wb') as reassembled_file: with gzip.open(self.gzip_file) as compressed_screenie: reassembled_file.write(compressed_screenie.read()) except Exception as e: logging.error(f"Error decompressing re-assembled screenshot: {e}") return f"Saved screenshot to {self.decompressed_file}!" else: return f"Processed chunk {output['current_chunk_n']}/{output['chunk_n'] + 1}" except TypeError: return output
def __init__(self, guid, psk): self._guid = str(guid) self._alias = str(guid) self._info = None self.address = None self.checkin_time = None self.crypto = ECDHE(psk=psk) self.jobs = Jobs(self) self.logger = logging.getLogger(f"session:{str(self._guid)}") self.logger.propagate = False self.logger.setLevel(logging.DEBUG) try: os.mkdir( os.path.join(get_path_in_data_folder("logs"), f"{self._guid}")) except FileExistsError: pass formatter = logging.Formatter('%(asctime)s - %(message)s') fh = logging.FileHandler(os.path.join( get_path_in_data_folder("logs"), f"{self._guid}/{self._guid}.log"), encoding='UTF-8') fh.setLevel(logging.DEBUG) fh.setFormatter(formatter) self.logger.addHandler(fh)
def start(args): if not os.path.exists(get_data_folder()): logging.info("First time use detected, creating data folder (~/.st)") os.makedirs(get_path_in_data_folder('logs')) if not os.path.exists(get_path_in_data_folder('logs')): os.mkdir(get_path_in_data_folder('logs')) loop = asyncio.get_event_loop() teamserver_digest = hmac.new(args['<password>'].encode(), msg=b'silenttrinity', digestmod=sha512).hexdigest() stop = asyncio.Future() for sig in (signal.SIGINT, signal.SIGTERM): loop.add_signal_handler(sig, stop.set_result, None) if args['--insecure']: logging.warning('SECURITY WARNING: --insecure flag passed, communication between client and server will be in cleartext!') if args['--debug']: logger = logging.getLogger() logger_handler = logging.StreamHandler() # Handler for the logger logger.addHandler(logger_handler) logger_handler.setFormatter(logging.Formatter( '[%(levelname)s] %(process)d %(threadName)s - %(filename)s: %(funcName)s - %(message)s')) logging.getLogger().setLevel(logging.DEBUG) loop.run_until_complete(server(stop, args, teamserver_digest))
def run(self): """ While we could use the standard decorators to register these routes, using add_url_rule() allows us to create diffrent endpoint names programmatically and pass the classes self object to the routes """ config = Config() config.accesslog = os.path.join(get_path_in_data_folder("logs"), "access.log") config.bind = f"{self['BindIP']}:{self['Port']}" config.insecure_bind = True config.include_server_header = False config.use_reloader = False config.debug = False http_blueprint = Blueprint(__name__, 'http') http_blueprint.before_request(self.check_if_naughty) #http_blueprint.after_request(self.make_normal) http_blueprint.add_url_rule('/<uuid:GUID>', 'key_exchange', self.key_exchange, methods=['POST']) http_blueprint.add_url_rule('/<uuid:GUID>', 'stage', self.stage, methods=['GET']) http_blueprint.add_url_rule('/<uuid:GUID>/jobs', 'jobs', self.jobs, methods=['GET']) http_blueprint.add_url_rule('/<uuid:GUID>/jobs/<job_id>', 'job_result', self.job_result, methods=['POST']) # Add a catch all route http_blueprint.add_url_rule('/', 'unknown_path', self.unknown_path, defaults={'path': ''}) http_blueprint.add_url_rule('/<path:path>', 'unknown_path', self.unknown_path, methods=['GET', 'POST']) #logging.getLogger('quart.app').setLevel(logging.DEBUG if state.args['--debug'] else logging.ERROR) #logging.getLogger('quart.serving').setLevel(logging.DEBUG if state.args['--debug'] else logging.ERROR) self.app = Quart(__name__) self.app.register_blueprint(http_blueprint) asyncio.run(serve(self.app, config))
def create_db_and_schema(db_path=get_path_in_data_folder("st.db")): with sqlite3.connect(db_path) as db: db.execute('''CREATE TABLE "sessions" ( "id" integer PRIMARY KEY, "guid" text, "psk" text, UNIQUE(guid,psk) )''')
async def server(stop, args, teamserver_digest): if not os.path.exists(get_path_in_data_folder("st.db")): logging.info('Creating database') await AsyncSTDatabase.create_db_and_schema() ts = TeamServer() ssl_context = None if not args['--insecure']: ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) try: ssl_context.load_cert_chain( get_path_in_data_folder("chain.pem") ) except FileNotFoundError: create_self_signed_cert() ssl_context.load_cert_chain( get_path_in_data_folder("chain.pem") ) server_cert_fingerprint = get_cert_fingerprint(get_path_in_data_folder("cert.pem")) logging.warning( (f"{colored('Teamserver certificate fingerprint:', 'yellow')} " f"{colored(server_cert_fingerprint.hex(), 'red')}") ) STWebSocketServerProtocol.teamserver_digest = teamserver_digest async with websockets.serve( ts.connection_handler, host=args['<host>'], port=int(args['--port']), create_protocol=STWebSocketServerProtocol, ssl=ssl_context, ping_interval=None, ping_timeout=None ): logging.info(colored(f"Teamserver started on {args['<host>']}:{args['--port']}", "yellow")) await stop
def start(args): if not os.path.exists(get_data_folder()): logging.info("First time use detected, creating data folder (~/.st)") os.makedirs(get_path_in_data_folder('logs')) if not os.path.exists(get_path_in_data_folder('logs')): os.mkdir(get_path_in_data_folder('logs')) loop = asyncio.get_event_loop() teamserver_digest = hmac.new(args['<password>'].encode(), msg=b'silenttrinity', digestmod=sha512).hexdigest() stop = asyncio.Future() for sig in (signal.SIGINT, signal.SIGTERM): loop.add_signal_handler(sig, stop.set_result, None) if args['--insecure']: logging.warning( 'SECURITY WARNING: --insecure flag passed, communication between client and server will be in cleartext!' ) loop.run_until_complete(server(stop, args, teamserver_digest))
def process(self, context, output): if self._new_dmp_file == True: self._new_dmp_file = False self.fname = ntpath.basename(self.options['Src']['Value']) self.gzip_file = os.path.join( get_path_in_data_folder("logs"), f"{context.session.guid}/downloader_{datetime.now().strftime('%Y_%m_%d_%H%M%S')}.gz" ) self.decompressed_file = os.path.join( get_path_in_data_folder("logs"), f"{context.session.guid}/downloader_{datetime.now().strftime('%Y_%m_%d_%H%M%S')}_{self.fname}" ) try: file_chunk = output['data'] with open(self.gzip_file, 'ab+') as reassembled_gzip_file: reassembled_gzip_file.write(b64decode(file_chunk)) if output['current_chunk_n'] == (output['chunk_n'] + 1): try: with open(self.decompressed_file, 'wb') as reassembled_file: with gzip.open(self.gzip_file) as compressed_file: reassembled_file.write(compressed_file.read()) os.remove(self.gzip_file) except Exception as e: logging.error( f"Error decompressing re-assembled file: {e}") self._new_dmp_file = True return else: return f"Processed chunk {output['current_chunk_n']}/{output['chunk_n'] + 1}" except TypeError: return output
def test_listeners(listener_loader): os.makedirs(get_path_in_data_folder('logs'), exist_ok=True) s = requests.Session() retries = Retry(total=3, backoff_factor=0.5) s.verify = False s.mount('http://', HTTPAdapter(max_retries=retries)) s.mount('https://', HTTPAdapter(max_retries=retries)) for l in listener_loader.loaded: print(f"Testing listener '{l.name}'") assert isinstance(l, Listener) == True if l.name in ['http', 'https']: l['BindIP'] = '127.0.0.1' l['Port'] = str(random.randint(3000, 6000)) if l.name == 'https': l['Cert'] = CERT_PATH l['key'] = KEY_PATH l.start() r = s.get(f"{l.name}://127.0.0.1:{l['Port']}/") assert r.status_code == 404 l.stop() assert l.running == False
def __init__(self, db_path=get_path_in_data_folder("st.db")): self.db_path = db_path
def run(self): if (self['Key'] == '~/.st/key.pem') and (self['Cert'] == '~/.st/cert.pem'): if not os.path.exists( get_path_in_data_folder("key.pem")) or not os.path.exists( get_path_in_data_folder( "cert.pem")) or self['RegenCert']: create_self_signed_cert() config = Config() config.ciphers = 'ALL' config.accesslog = os.path.join(get_path_in_data_folder("logs"), "access.log") config.bind = f"{self['BindIP']}:{self['Port']}" config.certfile = os.path.expanduser(self['Cert']) config.keyfile = os.path.expanduser(self['Key']) config.include_server_header = False # This doesn't seem to do anything? config.use_reloader = False config.debug = False """ While we could use the standard decorators to register these routes, using add_url_rule() allows us to create diffrent endpoint names programmatically and pass the classes self object to the routes """ http_blueprint = Blueprint(__name__, 'https') http_blueprint.before_request(self.check_if_naughty) #http_blueprint.after_request(self.make_normal) http_blueprint.add_url_rule('/<uuid:GUID>', 'key_exchange', self.key_exchange, methods=['POST']) http_blueprint.add_url_rule('/<uuid:GUID>', 'stage', self.stage, methods=['GET']) http_blueprint.add_url_rule('/<uuid:GUID>/jobs', 'jobs', self.jobs, methods=['GET']) http_blueprint.add_url_rule('/<uuid:GUID>/jobs/<job_id>', 'job_result', self.job_result, methods=['POST']) # Add a catch all route http_blueprint.add_url_rule('/', 'unknown_path', self.unknown_path, defaults={'path': ''}) http_blueprint.add_url_rule('/<path:path>', 'unknown_path', self.unknown_path, methods=['GET', 'POST']) #logging.getLogger('quart.app').setLevel(logging.DEBUG if state.args['--debug'] else logging.ERROR) #logging.getLogger('quart.serving').setLevel(logging.DEBUG if state.args['--debug'] else logging.ERROR) self.app = Quart(__name__) self.app.register_blueprint(http_blueprint) asyncio.run(serve(self.app, config))