Merge pull request #189 from VakarisZ/dn_to_ip
Domain name to ip translation
This commit is contained in:
commit
5c32028fba
|
@ -5,9 +5,12 @@ from abc import ABCMeta, abstractmethod
|
||||||
|
|
||||||
import ipaddress
|
import ipaddress
|
||||||
from six import text_type
|
from six import text_type
|
||||||
|
import logging
|
||||||
|
|
||||||
__author__ = 'itamar'
|
__author__ = 'itamar'
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class NetworkRange(object):
|
class NetworkRange(object):
|
||||||
__metaclass__ = ABCMeta
|
__metaclass__ = ABCMeta
|
||||||
|
@ -47,12 +50,23 @@ class NetworkRange(object):
|
||||||
address_str = address_str.strip()
|
address_str = address_str.strip()
|
||||||
if not address_str: # Empty string
|
if not address_str: # Empty string
|
||||||
return None
|
return None
|
||||||
if -1 != address_str.find('-'):
|
if NetworkRange.check_if_range(address_str):
|
||||||
return IpRange(ip_range=address_str)
|
return IpRange(ip_range=address_str)
|
||||||
if -1 != address_str.find('/'):
|
if -1 != address_str.find('/'):
|
||||||
return CidrRange(cidr_range=address_str)
|
return CidrRange(cidr_range=address_str)
|
||||||
return SingleIpRange(ip_address=address_str)
|
return SingleIpRange(ip_address=address_str)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def check_if_range(address_str):
|
||||||
|
if -1 != address_str.find('-'):
|
||||||
|
ips = address_str.split('-')
|
||||||
|
try:
|
||||||
|
ipaddress.ip_address(ips[0]) and ipaddress.ip_address(ips[1])
|
||||||
|
except ValueError as e:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _ip_to_number(address):
|
def _ip_to_number(address):
|
||||||
return struct.unpack(">L", socket.inet_aton(address))[0]
|
return struct.unpack(">L", socket.inet_aton(address))[0]
|
||||||
|
@ -111,13 +125,58 @@ class IpRange(NetworkRange):
|
||||||
class SingleIpRange(NetworkRange):
|
class SingleIpRange(NetworkRange):
|
||||||
def __init__(self, ip_address, shuffle=True):
|
def __init__(self, ip_address, shuffle=True):
|
||||||
super(SingleIpRange, self).__init__(shuffle=shuffle)
|
super(SingleIpRange, self).__init__(shuffle=shuffle)
|
||||||
self._ip_address = ip_address
|
self._ip_address, self.domain_name = self.string_to_host(ip_address)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<SingleIpRange %s>" % (self._ip_address,)
|
return "<SingleIpRange %s>" % (self._ip_address,)
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
"""
|
||||||
|
We have to check if we have an IP to return, because user could have entered invalid
|
||||||
|
domain name and no IP was found
|
||||||
|
:return: IP if there is one
|
||||||
|
"""
|
||||||
|
if self.ip_found():
|
||||||
|
yield self._number_to_ip(self.get_range()[0])
|
||||||
|
|
||||||
def is_in_range(self, ip_address):
|
def is_in_range(self, ip_address):
|
||||||
return self._ip_address == ip_address
|
return self._ip_address == ip_address
|
||||||
|
|
||||||
def _get_range(self):
|
def _get_range(self):
|
||||||
return [SingleIpRange._ip_to_number(self._ip_address)]
|
return [SingleIpRange._ip_to_number(self._ip_address)]
|
||||||
|
|
||||||
|
def ip_found(self):
|
||||||
|
"""
|
||||||
|
Checks if we could translate domain name entered into IP address
|
||||||
|
:return: True if dns found domain name and false otherwise
|
||||||
|
"""
|
||||||
|
return self._ip_address
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def string_to_host(string):
|
||||||
|
"""
|
||||||
|
Converts the string that user entered in "Scan IP/subnet list" to a tuple of domain name and ip
|
||||||
|
:param string: String that was entered in "Scan IP/subnet list"
|
||||||
|
:return: A tuple in format (IP, domain_name). Eg. (192.168.55.1, www.google.com)
|
||||||
|
"""
|
||||||
|
# The most common use case is to enter ip/range into "Scan IP/subnet list"
|
||||||
|
domain_name = ''
|
||||||
|
|
||||||
|
# Make sure to have unicode string
|
||||||
|
user_input = string.decode('utf-8', 'ignore')
|
||||||
|
|
||||||
|
# Try casting user's input as IP
|
||||||
|
try:
|
||||||
|
ip = ipaddress.ip_address(user_input).exploded
|
||||||
|
except ValueError:
|
||||||
|
# Exception means that it's a domain name
|
||||||
|
try:
|
||||||
|
ip = socket.gethostbyname(string)
|
||||||
|
domain_name = string
|
||||||
|
except socket.error:
|
||||||
|
LOG.error("Your specified host: {} is not found as a domain name and"
|
||||||
|
" it's not an IP address".format(string))
|
||||||
|
return None, string
|
||||||
|
# If a string was entered instead of IP we presume that it was domain name and translate it
|
||||||
|
return ip, domain_name
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,9 @@ __author__ = 'itamar'
|
||||||
|
|
||||||
|
|
||||||
class VictimHost(object):
|
class VictimHost(object):
|
||||||
def __init__(self, ip_addr):
|
def __init__(self, ip_addr, domain_name=''):
|
||||||
self.ip_addr = ip_addr
|
self.ip_addr = ip_addr
|
||||||
|
self.domain_name = str(domain_name)
|
||||||
self.os = {}
|
self.os = {}
|
||||||
self.services = {}
|
self.services = {}
|
||||||
self.monkey_exe = None
|
self.monkey_exe = None
|
||||||
|
|
|
@ -7,6 +7,7 @@ from infection_monkey.network.info import local_ips, get_interfaces_ranges
|
||||||
from infection_monkey.model import VictimHost
|
from infection_monkey.model import VictimHost
|
||||||
from infection_monkey.network import HostScanner
|
from infection_monkey.network import HostScanner
|
||||||
from infection_monkey.network import TcpScanner, PingScanner
|
from infection_monkey.network import TcpScanner, PingScanner
|
||||||
|
|
||||||
__author__ = 'itamar'
|
__author__ = 'itamar'
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
@ -78,7 +79,10 @@ class NetworkScanner(object):
|
||||||
for net_range in self._ranges:
|
for net_range in self._ranges:
|
||||||
LOG.debug("Scanning for potential victims in the network %r", net_range)
|
LOG.debug("Scanning for potential victims in the network %r", net_range)
|
||||||
for ip_addr in net_range:
|
for ip_addr in net_range:
|
||||||
victim = VictimHost(ip_addr)
|
if hasattr(net_range, 'domain_name'):
|
||||||
|
victim = VictimHost(ip_addr, net_range.domain_name)
|
||||||
|
else:
|
||||||
|
victim = VictimHost(ip_addr)
|
||||||
if stop_callback and stop_callback():
|
if stop_callback and stop_callback():
|
||||||
LOG.debug("Got stop signal")
|
LOG.debug("Got stop signal")
|
||||||
break
|
break
|
||||||
|
|
|
@ -90,10 +90,11 @@ class Telemetry(flask_restful.Resource):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_edge_by_scan_or_exploit_telemetry(telemetry_json):
|
def get_edge_by_scan_or_exploit_telemetry(telemetry_json):
|
||||||
dst_ip = telemetry_json['data']['machine']['ip_addr']
|
dst_ip = telemetry_json['data']['machine']['ip_addr']
|
||||||
|
dst_domain_name = telemetry_json['data']['machine']['domain_name']
|
||||||
src_monkey = NodeService.get_monkey_by_guid(telemetry_json['monkey_guid'])
|
src_monkey = NodeService.get_monkey_by_guid(telemetry_json['monkey_guid'])
|
||||||
dst_node = NodeService.get_monkey_by_ip(dst_ip)
|
dst_node = NodeService.get_monkey_by_ip(dst_ip)
|
||||||
if dst_node is None:
|
if dst_node is None:
|
||||||
dst_node = NodeService.get_or_create_node(dst_ip)
|
dst_node = NodeService.get_or_create_node(dst_ip, dst_domain_name)
|
||||||
|
|
||||||
return EdgeService.get_or_create_edge(src_monkey["_id"], dst_node["_id"])
|
return EdgeService.get_or_create_edge(src_monkey["_id"], dst_node["_id"])
|
||||||
|
|
||||||
|
@ -144,6 +145,7 @@ class Telemetry(flask_restful.Resource):
|
||||||
edge = Telemetry.get_edge_by_scan_or_exploit_telemetry(telemetry_json)
|
edge = Telemetry.get_edge_by_scan_or_exploit_telemetry(telemetry_json)
|
||||||
data = copy.deepcopy(telemetry_json['data']['machine'])
|
data = copy.deepcopy(telemetry_json['data']['machine'])
|
||||||
ip_address = data.pop("ip_addr")
|
ip_address = data.pop("ip_addr")
|
||||||
|
domain_name = data.pop("domain_name")
|
||||||
new_scan = \
|
new_scan = \
|
||||||
{
|
{
|
||||||
"timestamp": telemetry_json["timestamp"],
|
"timestamp": telemetry_json["timestamp"],
|
||||||
|
@ -153,7 +155,7 @@ class Telemetry(flask_restful.Resource):
|
||||||
mongo.db.edge.update(
|
mongo.db.edge.update(
|
||||||
{"_id": edge["_id"]},
|
{"_id": edge["_id"]},
|
||||||
{"$push": {"scans": new_scan},
|
{"$push": {"scans": new_scan},
|
||||||
"$set": {"ip_address": ip_address}}
|
"$set": {"ip_address": ip_address, 'domain_name': domain_name}}
|
||||||
)
|
)
|
||||||
|
|
||||||
node = mongo.db.node.find_one({"_id": edge["to"]})
|
node = mongo.db.node.find_one({"_id": edge["to"]})
|
||||||
|
|
|
@ -10,6 +10,7 @@ from cc.encryptor import encryptor
|
||||||
from cc.environment.environment import env
|
from cc.environment.environment import env
|
||||||
from cc.utils import local_ip_addresses
|
from cc.utils import local_ip_addresses
|
||||||
from config_schema import SCHEMA
|
from config_schema import SCHEMA
|
||||||
|
|
||||||
__author__ = "itay.mizeretz"
|
__author__ = "itay.mizeretz"
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
|
@ -6,6 +6,7 @@ import cc.services.log
|
||||||
from cc.database import mongo
|
from cc.database import mongo
|
||||||
from cc.services.edge import EdgeService
|
from cc.services.edge import EdgeService
|
||||||
from cc.utils import local_ip_addresses
|
from cc.utils import local_ip_addresses
|
||||||
|
import socket
|
||||||
|
|
||||||
__author__ = "itay.mizeretz"
|
__author__ = "itay.mizeretz"
|
||||||
|
|
||||||
|
@ -41,6 +42,7 @@ class NodeService:
|
||||||
# node is uninfected
|
# node is uninfected
|
||||||
new_node = NodeService.node_to_net_node(node, for_report)
|
new_node = NodeService.node_to_net_node(node, for_report)
|
||||||
new_node["ip_addresses"] = node["ip_addresses"]
|
new_node["ip_addresses"] = node["ip_addresses"]
|
||||||
|
new_node["domain_name"] = node["domain_name"]
|
||||||
|
|
||||||
for edge in edges:
|
for edge in edges:
|
||||||
accessible_from_nodes.append(NodeService.get_monkey_label(NodeService.get_monkey_by_id(edge["from"])))
|
accessible_from_nodes.append(NodeService.get_monkey_label(NodeService.get_monkey_by_id(edge["from"])))
|
||||||
|
@ -62,7 +64,10 @@ class NodeService:
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_node_label(node):
|
def get_node_label(node):
|
||||||
return node["os"]["version"] + " : " + node["ip_addresses"][0]
|
domain_name = ""
|
||||||
|
if node["domain_name"]:
|
||||||
|
domain_name = " ("+node["domain_name"]+")"
|
||||||
|
return node["os"]["version"] + " : " + node["ip_addresses"][0] + domain_name
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _cmp_exploits_by_timestamp(exploit_1, exploit_2):
|
def _cmp_exploits_by_timestamp(exploit_1, exploit_2):
|
||||||
|
@ -137,6 +142,7 @@ class NodeService:
|
||||||
"group": NodeService.get_monkey_group(monkey),
|
"group": NodeService.get_monkey_group(monkey),
|
||||||
"os": NodeService.get_monkey_os(monkey),
|
"os": NodeService.get_monkey_os(monkey),
|
||||||
"dead": monkey["dead"],
|
"dead": monkey["dead"],
|
||||||
|
"domain_name": ""
|
||||||
}
|
}
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -176,10 +182,11 @@ class NodeService:
|
||||||
upsert=False)
|
upsert=False)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def insert_node(ip_address):
|
def insert_node(ip_address, domain_name=''):
|
||||||
new_node_insert_result = mongo.db.node.insert_one(
|
new_node_insert_result = mongo.db.node.insert_one(
|
||||||
{
|
{
|
||||||
"ip_addresses": [ip_address],
|
"ip_addresses": [ip_address],
|
||||||
|
"domain_name": domain_name,
|
||||||
"exploited": False,
|
"exploited": False,
|
||||||
"creds": [],
|
"creds": [],
|
||||||
"os":
|
"os":
|
||||||
|
@ -191,10 +198,10 @@ class NodeService:
|
||||||
return mongo.db.node.find_one({"_id": new_node_insert_result.inserted_id})
|
return mongo.db.node.find_one({"_id": new_node_insert_result.inserted_id})
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_or_create_node(ip_address):
|
def get_or_create_node(ip_address, domain_name=''):
|
||||||
new_node = mongo.db.node.find_one({"ip_addresses": ip_address})
|
new_node = mongo.db.node.find_one({"ip_addresses": ip_address})
|
||||||
if new_node is None:
|
if new_node is None:
|
||||||
new_node = NodeService.insert_node(ip_address)
|
new_node = NodeService.insert_node(ip_address, domain_name)
|
||||||
return new_node
|
return new_node
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -261,6 +268,7 @@ class NodeService:
|
||||||
def get_monkey_island_node():
|
def get_monkey_island_node():
|
||||||
island_node = NodeService.get_monkey_island_pseudo_net_node()
|
island_node = NodeService.get_monkey_island_pseudo_net_node()
|
||||||
island_node["ip_addresses"] = local_ip_addresses()
|
island_node["ip_addresses"] = local_ip_addresses()
|
||||||
|
island_node["domain_name"] = socket.gethostname()
|
||||||
return island_node
|
return island_node
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
|
@ -131,7 +131,8 @@ class ReportService:
|
||||||
list((x['hostname'] for x in
|
list((x['hostname'] for x in
|
||||||
(NodeService.get_displayed_node_by_id(edge['from'], True)
|
(NodeService.get_displayed_node_by_id(edge['from'], True)
|
||||||
for edge in EdgeService.get_displayed_edges_by_to(node['id'], True)))),
|
for edge in EdgeService.get_displayed_edges_by_to(node['id'], True)))),
|
||||||
'services': node['services']
|
'services': node['services'],
|
||||||
|
'domain_name': node['domain_name']
|
||||||
})
|
})
|
||||||
|
|
||||||
logger.info('Scanned nodes generated for reporting')
|
logger.info('Scanned nodes generated for reporting')
|
||||||
|
@ -151,6 +152,7 @@ class ReportService:
|
||||||
{
|
{
|
||||||
'label': monkey['label'],
|
'label': monkey['label'],
|
||||||
'ip_addresses': monkey['ip_addresses'],
|
'ip_addresses': monkey['ip_addresses'],
|
||||||
|
'domain_name': node['domain_name'],
|
||||||
'exploits': list(set(
|
'exploits': list(set(
|
||||||
[ReportService.EXPLOIT_DISPLAY_DICT[exploit['exploiter']] for exploit in monkey['exploits'] if
|
[ReportService.EXPLOIT_DISPLAY_DICT[exploit['exploiter']] for exploit in monkey['exploits'] if
|
||||||
exploit['result']]))
|
exploit['result']]))
|
||||||
|
|
|
@ -5,12 +5,17 @@ let renderArray = function(val) {
|
||||||
return <div>{val.map(x => <div>{x}</div>)}</div>;
|
return <div>{val.map(x => <div>{x}</div>)}</div>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let renderIpAddresses = function (val) {
|
||||||
|
return <div>{renderArray(val.ip_addresses)} {(val.domain_name ? " (".concat(val.domain_name, ")") : "")} </div>;
|
||||||
|
};
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
Header: 'Breached Servers',
|
Header: 'Breached Servers',
|
||||||
columns: [
|
columns: [
|
||||||
{Header: 'Machine', accessor: 'label'},
|
{Header: 'Machine', accessor: 'label'},
|
||||||
{Header: 'IP Addresses', id: 'ip_addresses', accessor: x => renderArray(x.ip_addresses)},
|
{Header: 'IP Addresses', id: 'ip_addresses',
|
||||||
|
accessor: x => renderIpAddresses(x)},
|
||||||
{Header: 'Exploits', id: 'exploits', accessor: x => renderArray(x.exploits)}
|
{Header: 'Exploits', id: 'exploits', accessor: x => renderArray(x.exploits)}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,12 +5,17 @@ let renderArray = function(val) {
|
||||||
return <div>{val.map(x => <div>{x}</div>)}</div>;
|
return <div>{val.map(x => <div>{x}</div>)}</div>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let renderIpAddresses = function (val) {
|
||||||
|
return <div>{renderArray(val.ip_addresses)} {(val.domain_name ? " (".concat(val.domain_name, ")") : "")} </div>;
|
||||||
|
};
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
Header: 'Scanned Servers',
|
Header: 'Scanned Servers',
|
||||||
columns: [
|
columns: [
|
||||||
{ Header: 'Machine', accessor: 'label'},
|
{ Header: 'Machine', accessor: 'label'},
|
||||||
{ Header: 'IP Addresses', id: 'ip_addresses', accessor: x => renderArray(x.ip_addresses)},
|
{ Header: 'IP Addresses', id: 'ip_addresses',
|
||||||
|
accessor: x => renderIpAddresses(x)},
|
||||||
{ Header: 'Accessible From', id: 'accessible_from_nodes', accessor: x => renderArray(x.accessible_from_nodes)},
|
{ Header: 'Accessible From', id: 'accessible_from_nodes', accessor: x => renderArray(x.accessible_from_nodes)},
|
||||||
{ Header: 'Services', id: 'services', accessor: x => renderArray(x.services)}
|
{ Header: 'Services', id: 'services', accessor: x => renderArray(x.services)}
|
||||||
]
|
]
|
||||||
|
|
Loading…
Reference in New Issue