From 0658431358d8c2b923748eb8d66b2a5c03c42df2 Mon Sep 17 00:00:00 2001 From: Itay Mizeretz Date: Sun, 16 Dec 2018 18:15:04 +0200 Subject: [PATCH 1/8] Use carried traceroute on linux --- monkey/infection_monkey/monkey.spec | 5 ++ monkey/infection_monkey/network/tools.py | 75 +++++++++++------------- 2 files changed, 38 insertions(+), 42 deletions(-) diff --git a/monkey/infection_monkey/monkey.spec b/monkey/infection_monkey/monkey.spec index 84e6b82f0..29fe7db04 100644 --- a/monkey/infection_monkey/monkey.spec +++ b/monkey/infection_monkey/monkey.spec @@ -69,6 +69,7 @@ def process_datas(orig_datas): def get_binaries(): binaries = get_windows_only_binaries() if is_windows() else get_linux_only_binaries() binaries += get_sc_binaries() + binaries += get_traceroute_binaries() return binaries @@ -95,6 +96,10 @@ def get_msvcr(): return [('msvcr100.dll', os.environ['WINDIR'] + '\\system32\\msvcr100.dll', 'BINARY')] +def get_traceroute_binaries(): + return [('traceroute', get_bin_file_path('traceroute'), 'BINARY')] + + def get_monkey_filename(): return 'monkey.exe' if is_windows() else 'monkey' diff --git a/monkey/infection_monkey/network/tools.py b/monkey/infection_monkey/network/tools.py index fa84f84fe..64cc70bb6 100644 --- a/monkey/infection_monkey/network/tools.py +++ b/monkey/infection_monkey/network/tools.py @@ -9,9 +9,12 @@ import re from six.moves import range +from infection_monkey.pyinstaller_utils import get_binary_file_path + DEFAULT_TIMEOUT = 10 BANNER_READ = 1024 -IP_ADDR_RE = r'[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' +IP_ADDR_RE = r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}' +IP_ADDR_PARENT_RE = r'\(' + IP_ADDR_RE + r'\)' LOG = logging.getLogger(__name__) SLEEP_BETWEEN_POLL = 0.5 @@ -188,19 +191,8 @@ def traceroute(target_ip, ttl): return _traceroute_linux(target_ip, ttl) -def _traceroute_windows(target_ip, ttl): - """ - Traceroute for a specific IP/name - Windows implementation - """ - # we'll just use tracert because that's always there - cli = ["tracert", - "-d", - "-w", "250", - "-h", str(ttl), - target_ip] - proc_obj = subprocess.Popen(cli, stdout=subprocess.PIPE) - stdout, stderr = proc_obj.communicate() - ip_lines = stdout.split('\r\n') +def _parse_traceroute(output, regex, ttl): + ip_lines = output.split('\n') trace_list = [] first_line_index = None @@ -213,7 +205,7 @@ def _traceroute_windows(target_ip, ttl): if re.search(r'^\s*' + str(i - first_line_index + 1), ip_lines[i]) is None: # If trace is finished break - re_res = re.search(IP_ADDR_RE, ip_lines[i]) + re_res = re.search(regex, ip_lines[i]) if re_res is None: ip_addr = None else: @@ -223,36 +215,35 @@ def _traceroute_windows(target_ip, ttl): return trace_list +def _traceroute_windows(target_ip, ttl): + """ + Traceroute for a specific IP/name - Windows implementation + """ + # we'll just use tracert because that's always there + cli = ["tracert", + "-d", + "-w", "250", + "-h", str(ttl), + target_ip] + proc_obj = subprocess.Popen(cli, stdout=subprocess.PIPE) + stdout, stderr = proc_obj.communicate() + stdout = stdout.replace('\r', '') + return _parse_traceroute(stdout, IP_ADDR_RE, ttl) + + def _traceroute_linux(target_ip, ttl): """ Traceroute for a specific IP/name - Linux implementation """ - # implementation note: We're currently going to just use ping. - # reason is, implementing a non root requiring user is complicated (see traceroute(8) code) - # while this is just ugly - # we can't use traceroute because it's not always installed - current_ttl = 1 - trace_list = [] - while current_ttl <= ttl: - cli = ["ping", - "-c", "1", - "-w", "1", - "-t", str(current_ttl), - target_ip] - proc_obj = subprocess.Popen(cli, stdout=subprocess.PIPE) - stdout, stderr = proc_obj.communicate() - ips = re.findall(IP_ADDR_RE, stdout) - if len(ips) < 2: # Unexpected output. Fail the whole thing since it's not reliable. - return [] - elif ips[-1] in trace_list: # Failed getting this hop - trace_list.append(None) - else: - trace_list.append(ips[-1]) - dest_ip = ips[0] # first ip is dest ip. must be parsed here since it can change between pings - if dest_ip == ips[-1]: - break + traceroute_path = get_binary_file_path("traceroute") + cli = [traceroute_path, + "-m", str(ttl), + target_ip] + proc_obj = subprocess.Popen(cli, stdout=subprocess.PIPE) + stdout, stderr = proc_obj.communicate() - current_ttl += 1 - - return trace_list + lines = _parse_traceroute(stdout, IP_ADDR_PARENT_RE, ttl) + lines = [x[1:-1] if x else None # Removes parenthesis + for x in lines] + return lines From b2deb4b6c923fcde1efec232c0d152e8b191e6f3 Mon Sep 17 00:00:00 2001 From: Itay Mizeretz Date: Sun, 16 Dec 2018 19:09:08 +0200 Subject: [PATCH 2/8] Add doc for parse_traceroute --- monkey/infection_monkey/network/tools.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/monkey/infection_monkey/network/tools.py b/monkey/infection_monkey/network/tools.py index 64cc70bb6..2b5497d8b 100644 --- a/monkey/infection_monkey/network/tools.py +++ b/monkey/infection_monkey/network/tools.py @@ -192,6 +192,14 @@ def traceroute(target_ip, ttl): def _parse_traceroute(output, regex, ttl): + """ + Parses the output of traceroute (from either Linux or Windows) + :param output: The output of the traceroute + :param regex: Regex for finding an IP address + :param ttl: Max TTL. Must be the same as the TTL used as param for traceroute. + :return: List of ips which are the hops on the way to the traceroute destination. + If a hop's IP wasn't found by traceroute, instead of an IP, the array will contain None + """ ip_lines = output.split('\n') trace_list = [] From 9ccd1db30994aa77ab29369fc680bb522558cbd2 Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Tue, 18 Dec 2018 16:08:19 +0200 Subject: [PATCH 3/8] Make report map colored again --- monkey/monkey_island/cc/ui/src/components/pages/ReportPage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/monkey_island/cc/ui/src/components/pages/ReportPage.js b/monkey/monkey_island/cc/ui/src/components/pages/ReportPage.js index 61e80737b..254d75809 100644 --- a/monkey/monkey_island/cc/ui/src/components/pages/ReportPage.js +++ b/monkey/monkey_island/cc/ui/src/components/pages/ReportPage.js @@ -104,7 +104,7 @@ class ReportPageComponent extends AuthComponent { .then(res => res.json()) .then(res => { res.edges.forEach(edge => { - edge.color = edgeGroupToColor(edge.group); + edge.color = {'color': edgeGroupToColor(edge.group)}; }); this.setState({graph: res}); this.props.onStatusChange(); From 079038783b7d5062b8aff4356380fba7748e5ae6 Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Sun, 23 Dec 2018 11:26:53 +0200 Subject: [PATCH 4/8] Update monkey/infection_monkey/network/tools.py Co-Authored-By: itaymmguardicore <30774653+itaymmguardicore@users.noreply.github.com> --- monkey/infection_monkey/network/tools.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/infection_monkey/network/tools.py b/monkey/infection_monkey/network/tools.py index 2b5497d8b..a5f8c8f28 100644 --- a/monkey/infection_monkey/network/tools.py +++ b/monkey/infection_monkey/network/tools.py @@ -14,7 +14,7 @@ from infection_monkey.pyinstaller_utils import get_binary_file_path DEFAULT_TIMEOUT = 10 BANNER_READ = 1024 IP_ADDR_RE = r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}' -IP_ADDR_PARENT_RE = r'\(' + IP_ADDR_RE + r'\)' +IP_ADDR_PARENTHESES_RE = r'\(' + IP_ADDR_RE + r'\)' LOG = logging.getLogger(__name__) SLEEP_BETWEEN_POLL = 0.5 From 6ff2e7f541d3f432017520296ba29879c7d9def7 Mon Sep 17 00:00:00 2001 From: Itay Mizeretz Date: Sun, 23 Dec 2018 12:21:11 +0200 Subject: [PATCH 5/8] Fix CR comment --- monkey/infection_monkey/network/tools.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/infection_monkey/network/tools.py b/monkey/infection_monkey/network/tools.py index a5f8c8f28..2408663aa 100644 --- a/monkey/infection_monkey/network/tools.py +++ b/monkey/infection_monkey/network/tools.py @@ -251,7 +251,7 @@ def _traceroute_linux(target_ip, ttl): proc_obj = subprocess.Popen(cli, stdout=subprocess.PIPE) stdout, stderr = proc_obj.communicate() - lines = _parse_traceroute(stdout, IP_ADDR_PARENT_RE, ttl) + lines = _parse_traceroute(stdout, IP_ADDR_PARENTHESES_RE, ttl) lines = [x[1:-1] if x else None # Removes parenthesis for x in lines] return lines From 606f3525f7bde8cd731abca69ffdd563de516e0b Mon Sep 17 00:00:00 2001 From: Itay Mizeretz Date: Sun, 23 Dec 2018 16:51:27 +0200 Subject: [PATCH 6/8] Fix CR + add 32/64bit binary choice --- monkey/infection_monkey/monkey.spec | 3 ++- monkey/infection_monkey/network/tools.py | 19 +++++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/monkey/infection_monkey/monkey.spec b/monkey/infection_monkey/monkey.spec index 29fe7db04..7315e10f5 100644 --- a/monkey/infection_monkey/monkey.spec +++ b/monkey/infection_monkey/monkey.spec @@ -97,7 +97,8 @@ def get_msvcr(): def get_traceroute_binaries(): - return [('traceroute', get_bin_file_path('traceroute'), 'BINARY')] + traceroute_name = 'traceroute32' if is_32_bit() else 'traceroute64' + return [(traceroute_name, get_bin_file_path(traceroute_name), 'BINARY')] def get_monkey_filename(): diff --git a/monkey/infection_monkey/network/tools.py b/monkey/infection_monkey/network/tools.py index 2408663aa..a38273260 100644 --- a/monkey/infection_monkey/network/tools.py +++ b/monkey/infection_monkey/network/tools.py @@ -10,6 +10,7 @@ import re from six.moves import range from infection_monkey.pyinstaller_utils import get_binary_file_path +from infection_monkey.utils import is_64bit_python DEFAULT_TIMEOUT = 10 BANNER_READ = 1024 @@ -191,6 +192,21 @@ def traceroute(target_ip, ttl): return _traceroute_linux(target_ip, ttl) +def _get_traceroute_bin_path(): + """ + Gets the path to the prebuilt traceroute executable + + This is the traceroute utility from: http://traceroute.sourceforge.net + Its been built using the buildroot utility with the following settings: + * Statically link to musl and all other required libs + * Optimize for size + This is done because not all linux distros come with traceroute out-of-the-box, and to ensure it behaves as expected + + :return: Path to traceroute executable + """ + return get_binary_file_path("traceroute64" if is_64bit_python() else "traceroute32") + + def _parse_traceroute(output, regex, ttl): """ Parses the output of traceroute (from either Linux or Windows) @@ -244,8 +260,7 @@ def _traceroute_linux(target_ip, ttl): Traceroute for a specific IP/name - Linux implementation """ - traceroute_path = get_binary_file_path("traceroute") - cli = [traceroute_path, + cli = [_get_traceroute_bin_path(), "-m", str(ttl), target_ip] proc_obj = subprocess.Popen(cli, stdout=subprocess.PIPE) From e82fb7f0610eafb6ca5c7762fab87442711cc2d0 Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Sun, 23 Dec 2018 19:35:36 +0200 Subject: [PATCH 7/8] Add default ttl --- monkey/infection_monkey/network/tools.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/infection_monkey/network/tools.py b/monkey/infection_monkey/network/tools.py index a38273260..a5e6d0783 100644 --- a/monkey/infection_monkey/network/tools.py +++ b/monkey/infection_monkey/network/tools.py @@ -179,7 +179,7 @@ def tcp_port_to_service(port): return 'tcp-' + str(port) -def traceroute(target_ip, ttl): +def traceroute(target_ip, ttl=64): """ Traceroute for a specific IP/name. :param target_ip: IP/name of target From 4e5ede0a723435e09858502469fe497fe0e68d5b Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Mon, 24 Dec 2018 10:58:29 +0200 Subject: [PATCH 8/8] Add note on exception throwing --- monkey/infection_monkey/network/tools.py | 1 + 1 file changed, 1 insertion(+) diff --git a/monkey/infection_monkey/network/tools.py b/monkey/infection_monkey/network/tools.py index a5e6d0783..3a9adef57 100644 --- a/monkey/infection_monkey/network/tools.py +++ b/monkey/infection_monkey/network/tools.py @@ -182,6 +182,7 @@ def tcp_port_to_service(port): def traceroute(target_ip, ttl=64): """ Traceroute for a specific IP/name. + Note, may throw exception on failure that should be handled by caller. :param target_ip: IP/name of target :param ttl: Max TTL :return: Sequence of IPs in the way