forked from p15670423/monkey
Agent: Implement preliminary network scanning thread
This commit is contained in:
parent
05adf6bae6
commit
7b40996d6a
|
@ -1,4 +1,5 @@
|
||||||
import logging
|
import logging
|
||||||
|
import queue
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
from queue import Queue
|
from queue import Queue
|
||||||
|
@ -7,15 +8,18 @@ from typing import Any, Callable, Dict, List, Tuple
|
||||||
|
|
||||||
from infection_monkey.i_control_channel import IControlChannel
|
from infection_monkey.i_control_channel import IControlChannel
|
||||||
from infection_monkey.i_master import IMaster
|
from infection_monkey.i_master import IMaster
|
||||||
from infection_monkey.i_puppet import IPuppet
|
from infection_monkey.i_puppet import IPuppet, PortStatus
|
||||||
|
from infection_monkey.model.host import VictimHost
|
||||||
from infection_monkey.telemetry.messengers.i_telemetry_messenger import ITelemetryMessenger
|
from infection_monkey.telemetry.messengers.i_telemetry_messenger import ITelemetryMessenger
|
||||||
from infection_monkey.telemetry.post_breach_telem import PostBreachTelem
|
from infection_monkey.telemetry.post_breach_telem import PostBreachTelem
|
||||||
|
from infection_monkey.telemetry.scan_telem import ScanTelem
|
||||||
from infection_monkey.telemetry.system_info_telem import SystemInfoTelem
|
from infection_monkey.telemetry.system_info_telem import SystemInfoTelem
|
||||||
from infection_monkey.utils.timer import Timer
|
from infection_monkey.utils.timer import Timer
|
||||||
|
|
||||||
CHECK_ISLAND_FOR_STOP_COMMAND_INTERVAL_SEC = 5
|
CHECK_ISLAND_FOR_STOP_COMMAND_INTERVAL_SEC = 5
|
||||||
CHECK_FOR_TERMINATE_INTERVAL_SEC = CHECK_ISLAND_FOR_STOP_COMMAND_INTERVAL_SEC / 5
|
CHECK_FOR_TERMINATE_INTERVAL_SEC = CHECK_ISLAND_FOR_STOP_COMMAND_INTERVAL_SEC / 5
|
||||||
SHUTDOWN_TIMEOUT = 5
|
SHUTDOWN_TIMEOUT = 5
|
||||||
|
NUM_SCAN_THREADS = 16 # TODO: Adjust this to the optimal number of scan threads
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
@ -109,7 +113,7 @@ class AutomatedMaster(IMaster):
|
||||||
# requires the output of PBAs, so we don't need to join on that thread here. We will join on
|
# requires the output of PBAs, so we don't need to join on that thread here. We will join on
|
||||||
# the PBA thread later in this function to prevent the simulation from ending while PBAs are
|
# the PBA thread later in this function to prevent the simulation from ending while PBAs are
|
||||||
# still running.
|
# still running.
|
||||||
system_info_collector_thread.join()
|
# system_info_collector_thread.join()
|
||||||
|
|
||||||
if self._can_propagate():
|
if self._can_propagate():
|
||||||
propagation_thread = _create_daemon_thread(target=self._propagate, args=(config,))
|
propagation_thread = _create_daemon_thread(target=self._propagate, args=(config,))
|
||||||
|
@ -155,7 +159,9 @@ class AutomatedMaster(IMaster):
|
||||||
|
|
||||||
hosts_to_exploit = Queue()
|
hosts_to_exploit = Queue()
|
||||||
|
|
||||||
scan_thread = _create_daemon_thread(target=self._scan_network)
|
scan_thread = _create_daemon_thread(
|
||||||
|
target=self._scan_network, args=(config, hosts_to_exploit)
|
||||||
|
)
|
||||||
exploit_thread = _create_daemon_thread(
|
exploit_thread = _create_daemon_thread(
|
||||||
target=self._exploit_targets, args=(hosts_to_exploit, scan_thread)
|
target=self._exploit_targets, args=(hosts_to_exploit, scan_thread)
|
||||||
)
|
)
|
||||||
|
@ -168,12 +174,76 @@ class AutomatedMaster(IMaster):
|
||||||
|
|
||||||
logger.info("Finished attempting to propagate")
|
logger.info("Finished attempting to propagate")
|
||||||
|
|
||||||
def _scan_network(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def _exploit_targets(self, hosts_to_exploit: Queue, scan_thread: Thread):
|
def _exploit_targets(self, hosts_to_exploit: Queue, scan_thread: Thread):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# TODO: Refactor this into its own class
|
||||||
|
def _scan_network(self, scan_config: Dict, hosts_to_exploit: Queue):
|
||||||
|
logger.info("Starting network scan")
|
||||||
|
|
||||||
|
# TODO: Generate list of IPs to scan
|
||||||
|
ips_to_scan = Queue()
|
||||||
|
for i in range(1, 255):
|
||||||
|
ips_to_scan.put(f"10.0.0.{i}")
|
||||||
|
|
||||||
|
scan_threads = []
|
||||||
|
for i in range(0, NUM_SCAN_THREADS):
|
||||||
|
t = _create_daemon_thread(
|
||||||
|
target=self._scan_ips, args=(ips_to_scan, scan_config, hosts_to_exploit)
|
||||||
|
)
|
||||||
|
t.start()
|
||||||
|
scan_threads.append(t)
|
||||||
|
|
||||||
|
for t in scan_threads:
|
||||||
|
t.join()
|
||||||
|
|
||||||
|
logger.info("Finished network scan")
|
||||||
|
|
||||||
|
def _scan_ips(self, ips_to_scan: Queue, scan_config: Dict, hosts_to_exploit: Queue):
|
||||||
|
logger.debug(f"Starting scan thread -- Thread ID: {threading.get_ident()}")
|
||||||
|
try:
|
||||||
|
while not self._stop.is_set():
|
||||||
|
ip = ips_to_scan.get_nowait()
|
||||||
|
logger.info(f"Scanning {ip}")
|
||||||
|
|
||||||
|
victim_host = VictimHost(ip)
|
||||||
|
|
||||||
|
self._ping_ip(ip, victim_host)
|
||||||
|
|
||||||
|
# TODO: get ports from config
|
||||||
|
ports = [22, 445, 3389, 8008]
|
||||||
|
self._scan_tcp_ports(ip, ports, victim_host)
|
||||||
|
|
||||||
|
hosts_to_exploit.put(hosts_to_exploit)
|
||||||
|
self._telemetry_messenger.send_telemetry(ScanTelem(victim_host))
|
||||||
|
|
||||||
|
except queue.Empty:
|
||||||
|
logger.debug(
|
||||||
|
f"ips_to_scan queue is empty, scanning thread {threading.get_ident()} exiting"
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.debug(f"Detected the stop signal, scanning thread {threading.get_ident()} exiting")
|
||||||
|
|
||||||
|
def _ping_ip(self, ip: str, victim_host: VictimHost):
|
||||||
|
(response_received, os) = self._puppet.ping(ip)
|
||||||
|
|
||||||
|
victim_host.icmp = response_received
|
||||||
|
if os is not None:
|
||||||
|
victim_host.os["type"] = os
|
||||||
|
|
||||||
|
def _scan_tcp_ports(self, ip: str, ports: List[int], victim_host: VictimHost):
|
||||||
|
for p in ports:
|
||||||
|
if self._stop.is_set():
|
||||||
|
break
|
||||||
|
|
||||||
|
port_scan_data = self._puppet.scan_tcp_port(ip, p)
|
||||||
|
if port_scan_data.status == PortStatus.OPEN:
|
||||||
|
victim_host.services[port_scan_data.service] = {}
|
||||||
|
victim_host.services[port_scan_data.service]["display_name"] = "unknown(TCP)"
|
||||||
|
victim_host.services[port_scan_data.service]["port"] = port_scan_data.port
|
||||||
|
if port_scan_data.banner is not None:
|
||||||
|
victim_host.services[port_scan_data.service]["banner"] = port_scan_data.banner
|
||||||
|
|
||||||
def _run_payload(self, payload: Tuple[str, Dict]):
|
def _run_payload(self, payload: Tuple[str, Dict]):
|
||||||
name = payload[0]
|
name = payload[0]
|
||||||
options = payload[1]
|
options = payload[1]
|
||||||
|
|
Loading…
Reference in New Issue