diff --git a/monkey/common/common_consts/telem_categories.py b/monkey/common/common_consts/telem_categories.py index 669b2379c..0697fd4f7 100644 --- a/monkey/common/common_consts/telem_categories.py +++ b/monkey/common/common_consts/telem_categories.py @@ -8,4 +8,3 @@ class TelemCategoryEnum: SCAN = "scan" STATE = "state" TRACE = "trace" - TUNNEL = "tunnel" diff --git a/monkey/infection_monkey/control.py b/monkey/infection_monkey/control.py index 3aedeb272..7f161ecbd 100644 --- a/monkey/infection_monkey/control.py +++ b/monkey/infection_monkey/control.py @@ -2,20 +2,16 @@ import json import logging import platform from socket import gethostname -from typing import Mapping, Optional import requests +from urllib3 import disable_warnings -import infection_monkey.tunnel as tunnel from common.common_consts.timeouts import LONG_REQUEST_TIMEOUT, MEDIUM_REQUEST_TIMEOUT from infection_monkey.config import GUID from infection_monkey.network.info import get_host_subnets, local_ips -from infection_monkey.transport.http import HTTPConnectProxy -from infection_monkey.transport.tcp import TcpProxy from infection_monkey.utils import agent_process -from infection_monkey.utils.environment import is_windows_os -requests.packages.urllib3.disable_warnings() +disable_warnings() # noqa DUO131 logger = logging.getLogger(__name__) @@ -28,8 +24,7 @@ class ControlClient: # https://github.com/guardicore/monkey/blob/133f7f5da131b481561141171827d1f9943f6aec/monkey/infection_monkey/telemetry/base_telem.py control_client_object = None - def __init__(self, server_address: str, proxies: Optional[Mapping[str, str]] = None): - self.proxies = {} if not proxies else proxies + def __init__(self, server_address: str): self.server_address = server_address def wakeup(self, parent=None): @@ -50,37 +45,14 @@ class ControlClient: "launch_time": agent_process.get_start_time(), } - if self.proxies: - monkey["tunnel"] = self.proxies.get("https") - requests.post( # noqa: DUO123 f"https://{self.server_address}/api/agent", data=json.dumps(monkey), headers={"content-type": "application/json"}, verify=False, - proxies=self.proxies, timeout=MEDIUM_REQUEST_TIMEOUT, ) - def set_proxies(self, proxy_find): - """ - Note: The proxy schema changes between different versions of requests and urllib3, - which causes the machine to not open a tunnel back. - If we get "ValueError: check_hostname requires server_hostname" or - "Proxy URL had not schema, should start with http:// or https://" errors, - the proxy schema needs to be changed. - Keep this in mind when upgrading to newer python version or when urllib3 and - requests are updated there is possibility that the proxy schema is changed. - https://github.com/psf/requests/issues/5297 - https://github.com/psf/requests/issues/5855 - """ - proxy_address, proxy_port = proxy_find - logger.info("Found tunnel at %s:%s" % (proxy_address, proxy_port)) - if is_windows_os(): - self.proxies["https"] = f"http://{proxy_address}:{proxy_port}" - else: - self.proxies["https"] = f"{proxy_address}:{proxy_port}" - def send_telemetry(self, telem_category, json_data: str): if not self.server_address: logger.error( @@ -95,7 +67,6 @@ class ControlClient: data=json.dumps(telemetry), headers={"content-type": "application/json"}, verify=False, - proxies=self.proxies, timeout=MEDIUM_REQUEST_TIMEOUT, ) except Exception as exc: @@ -111,41 +82,16 @@ class ControlClient: data=json.dumps(telemetry), headers={"content-type": "application/json"}, verify=False, - proxies=self.proxies, timeout=MEDIUM_REQUEST_TIMEOUT, ) except Exception as exc: logger.warning(f"Error connecting to control server {self.server_address}: {exc}") - def create_control_tunnel(self, keep_tunnel_open_time: int): - if not self.server_address: - return None - - my_proxy = self.proxies.get("https", "").replace("https://", "") - if my_proxy: - proxy_class = TcpProxy - try: - target_addr, target_port = my_proxy.split(":", 1) - target_port = int(target_port) - except ValueError: - return None - else: - proxy_class = HTTPConnectProxy - target_addr, target_port = None, None - - return tunnel.MonkeyTunnel( - proxy_class, - keep_tunnel_open_time=keep_tunnel_open_time, - target_addr=target_addr, - target_port=target_port, - ) - def get_pba_file(self, filename): try: return requests.get( # noqa: DUO123 PBA_FILE_DOWNLOAD % (self.server_address, filename), verify=False, - proxies=self.proxies, timeout=LONG_REQUEST_TIMEOUT, ) except requests.exceptions.RequestException: diff --git a/monkey/infection_monkey/exploit/caching_agent_binary_repository.py b/monkey/infection_monkey/exploit/caching_agent_binary_repository.py index f3d4dc73a..745aae112 100644 --- a/monkey/infection_monkey/exploit/caching_agent_binary_repository.py +++ b/monkey/infection_monkey/exploit/caching_agent_binary_repository.py @@ -1,7 +1,6 @@ import io import threading from functools import lru_cache -from typing import Mapping import requests @@ -18,9 +17,8 @@ class CachingAgentBinaryRepository(IAgentBinaryRepository): request is actually sent to the island for each requested binary. """ - def __init__(self, island_url: str, proxies: Mapping[str, str]): + def __init__(self, island_url: str): self._island_url = island_url - self._proxies = proxies self._lock = threading.Lock() def get_agent_binary( @@ -40,7 +38,6 @@ class CachingAgentBinaryRepository(IAgentBinaryRepository): response = requests.get( # noqa: DUO123 f"{self._island_url}/api/agent-binaries/{os_name}", verify=False, - proxies=self._proxies, timeout=MEDIUM_REQUEST_TIMEOUT, ) diff --git a/monkey/infection_monkey/master/control_channel.py b/monkey/infection_monkey/master/control_channel.py index 8c6653573..b1b4bae81 100644 --- a/monkey/infection_monkey/master/control_channel.py +++ b/monkey/infection_monkey/master/control_channel.py @@ -1,7 +1,7 @@ import json import logging from pprint import pformat -from typing import MutableMapping, Optional, Sequence +from typing import Optional, Sequence from uuid import UUID import requests @@ -22,10 +22,9 @@ logger = logging.getLogger(__name__) class ControlChannel(IControlChannel): - def __init__(self, server: str, agent_id: str, proxies: MutableMapping[str, str]): + def __init__(self, server: str, agent_id: str): self._agent_id = agent_id self._control_channel_server = server - self._proxies = proxies def register_agent(self, parent: Optional[UUID] = None): agent_registration_data = AgentRegistrationData( @@ -44,7 +43,6 @@ class ControlChannel(IControlChannel): url, json=agent_registration_data.dict(simplify=True), verify=False, - proxies=self._proxies, timeout=SHORT_REQUEST_TIMEOUT, ) response.raise_for_status() @@ -68,7 +66,6 @@ class ControlChannel(IControlChannel): response = requests.get( # noqa: DUO123 url, verify=False, - proxies=self._proxies, timeout=SHORT_REQUEST_TIMEOUT, ) response.raise_for_status() @@ -89,7 +86,6 @@ class ControlChannel(IControlChannel): response = requests.get( # noqa: DUO123 f"https://{self._control_channel_server}/api/agent-configuration", verify=False, - proxies=self._proxies, timeout=SHORT_REQUEST_TIMEOUT, ) response.raise_for_status() @@ -116,7 +112,6 @@ class ControlChannel(IControlChannel): response = requests.get( # noqa: DUO123 propagation_credentials_url, verify=False, - proxies=self._proxies, timeout=SHORT_REQUEST_TIMEOUT, ) response.raise_for_status() diff --git a/monkey/infection_monkey/model/host.py b/monkey/infection_monkey/model/host.py index bcfcf2f16..170e6fea4 100644 --- a/monkey/infection_monkey/model/host.py +++ b/monkey/infection_monkey/model/host.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Any, Dict, Optional from common import OperatingSystem @@ -7,10 +7,9 @@ class VictimHost(object): def __init__(self, ip_addr: str, domain_name: str = ""): self.ip_addr = ip_addr self.domain_name = str(domain_name) - self.os = {} - self.services = {} + self.os: Dict[str, Any] = {} + self.services: Dict[str, Any] = {} self.icmp = False - self.default_tunnel = None self.default_server = None def as_dict(self): diff --git a/monkey/infection_monkey/model/victim_host_factory.py b/monkey/infection_monkey/model/victim_host_factory.py index a6b56532e..dc22425bb 100644 --- a/monkey/infection_monkey/model/victim_host_factory.py +++ b/monkey/infection_monkey/model/victim_host_factory.py @@ -4,7 +4,6 @@ from typing import Optional, Tuple from infection_monkey.model import VictimHost from infection_monkey.network import NetworkAddress from infection_monkey.network.tools import get_interface_to_target -from infection_monkey.tunnel import MonkeyTunnel logger = logging.getLogger(__name__) @@ -12,12 +11,10 @@ logger = logging.getLogger(__name__) class VictimHostFactory: def __init__( self, - tunnel: Optional[MonkeyTunnel], island_ip: Optional[str], island_port: Optional[str], on_island: bool, ): - self.tunnel = tunnel self.island_ip = island_ip self.island_port = island_port self.on_island = on_island @@ -26,19 +23,15 @@ class VictimHostFactory: domain = network_address.domain or "" victim_host = VictimHost(network_address.ip, domain) - if self.tunnel: - victim_host.default_tunnel = self.tunnel.get_tunnel_for_ip(victim_host.ip_addr) - if self.island_ip: ip, port = self._choose_island_address(victim_host.ip_addr) victim_host.set_island_address(ip, port) - logger.debug(f"Default tunnel for {victim_host} set to {victim_host.default_tunnel}") logger.debug(f"Default server for {victim_host} set to {victim_host.default_server}") return victim_host - def _choose_island_address(self, victim_ip: str) -> Tuple[str, Optional[str]]: + def _choose_island_address(self, victim_ip: str) -> Tuple[Optional[str], Optional[str]]: # Victims need to connect back to the interface they can reach # On island, choose the right interface to pass to children monkeys if self.on_island: diff --git a/monkey/infection_monkey/monkey.py b/monkey/infection_monkey/monkey.py index 005fad62e..9015d5c7f 100644 --- a/monkey/infection_monkey/monkey.py +++ b/monkey/infection_monkey/monkey.py @@ -78,7 +78,6 @@ from infection_monkey.telemetry.messengers.legacy_telemetry_messenger_adapter im LegacyTelemetryMessengerAdapter, ) from infection_monkey.telemetry.state_telem import StateTelem -from infection_monkey.telemetry.tunnel_telem import TunnelTelem from infection_monkey.utils.aws_environment_check import run_aws_environment_check from infection_monkey.utils.environment import is_windows_os from infection_monkey.utils.file_utils import mark_file_for_deletion_on_windows @@ -162,9 +161,7 @@ class InfectionMonkey: run_aws_environment_check(self._telemetry_messenger) - should_stop = ControlChannel( - self._control_client.server_address, GUID, self._control_client.proxies - ).should_agent_stop() + should_stop = ControlChannel(self._control_client.server_address, GUID).should_agent_stop() if should_stop: logger.info("The Monkey Island has instructed this agent to stop") return @@ -180,9 +177,7 @@ class InfectionMonkey: if firewall.is_enabled(): firewall.add_firewall_rule() - control_channel = ControlChannel( - self._control_client.server_address, GUID, self._control_client.proxies - ) + control_channel = ControlChannel(self._control_client.server_address, GUID) control_channel.register_agent(self._opts.parent) config = control_channel.get_config() @@ -199,7 +194,6 @@ class InfectionMonkey: self._relay.start() StateTelem(is_done=False, version=get_version()).send() - TunnelTelem(self._control_client.proxies).send() self._build_master() @@ -209,9 +203,7 @@ class InfectionMonkey: local_network_interfaces = InfectionMonkey._get_local_network_interfaces() # TODO control_channel and control_client have same responsibilities, merge them - control_channel = ControlChannel( - self._control_client.server_address, GUID, self._control_client.proxies - ) + control_channel = ControlChannel(self._control_client.server_address, GUID) propagation_credentials_repository = AggregatingPropagationCredentialsRepository( control_channel ) @@ -283,7 +275,7 @@ class InfectionMonkey: puppet.load_plugin("ssh", SSHFingerprinter(), PluginType.FINGERPRINTER) agent_binary_repository = CachingAgentBinaryRepository( - f"https://{self._control_client.server_address}", self._control_client.proxies + f"https://{self._control_client.server_address}" ) exploit_wrapper = ExploiterWrapper( self._telemetry_messenger, event_queue, agent_binary_repository @@ -383,7 +375,7 @@ class InfectionMonkey: on_island = self._running_on_island(local_network_interfaces) logger.debug(f"This agent is running on the island: {on_island}") - return VictimHostFactory(None, self._cmd_island_ip, self._cmd_island_port, on_island) + return VictimHostFactory(self._cmd_island_ip, self._cmd_island_port, on_island) def _running_on_island(self, local_network_interfaces: List[IPv4Interface]) -> bool: server_ip, _ = address_to_ip_port(self._control_client.server_address) diff --git a/monkey/infection_monkey/telemetry/tunnel_telem.py b/monkey/infection_monkey/telemetry/tunnel_telem.py deleted file mode 100644 index efe917643..000000000 --- a/monkey/infection_monkey/telemetry/tunnel_telem.py +++ /dev/null @@ -1,18 +0,0 @@ -from typing import Mapping - -from common.common_consts.telem_categories import TelemCategoryEnum -from infection_monkey.telemetry.base_telem import BaseTelem - - -class TunnelTelem(BaseTelem): - def __init__(self, proxy: Mapping[str, str]): - """ - Default tunnel telemetry constructor - """ - super(TunnelTelem, self).__init__() - self.proxy = proxy.get("https") - - telem_category = TelemCategoryEnum.TUNNEL - - def get_data(self): - return {"proxy": self.proxy} diff --git a/monkey/infection_monkey/transport/base.py b/monkey/infection_monkey/transport/base.py deleted file mode 100644 index f61f7b115..000000000 --- a/monkey/infection_monkey/transport/base.py +++ /dev/null @@ -1,31 +0,0 @@ -import time -from threading import Thread - -g_last_served = None -PROXY_TIMEOUT = 2.5 - - -class TransportProxyBase(Thread): - def __init__(self, local_port, dest_host=None, dest_port=None, local_host=""): - global g_last_served - - self.local_host = local_host - self.local_port = local_port - self.dest_host = dest_host - self.dest_port = dest_port - self._stopped = False - super(TransportProxyBase, self).__init__() - self.daemon = True - - def stop(self): - self._stopped = True - - -def update_last_serve_time(): - global g_last_served - g_last_served = time.time() - - -def get_last_serve_time(): - global g_last_served - return g_last_served diff --git a/monkey/infection_monkey/transport/http.py b/monkey/infection_monkey/transport/http.py index 46dad8c52..293d86496 100644 --- a/monkey/infection_monkey/transport/http.py +++ b/monkey/infection_monkey/transport/http.py @@ -1,17 +1,9 @@ import http.server -import select -import socket import threading import urllib from logging import getLogger -from urllib.parse import urlsplit from infection_monkey.network.tools import get_interface_to_target -from infection_monkey.transport.base import ( - PROXY_TIMEOUT, - TransportProxyBase, - update_last_serve_time, -) logger = getLogger(__name__) @@ -110,56 +102,6 @@ class FileServHTTPRequestHandler(http.server.BaseHTTPRequestHandler): ) -class HTTPConnectProxyHandler(http.server.BaseHTTPRequestHandler): - timeout = 30 # timeout with clients, set to None not to make persistent connection - - def version_string(self): - return "" - - def do_CONNECT(self): - logger.info("Received a connect request!") - # just provide a tunnel, transfer the data with no modification - req = self - req.path = "https://%s/" % req.path.replace(":443", "") - - u = urlsplit(req.path) - address = (u.hostname, u.port or 443) - try: - conn = socket.create_connection(address) - except socket.error as e: - logger.debug( - "HTTPConnectProxyHandler: Got exception while trying to connect to %s: %s" - % (repr(address), e) - ) - self.send_error(504) # 504 Gateway Timeout - return - self.send_response(200, "Connection Established") - self.send_header("Connection", "close") - self.end_headers() - - conns = [self.connection, conn] - keep_connection = True - while keep_connection: - keep_connection = False - rlist, wlist, xlist = select.select(conns, [], conns, self.timeout) - if xlist: - break - for r in rlist: - other = conns[1] if r is conns[0] else conns[0] - data = r.recv(8192) - if data: - other.sendall(data) - keep_connection = True - update_last_serve_time() - conn.close() - - def log_message(self, format_string, *args): - logger.debug( - "HTTPConnectProxyHandler: %s - [%s] %s" - % (self.address_string(), self.log_date_time_string(), format_string % args) - ) - - class LockedHTTPServer(threading.Thread): """ Same as HTTPServer used for file downloads just with locks to avoid racing conditions. @@ -226,11 +168,3 @@ class LockedHTTPServer(threading.Thread): def stop(self, timeout=STOP_TIMEOUT): self._stopped = True self.join(timeout) - - -class HTTPConnectProxy(TransportProxyBase): - def run(self): - httpd = http.server.HTTPServer((self.local_host, self.local_port), HTTPConnectProxyHandler) - httpd.timeout = PROXY_TIMEOUT - while not self._stopped: - httpd.handle_request() diff --git a/monkey/infection_monkey/transport/tcp.py b/monkey/infection_monkey/transport/tcp.py deleted file mode 100644 index 83c631c3b..000000000 --- a/monkey/infection_monkey/transport/tcp.py +++ /dev/null @@ -1,88 +0,0 @@ -import select -import socket -from logging import getLogger -from threading import Thread - -from infection_monkey.transport.base import ( - PROXY_TIMEOUT, - TransportProxyBase, - update_last_serve_time, -) - -READ_BUFFER_SIZE = 8192 -SOCKET_READ_TIMEOUT = 10 - -logger = getLogger(__name__) - - -class SocketsPipe(Thread): - def __init__(self, source, dest, timeout=SOCKET_READ_TIMEOUT): - Thread.__init__(self) - self.source = source - self.dest = dest - self.timeout = timeout - self._keep_connection = True - super(SocketsPipe, self).__init__() - self.daemon = True - - def run(self): - sockets = [self.source, self.dest] - while self._keep_connection: - self._keep_connection = False - rlist, wlist, xlist = select.select(sockets, [], sockets, self.timeout) - if xlist: - break - for r in rlist: - other = self.dest if r is self.source else self.source - try: - data = r.recv(READ_BUFFER_SIZE) - except Exception: - break - if data: - try: - other.sendall(data) - update_last_serve_time() - except Exception: - break - self._keep_connection = True - - self.source.close() - self.dest.close() - - -class TcpProxy(TransportProxyBase): - def run(self): - pipes = [] - l_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - l_socket.bind((self.local_host, self.local_port)) - l_socket.settimeout(PROXY_TIMEOUT) - l_socket.listen(5) - - while not self._stopped: - try: - source, address = l_socket.accept() - except socket.timeout: - continue - - dest = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - try: - dest.connect((self.dest_host, self.dest_port)) - except socket.error: - source.close() - dest.close() - continue - - pipe = SocketsPipe(source, dest) - pipes.append(pipe) - logger.debug( - "piping sockets %s:%s->%s:%s", - address[0], - address[1], - self.dest_host, - self.dest_port, - ) - pipe.start() - - l_socket.close() - for pipe in pipes: - pipe.join() diff --git a/monkey/infection_monkey/tunnel.py b/monkey/infection_monkey/tunnel.py deleted file mode 100644 index b4ca3b517..000000000 --- a/monkey/infection_monkey/tunnel.py +++ /dev/null @@ -1,230 +0,0 @@ -import logging -import socket -import struct -import time -from threading import Event, Thread - -from common.utils import Timer -from infection_monkey.network.firewall import app as firewall -from infection_monkey.network.info import get_free_tcp_port, local_ips -from infection_monkey.network.tools import check_tcp_port, get_interface_to_target -from infection_monkey.transport.base import get_last_serve_time - -logger = logging.getLogger(__name__) - -MCAST_GROUP = "224.1.1.1" -MCAST_PORT = 5007 -BUFFER_READ = 1024 -DEFAULT_TIMEOUT = 10 -QUIT_TIMEOUT = 60 * 10 # 10 minutes - - -def _set_multicast_socket(timeout=DEFAULT_TIMEOUT, adapter=""): - sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) - sock.settimeout(timeout) - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - sock.bind((adapter, MCAST_PORT)) - sock.setsockopt( - socket.IPPROTO_IP, - socket.IP_ADD_MEMBERSHIP, - struct.pack("4sl", socket.inet_aton(MCAST_GROUP), socket.INADDR_ANY), - ) - return sock - - -def _check_tunnel(address, port, existing_sock=None): - if not existing_sock: - sock = _set_multicast_socket() - else: - sock = existing_sock - - logger.debug("Checking tunnel %s:%s", address, port) - is_open, _ = check_tcp_port(address, int(port)) - if not is_open: - logger.debug("Could not connect to %s:%s", address, port) - if not existing_sock: - sock.close() - return False - - try: - sock.sendto(b"+", (address, MCAST_PORT)) - except Exception as exc: - logger.debug("Caught exception in tunnel registration: %s", exc) - - if not existing_sock: - sock.close() - return True - - -def find_tunnel(default=None, attempts=3, timeout=DEFAULT_TIMEOUT): - l_ips = local_ips() - - if default: - if default.find(":") != -1: - address, port = default.split(":", 1) - if _check_tunnel(address, port): - return address, port - - for adapter in l_ips: - for attempt in range(0, attempts): - try: - logger.info("Trying to find using adapter %s", adapter) - sock = _set_multicast_socket(timeout, adapter) - sock.sendto(b"?", (MCAST_GROUP, MCAST_PORT)) - tunnels = [] - - while True: - try: - answer, address = sock.recvfrom(BUFFER_READ) - if answer not in [b"?", b"+", b"-"]: - tunnels.append(answer) - except socket.timeout: - break - - for tunnel in tunnels: - if tunnel.find(":") != -1: - address, port = tunnel.split(":", 1) - if address in l_ips: - continue - - if _check_tunnel(address, port, sock): - sock.close() - return address, port - - except Exception as exc: - logger.debug("Caught exception in tunnel lookup: %s", exc) - continue - - return None - - -def quit_tunnel(address, timeout=DEFAULT_TIMEOUT): - try: - sock = _set_multicast_socket(timeout) - sock.sendto(b"-", (address, MCAST_PORT)) - sock.close() - logger.debug("Success quitting tunnel") - except Exception as exc: - logger.debug("Exception quitting tunnel: %s", exc) - return - - -class MonkeyTunnel(Thread): - def __init__( - self, - proxy_class, - keep_tunnel_open_time, - target_addr=None, - target_port=None, - timeout=DEFAULT_TIMEOUT, - ): - self._target_addr = target_addr - self._target_port = target_port - self._proxy_class = proxy_class - self._keep_tunnel_open_time = keep_tunnel_open_time - self._broad_sock = None - self._timeout = timeout - self._stopped = Event() - self._clients = [] - self.local_port = None - super(MonkeyTunnel, self).__init__(name="MonkeyTunnelThread") - self.daemon = True - self.l_ips = None - self._wait_for_exploited_machines = Event() - - def run(self): - self._broad_sock = _set_multicast_socket(self._timeout) - self.l_ips = local_ips() - self.local_port = get_free_tcp_port() - - if not self.local_port: - return - - if not firewall.listen_allowed(localport=self.local_port): - logger.info("Machine firewalled, listen not allowed, not running tunnel.") - return - - proxy = self._proxy_class( - local_port=self.local_port, dest_host=self._target_addr, dest_port=self._target_port - ) - logger.info( - "Running tunnel using proxy class: %s, listening on port %s, routing to: %s:%s", - proxy.__class__.__name__, - self.local_port, - self._target_addr, - self._target_port, - ) - proxy.start() - - while not self._stopped.is_set(): - try: - search, address = self._broad_sock.recvfrom(BUFFER_READ) - if b"?" == search: - ip_match = get_interface_to_target(address[0]) - if ip_match: - answer = "%s:%d" % (ip_match, self.local_port) - logger.debug( - "Got tunnel request from %s, answering with %s", address[0], answer - ) - self._broad_sock.sendto(answer.encode(), (address[0], MCAST_PORT)) - elif b"+" == search: - if not address[0] in self._clients: - logger.debug("Tunnel control: Added %s to watchlist", address[0]) - self._clients.append(address[0]) - elif b"-" == search: - logger.debug("Tunnel control: Removed %s from watchlist", address[0]) - self._clients = [client for client in self._clients if client != address[0]] - - except socket.timeout: - continue - - logger.info("Stopping tunnel, waiting for clients: %s" % repr(self._clients)) - - # wait till all of the tunnel clients has been disconnected, or no one used the tunnel in - # QUIT_TIMEOUT seconds - timer = Timer() - timer.set(self._calculate_timeout()) - while self._clients and not timer.is_expired(): - try: - search, address = self._broad_sock.recvfrom(BUFFER_READ) - if b"-" == search: - logger.debug("Tunnel control: Removed %s from watchlist", address[0]) - self._clients = [client for client in self._clients if client != address[0]] - except socket.timeout: - continue - - timer.set(self._calculate_timeout()) - - logger.info("Closing tunnel") - self._broad_sock.close() - proxy.stop() - proxy.join() - - def _calculate_timeout(self) -> float: - try: - return QUIT_TIMEOUT - (time.time() - get_last_serve_time()) - except TypeError: # get_last_serve_time() may return None - return 0.0 - - def get_tunnel_for_ip(self, ip: str): - - if not self.local_port: - return - - ip_match = get_interface_to_target(ip) - return "%s:%d" % (ip_match, self.local_port) - - def set_wait_for_exploited_machines(self): - self._wait_for_exploited_machines.set() - - def stop(self): - self._wait_for_exploited_machine_connection() - self._stopped.set() - - def _wait_for_exploited_machine_connection(self): - if self._wait_for_exploited_machines.is_set(): - logger.info( - f"Waiting {self._keep_tunnel_open_time} seconds for exploited machines to connect " - "to the tunnel." - ) - time.sleep(self._keep_tunnel_open_time) diff --git a/monkey/monkey_island/cc/resources/telemetry_feed.py b/monkey/monkey_island/cc/resources/telemetry_feed.py index 9087e2b97..feb408ae0 100644 --- a/monkey/monkey_island/cc/resources/telemetry_feed.py +++ b/monkey/monkey_island/cc/resources/telemetry_feed.py @@ -64,16 +64,6 @@ class TelemetryFeed(AbstractResource): def get_telem_brief_parser_by_category(telem_category): return TELEM_PROCESS_DICT[telem_category] - @staticmethod - def get_tunnel_telem_brief(telem): - tunnel = telem["data"]["proxy"] - if tunnel is None: - return "No tunnel is used." - else: - tunnel_host_ip = tunnel.split(":")[-2].replace("//", "") - tunnel_host = NodeService.get_monkey_by_ip(tunnel_host_ip)["hostname"] - return "Tunnel set up to machine: %s." % tunnel_host - @staticmethod def get_state_telem_brief(telem): if telem["data"]["done"]: @@ -132,7 +122,6 @@ TELEM_PROCESS_DICT = { TelemCategoryEnum.SCAN: TelemetryFeed.get_scan_telem_brief, TelemCategoryEnum.STATE: TelemetryFeed.get_state_telem_brief, TelemCategoryEnum.TRACE: TelemetryFeed.get_trace_telem_brief, - TelemCategoryEnum.TUNNEL: TelemetryFeed.get_tunnel_telem_brief, } diff --git a/monkey/monkey_island/cc/services/telemetry/processing/processing.py b/monkey/monkey_island/cc/services/telemetry/processing/processing.py index 557dbff7f..f3550077f 100644 --- a/monkey/monkey_island/cc/services/telemetry/processing/processing.py +++ b/monkey/monkey_island/cc/services/telemetry/processing/processing.py @@ -8,7 +8,6 @@ from monkey_island.cc.services.telemetry.processing.exploit import process_explo from monkey_island.cc.services.telemetry.processing.post_breach import process_post_breach_telemetry from monkey_island.cc.services.telemetry.processing.scan import process_scan_telemetry from monkey_island.cc.services.telemetry.processing.state import process_state_telemetry -from monkey_island.cc.services.telemetry.processing.tunnel import process_tunnel_telemetry logger = logging.getLogger(__name__) @@ -22,7 +21,6 @@ TELEMETRY_CATEGORY_TO_PROCESSING_FUNC = { TelemCategoryEnum.SCAN: process_scan_telemetry, TelemCategoryEnum.STATE: process_state_telemetry, TelemCategoryEnum.TRACE: lambda *args, **kwargs: None, - TelemCategoryEnum.TUNNEL: process_tunnel_telemetry, } # Don't save credential telemetries in telemetries collection. diff --git a/monkey/monkey_island/cc/services/telemetry/processing/tunnel.py b/monkey/monkey_island/cc/services/telemetry/processing/tunnel.py deleted file mode 100644 index 6bd1fd711..000000000 --- a/monkey/monkey_island/cc/services/telemetry/processing/tunnel.py +++ /dev/null @@ -1,15 +0,0 @@ -from monkey_island.cc.services.node import NodeService -from monkey_island.cc.services.telemetry.processing.utils import get_tunnel_host_ip_from_proxy_field -from monkey_island.cc.services.telemetry.zero_trust_checks.tunneling import ( - check_tunneling_violation, -) - - -def process_tunnel_telemetry(telemetry_json, _): - check_tunneling_violation(telemetry_json) - monkey_id = NodeService.get_monkey_by_guid(telemetry_json["monkey_guid"])["_id"] - if telemetry_json["data"]["proxy"] is not None: - tunnel_host_ip = get_tunnel_host_ip_from_proxy_field(telemetry_json) - NodeService.set_monkey_tunnel(monkey_id, tunnel_host_ip) - else: - NodeService.unset_all_monkey_tunnels(monkey_id) diff --git a/monkey/monkey_island/cc/services/telemetry/processing/utils.py b/monkey/monkey_island/cc/services/telemetry/processing/utils.py index ffa6960f6..30487593a 100644 --- a/monkey/monkey_island/cc/services/telemetry/processing/utils.py +++ b/monkey/monkey_island/cc/services/telemetry/processing/utils.py @@ -14,8 +14,3 @@ def get_edge_by_scan_or_exploit_telemetry(telemetry_json): dst_label = NodeService.get_label_for_endpoint(dst_node["_id"]) return EdgeService.get_or_create_edge(src_monkey["_id"], dst_node["_id"], src_label, dst_label) - - -def get_tunnel_host_ip_from_proxy_field(telemetry_json): - tunnel_host_ip = telemetry_json["data"]["proxy"].split(":")[-2].replace("//", "") - return tunnel_host_ip diff --git a/monkey/monkey_island/cc/services/telemetry/zero_trust_checks/tunneling.py b/monkey/monkey_island/cc/services/telemetry/zero_trust_checks/tunneling.py deleted file mode 100644 index 092fd67e2..000000000 --- a/monkey/monkey_island/cc/services/telemetry/zero_trust_checks/tunneling.py +++ /dev/null @@ -1,32 +0,0 @@ -import common.common_consts.zero_trust_consts as zero_trust_consts -from monkey_island.cc.models import Monkey -from monkey_island.cc.models.zero_trust.event import Event -from monkey_island.cc.services.telemetry.processing.utils import get_tunnel_host_ip_from_proxy_field -from monkey_island.cc.services.zero_trust.monkey_findings.monkey_zt_finding_service import ( - MonkeyZTFindingService, -) - - -def check_tunneling_violation(tunnel_telemetry_json): - if tunnel_telemetry_json["data"]["proxy"] is not None: - # Monkey is tunneling, create findings - tunnel_host_ip = get_tunnel_host_ip_from_proxy_field(tunnel_telemetry_json) - current_monkey = Monkey.get_single_monkey_by_guid(tunnel_telemetry_json["monkey_guid"]) - tunneling_events = [ - Event.create_event( - title="Tunneling event", - message="Monkey on {hostname} tunneled traffic through {proxy}.".format( - hostname=current_monkey.hostname, proxy=tunnel_host_ip - ), - event_type=zero_trust_consts.EVENT_TYPE_MONKEY_NETWORK, - timestamp=tunnel_telemetry_json["timestamp"], - ) - ] - - MonkeyZTFindingService.create_or_add_to_existing( - test=zero_trust_consts.TEST_TUNNELING, - status=zero_trust_consts.STATUS_FAILED, - events=tunneling_events, - ) - - MonkeyZTFindingService.add_malicious_activity_to_timeline(tunneling_events) diff --git a/monkey/tests/unit_tests/infection_monkey/model/test_victim_host_factory.py b/monkey/tests/unit_tests/infection_monkey/model/test_victim_host_factory.py index 766ef0392..a584dca17 100644 --- a/monkey/tests/unit_tests/infection_monkey/model/test_victim_host_factory.py +++ b/monkey/tests/unit_tests/infection_monkey/model/test_victim_host_factory.py @@ -1,18 +1,9 @@ -from unittest.mock import MagicMock - import pytest from infection_monkey.model import VictimHostFactory from infection_monkey.network import NetworkAddress -@pytest.fixture -def mock_tunnel(): - tunnel = MagicMock() - tunnel.get_tunnel_for_ip = lambda _: "1.2.3.4:1234" - return tunnel - - @pytest.fixture(autouse=True) def mock_get_interface_to_target(monkeypatch): monkeypatch.setattr( @@ -21,37 +12,18 @@ def mock_get_interface_to_target(monkeypatch): def test_factory_no_tunnel(): - factory = VictimHostFactory( - tunnel=None, island_ip="192.168.56.1", island_port="5000", on_island=False - ) + factory = VictimHostFactory(island_ip="192.168.56.1", island_port="5000", on_island=False) network_address = NetworkAddress("192.168.56.2", None) victim = factory.build_victim_host(network_address) assert victim.default_server == "192.168.56.1:5000" assert victim.ip_addr == "192.168.56.2" - assert victim.default_tunnel is None assert victim.domain_name == "" -def test_factory_with_tunnel(mock_tunnel): - factory = VictimHostFactory( - tunnel=mock_tunnel, island_ip="192.168.56.1", island_port="5000", on_island=False - ) - network_address = NetworkAddress("192.168.56.2", None) - - victim = factory.build_victim_host(network_address) - - assert victim.default_server == "192.168.56.1:5000" - assert victim.ip_addr == "192.168.56.2" - assert victim.default_tunnel == "1.2.3.4:1234" - assert victim.domain_name == "" - - -def test_factory_on_island(mock_tunnel): - factory = VictimHostFactory( - tunnel=mock_tunnel, island_ip="192.168.56.1", island_port="99", on_island=True - ) +def test_factory_on_island(): + factory = VictimHostFactory(island_ip="192.168.56.1", island_port="99", on_island=True) network_address = NetworkAddress("192.168.56.2", "www.bogus.monkey") victim = factory.build_victim_host(network_address) @@ -59,14 +31,11 @@ def test_factory_on_island(mock_tunnel): assert victim.default_server == "1.1.1.1:99" assert victim.domain_name == "www.bogus.monkey" assert victim.ip_addr == "192.168.56.2" - assert victim.default_tunnel == "1.2.3.4:1234" @pytest.mark.parametrize("default_port", ["", None]) -def test_factory_no_port(mock_tunnel, default_port): - factory = VictimHostFactory( - tunnel=mock_tunnel, island_ip="192.168.56.1", island_port=default_port, on_island=True - ) +def test_factory_no_port(default_port): + factory = VictimHostFactory(island_ip="192.168.56.1", island_port=default_port, on_island=True) network_address = NetworkAddress("192.168.56.2", "www.bogus.monkey") victim = factory.build_victim_host(network_address) @@ -74,8 +43,8 @@ def test_factory_no_port(mock_tunnel, default_port): assert victim.default_server == "1.1.1.1" -def test_factory_no_default_server(mock_tunnel): - factory = VictimHostFactory(tunnel=mock_tunnel, island_ip=None, island_port="", on_island=True) +def test_factory_no_default_server(): + factory = VictimHostFactory(island_ip=None, island_port="", on_island=True) network_address = NetworkAddress("192.168.56.2", "www.bogus.monkey") victim = factory.build_victim_host(network_address) diff --git a/monkey/tests/unit_tests/infection_monkey/telemetry/test_exploit_telem.py b/monkey/tests/unit_tests/infection_monkey/telemetry/test_exploit_telem.py index 3255cc7b7..c38c1d130 100644 --- a/monkey/tests/unit_tests/infection_monkey/telemetry/test_exploit_telem.py +++ b/monkey/tests/unit_tests/infection_monkey/telemetry/test_exploit_telem.py @@ -16,7 +16,6 @@ HOST_AS_DICT = { "os": {}, "services": {}, "icmp": False, - "default_tunnel": None, "default_server": None, } EXPLOITER_NAME = "SSHExploiter" diff --git a/monkey/tests/unit_tests/infection_monkey/telemetry/test_scan_telem.py b/monkey/tests/unit_tests/infection_monkey/telemetry/test_scan_telem.py index a369fe4cf..837b7d782 100644 --- a/monkey/tests/unit_tests/infection_monkey/telemetry/test_scan_telem.py +++ b/monkey/tests/unit_tests/infection_monkey/telemetry/test_scan_telem.py @@ -14,7 +14,6 @@ HOST_AS_DICT = { "os": {}, "services": {}, "icmp": False, - "default_tunnel": None, "default_server": None, } HOST_SERVICES = {} diff --git a/monkey/tests/unit_tests/infection_monkey/telemetry/test_tunnel_telem.py b/monkey/tests/unit_tests/infection_monkey/telemetry/test_tunnel_telem.py deleted file mode 100644 index eb18307ce..000000000 --- a/monkey/tests/unit_tests/infection_monkey/telemetry/test_tunnel_telem.py +++ /dev/null @@ -1,19 +0,0 @@ -import json - -import pytest - -from infection_monkey.telemetry.tunnel_telem import TunnelTelem - - -@pytest.fixture -def tunnel_telem_test_instance(): - return TunnelTelem({}) - - -def test_tunnel_telem_send(tunnel_telem_test_instance, spy_send_telemetry): - tunnel_telem_test_instance.send() - expected_data = {"proxy": None} - expected_data = json.dumps(expected_data, cls=tunnel_telem_test_instance.json_encoder) - - assert spy_send_telemetry.data == expected_data - assert spy_send_telemetry.telem_category == "tunnel" diff --git a/monkey/tests/unit_tests/infection_monkey/test_control.py b/monkey/tests/unit_tests/infection_monkey/test_control.py deleted file mode 100644 index b90087ebf..000000000 --- a/monkey/tests/unit_tests/infection_monkey/test_control.py +++ /dev/null @@ -1,16 +0,0 @@ -import pytest - -from monkey.infection_monkey.control import ControlClient - - -@pytest.mark.parametrize( - "is_windows_os,expected_proxy_string", - [(True, "http://8.8.8.8:45455"), (False, "8.8.8.8:45455")], -) -def test_control_set_proxies(monkeypatch, is_windows_os, expected_proxy_string): - monkeypatch.setattr("monkey.infection_monkey.control.is_windows_os", lambda: is_windows_os) - control_client = ControlClient("8.8.8.8:5000") - - control_client.set_proxies(("8.8.8.8", "45455")) - - assert control_client.proxies["https"] == expected_proxy_string diff --git a/monkey/tests/unit_tests/monkey_island/cc/services/edge/test_displayed_edge_service.py b/monkey/tests/unit_tests/monkey_island/cc/services/edge/test_displayed_edge_service.py index aadd13f60..90195f980 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/services/edge/test_displayed_edge_service.py +++ b/monkey/tests/unit_tests/monkey_island/cc/services/edge/test_displayed_edge_service.py @@ -18,7 +18,6 @@ SCAN_DATA_MOCK = [ }, }, "monkey_exe": None, - "default_tunnel": None, "default_server": None, }, } diff --git a/vulture_allowlist.py b/vulture_allowlist.py index 65756c95f..3a45ca674 100644 --- a/vulture_allowlist.py +++ b/vulture_allowlist.py @@ -299,9 +299,6 @@ event deserialize serialized_event -# TODO: Remove when removing Tunnel code -create_control_tunnel -set_wait_for_exploited_machines # pydantic base models underscore_attrs_are_private