Merge pull request #54 from guardicore/bugfix/various-fixes

Bugfix/various fixes
This commit is contained in:
Daniel Goldberg 2017-10-02 12:48:29 +03:00 committed by GitHub
commit 62713932de
22 changed files with 172 additions and 121 deletions

View File

@ -1 +1 @@
c:\python27\Scripts\pyinstaller -F --log-level=DEBUG --clean --upx-dir=.\bin monkey.spec pyinstaller -F --log-level=DEBUG --clean --upx-dir=.\bin monkey.spec

View File

@ -213,7 +213,7 @@ class Configuration(object):
# exploiters config # exploiters config
########################### ###########################
skip_exploit_if_file_exist = True skip_exploit_if_file_exist = False
ms08_067_exploit_attempts = 5 ms08_067_exploit_attempts = 5
ms08_067_remote_user_add = "Monkey_IUSER_SUPPORT" ms08_067_remote_user_add = "Monkey_IUSER_SUPPORT"

View File

@ -1,14 +1,16 @@
import json import json
import logging import logging
import requests
import platform import platform
import monkeyfs
from network.info import local_ips, check_internet_access
from socket import gethostname from socket import gethostname
from config import WormConfiguration, GUID
from transport.tcp import TcpProxy import requests
from transport.http import HTTPConnectProxy
import monkeyfs
import tunnel import tunnel
from config import WormConfiguration, GUID
from network.info import local_ips, check_internet_access
from transport.http import HTTPConnectProxy
from transport.tcp import TcpProxy
__author__ = 'hoffer' __author__ = 'hoffer'
@ -60,7 +62,7 @@ class ControlClient(object):
timeout=20) timeout=20)
break break
except Exception, exc: except Exception as exc:
WormConfiguration.current_server = "" WormConfiguration.current_server = ""
LOG.warn("Error connecting to control server %s: %s", server, exc) LOG.warn("Error connecting to control server %s: %s", server, exc)
@ -89,7 +91,7 @@ class ControlClient(object):
headers={'content-type': 'application/json'}, headers={'content-type': 'application/json'},
verify=False, verify=False,
proxies=ControlClient.proxies) proxies=ControlClient.proxies)
except Exception, exc: except Exception as exc:
LOG.warn("Error connecting to control server %s: %s", LOG.warn("Error connecting to control server %s: %s",
WormConfiguration.current_server, exc) WormConfiguration.current_server, exc)
return {} return {}
@ -105,7 +107,7 @@ class ControlClient(object):
headers={'content-type': 'application/json'}, headers={'content-type': 'application/json'},
verify=False, verify=False,
proxies=ControlClient.proxies) proxies=ControlClient.proxies)
except Exception, exc: except Exception as exc:
LOG.warn("Error connecting to control server %s: %s", LOG.warn("Error connecting to control server %s: %s",
WormConfiguration.current_server, exc) WormConfiguration.current_server, exc)
@ -118,7 +120,7 @@ class ControlClient(object):
verify=False, verify=False,
proxies=ControlClient.proxies) proxies=ControlClient.proxies)
except Exception, exc: except Exception as exc:
LOG.warn("Error connecting to control server %s: %s", LOG.warn("Error connecting to control server %s: %s",
WormConfiguration.current_server, exc) WormConfiguration.current_server, exc)
return return
@ -126,7 +128,7 @@ class ControlClient(object):
try: try:
unknown_variables = WormConfiguration.from_dict(reply.json().get('config')) unknown_variables = WormConfiguration.from_dict(reply.json().get('config'))
LOG.info("New configuration was loaded from server: %r" % (WormConfiguration.as_dict(),)) LOG.info("New configuration was loaded from server: %r" % (WormConfiguration.as_dict(),))
except Exception, exc: except Exception as exc:
# we don't continue with default conf here because it might be dangerous # we don't continue with default conf here because it might be dangerous
LOG.error("Error parsing JSON reply from control server %s (%s): %s", LOG.error("Error parsing JSON reply from control server %s (%s): %s",
WormConfiguration.current_server, reply._content, exc) WormConfiguration.current_server, reply._content, exc)
@ -145,7 +147,7 @@ class ControlClient(object):
headers={'content-type': 'application/json'}, headers={'content-type': 'application/json'},
verify=False, verify=False,
proxies=ControlClient.proxies) proxies=ControlClient.proxies)
except Exception, exc: except Exception as exc:
LOG.warn("Error connecting to control server %s: %s", WormConfiguration.current_server, exc) LOG.warn("Error connecting to control server %s: %s", WormConfiguration.current_server, exc)
return {} return {}
@ -215,7 +217,7 @@ class ControlClient(object):
if size == monkeyfs.getsize(dest_file): if size == monkeyfs.getsize(dest_file):
return dest_file return dest_file
except Exception, exc: except Exception as exc:
LOG.warn("Error connecting to control server %s: %s", LOG.warn("Error connecting to control server %s: %s",
WormConfiguration.current_server, exc) WormConfiguration.current_server, exc)
@ -243,7 +245,7 @@ class ControlClient(object):
else: else:
return None, None return None, None
except Exception, exc: except Exception as exc:
LOG.warn("Error connecting to control server %s: %s", LOG.warn("Error connecting to control server %s: %s",
WormConfiguration.current_server, exc) WormConfiguration.current_server, exc)

View File

@ -1,17 +1,17 @@
import argparse
import ctypes
import logging
import os import os
import pprint
import shutil
import subprocess
import sys import sys
import time import time
import ctypes
import shutil
import pprint
import logging
import subprocess
import argparse
from ctypes import c_char_p from ctypes import c_char_p
from config import WormConfiguration
from exploit.tools import build_monkey_commandline_explicitly from exploit.tools import build_monkey_commandline_explicitly
from model import MONKEY_CMDLINE_WINDOWS, MONKEY_CMDLINE_LINUX, GENERAL_CMDLINE_LINUX from model import MONKEY_CMDLINE_WINDOWS, MONKEY_CMDLINE_LINUX, GENERAL_CMDLINE_LINUX
from config import WormConfiguration
from system_info import SystemInfoCollector, OperatingSystem from system_info import SystemInfoCollector, OperatingSystem
if "win32" == sys.platform: if "win32" == sys.platform:
@ -19,6 +19,12 @@ if "win32" == sys.platform:
else: else:
DETACHED_PROCESS = 0 DETACHED_PROCESS = 0
# Linux doesn't have WindowsError
try:
WindowsError
except NameError:
WindowsError = None
__author__ = 'itamar' __author__ = 'itamar'
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -62,7 +68,7 @@ class MonkeyDrops(object):
self._config['source_path'], self._config['destination_path']) self._config['source_path'], self._config['destination_path'])
file_moved = True file_moved = True
except (WindowsError, IOError, OSError), exc: except (WindowsError, IOError, OSError) as exc:
LOG.debug("Error moving source file '%s' into '%s': %s", LOG.debug("Error moving source file '%s' into '%s': %s",
self._config['source_path'], self._config['destination_path'], self._config['source_path'], self._config['destination_path'],
exc) exc)
@ -75,7 +81,7 @@ class MonkeyDrops(object):
LOG.info("Copied source file '%s' into '%s'", LOG.info("Copied source file '%s' into '%s'",
self._config['source_path'], self._config['destination_path']) self._config['source_path'], self._config['destination_path'])
except (WindowsError, IOError, OSError), exc: except (WindowsError, IOError, OSError) as exc:
LOG.error("Error copying source file '%s' into '%s': %s", LOG.error("Error copying source file '%s' into '%s': %s",
self._config['source_path'], self._config['destination_path'], self._config['source_path'], self._config['destination_path'],
exc) exc)
@ -89,7 +95,7 @@ class MonkeyDrops(object):
dropper_date_reference_path = WormConfiguration.dropper_date_reference_path_linux dropper_date_reference_path = WormConfiguration.dropper_date_reference_path_linux
try: try:
ref_stat = os.stat(dropper_date_reference_path) ref_stat = os.stat(dropper_date_reference_path)
except: except OSError as exc:
LOG.warn("Cannot set reference date using '%s', file not found", LOG.warn("Cannot set reference date using '%s', file not found",
dropper_date_reference_path) dropper_date_reference_path)
else: else:
@ -131,12 +137,12 @@ class MonkeyDrops(object):
# try removing the file first # try removing the file first
try: try:
os.remove(self._config['source_path']) os.remove(self._config['source_path'])
except Exception, exc: except Exception as exc:
LOG.debug("Error removing source file '%s': %s", self._config['source_path'], exc) LOG.debug("Error removing source file '%s': %s", self._config['source_path'], exc)
# mark the file for removal on next boot # mark the file for removal on next boot
dropper_source_path_ctypes = c_char_p(self._config['source_path']) dropper_source_path_ctypes = c_char_p(self._config['source_path'])
if 0 == ctypes.windll.kernel32.MoveFileExA( dropper_source_path_ctypes, None, if 0 == ctypes.windll.kernel32.MoveFileExA(dropper_source_path_ctypes, None,
MOVEFILE_DELAY_UNTIL_REBOOT): MOVEFILE_DELAY_UNTIL_REBOOT):
LOG.debug("Error marking source file '%s' for deletion on next boot (error %d)", LOG.debug("Error marking source file '%s' for deletion on next boot (error %d)",
self._config['source_path'], ctypes.windll.kernel32.GetLastError()) self._config['source_path'], ctypes.windll.kernel32.GetLastError())

View File

@ -62,7 +62,7 @@
"self_delete_in_cleanup": true, "self_delete_in_cleanup": true,
"serialize_config": false, "serialize_config": false,
"singleton_mutex_name": "{2384ec59-0df8-4ab9-918c-843740924a28}", "singleton_mutex_name": "{2384ec59-0df8-4ab9-918c-843740924a28}",
"skip_exploit_if_file_exist": true, "skip_exploit_if_file_exist": false,
"exploit_user_list": [], "exploit_user_list": [],
"exploit_password_list": [], "exploit_password_list": [],
"exploit_lm_hash_list": [], "exploit_lm_hash_list": [],

View File

@ -53,6 +53,9 @@ class ElasticGroovyExploiter(HostExploiter):
LOG.info("Host: %s doesn't have ES open" % host.ip_addr) LOG.info("Host: %s doesn't have ES open" % host.ip_addr)
return False return False
major, minor, build = host.services[ES_SERVICE]['version'].split('.') major, minor, build = host.services[ES_SERVICE]['version'].split('.')
major = int(major)
minor = int(minor)
build = int(build)
if major > 1: if major > 1:
return False return False
if major == 1 and minor > 4: if major == 1 and minor > 4:

View File

@ -206,6 +206,9 @@ class SambaCryExploiter(HostExploiter):
elif (samba_version_parts[0] == "4") and (samba_version_parts[1] == "6") and ( elif (samba_version_parts[0] == "4") and (samba_version_parts[1] == "6") and (
samba_version_parts[1] <= "3"): samba_version_parts[1] <= "3"):
is_vulnerable = True is_vulnerable = True
else:
# If pattern doesn't match we can't tell what version it is. Better try
is_vulnerable = True
LOG.info("Host: %s.samba server name: %s. samba version: %s. is vulnerable: %s" % LOG.info("Host: %s.samba server name: %s. samba version: %s. is vulnerable: %s" %
(host.ip_addr, smb_server_name, samba_version, repr(is_vulnerable))) (host.ip_addr, smb_server_name, samba_version, repr(is_vulnerable)))
@ -304,7 +307,7 @@ class SambaCryExploiter(HostExploiter):
try: try:
# the extra / on the beginning is required for the vulnerability # the extra / on the beginning is required for the vulnerability
self.open_pipe(smb_client, "/" + module_path) self.open_pipe(smb_client, "/" + module_path)
except (impacket.smbconnection.SessionError, SessionError) as e: except Exception as e:
# This is the expected result. We can't tell whether we succeeded or not just by this error code. # This is the expected result. We can't tell whether we succeeded or not just by this error code.
if str(e).find('STATUS_OBJECT_NAME_NOT_FOUND') >= 0: if str(e).find('STATUS_OBJECT_NAME_NOT_FOUND') >= 0:
return True return True

View File

@ -64,7 +64,8 @@ class ShellShockExploiter(HostExploiter):
# we want to report all vulnerable URLs even if we didn't succeed # we want to report all vulnerable URLs even if we didn't succeed
# let's overload this # let's overload this
[self.report_vuln_shellshock(host, url) for url in exploitable_urls] # TODO: uncomment when server is ready for it
# [self.report_vuln_shellshock(host, url) for url in exploitable_urls]
# now try URLs until we install something on victim # now try URLs until we install something on victim
for _, url, header, exploit in exploitable_urls: for _, url, header, exploit in exploitable_urls:

View File

@ -171,9 +171,11 @@ class ChaosMonkey(object):
ControlClient.send_telemetry('exploit', {'result': False, 'machine': machine.__dict__, ControlClient.send_telemetry('exploit', {'result': False, 'machine': machine.__dict__,
'exploiter': exploiter.__class__.__name__}) 'exploiter': exploiter.__class__.__name__})
except Exception, exc: except Exception as exc:
LOG.error("Exception while attacking %s using %s: %s", LOG.error("Exception while attacking %s using %s: %s",
machine, exploiter.__class__.__name__, exc) machine, exploiter.__class__.__name__, exc)
ControlClient.send_telemetry('exploit', {'result': False, 'machine': machine.__dict__,
'exploiter': exploiter.__class__.__name__})
continue continue
if successful_exploiter: if successful_exploiter:

View File

@ -6,6 +6,12 @@ from enum import IntEnum
from network.info import get_host_subnets from network.info import get_host_subnets
# Linux doesn't have WindowsError
try:
WindowsError
except NameError:
WindowsError = None
__author__ = 'uri' __author__ = 'uri'

View File

@ -1,14 +1,13 @@
import ctypes import ctypes
import binascii import binascii
import logging import logging
import socket
__author__ = 'itay.mizeretz' __author__ = 'itay.mizeretz'
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
class MimikatzCollector: class MimikatzCollector:
""" """
Password collection module for Windows using Mimikatz. Password collection module for Windows using Mimikatz.
@ -24,7 +23,7 @@ class MimikatzCollector:
self._collect = collect_proto(("collect", self._dll)) self._collect = collect_proto(("collect", self._dll))
self._get = get_proto(("get", self._dll)) self._get = get_proto(("get", self._dll))
self._isInit = True self._isInit = True
except StandardError as ex: except StandardError:
LOG.exception("Error initializing mimikatz collector") LOG.exception("Error initializing mimikatz collector")
def get_logon_info(self): def get_logon_info(self):
@ -40,18 +39,28 @@ class MimikatzCollector:
entry_count = self._collect() entry_count = self._collect()
logon_data_dictionary = {} logon_data_dictionary = {}
hostname = socket.gethostname()
for i in range(entry_count): for i in range(entry_count):
entry = self._get() entry = self._get()
username = str(entry.username) username = entry.username.encode('utf-8').strip()
password = str(entry.password)
password = entry.password.encode('utf-8').strip()
lm_hash = binascii.hexlify(bytearray(entry.lm_hash)) lm_hash = binascii.hexlify(bytearray(entry.lm_hash))
ntlm_hash = binascii.hexlify(bytearray(entry.ntlm_hash)) ntlm_hash = binascii.hexlify(bytearray(entry.ntlm_hash))
has_password = (0 != len(password))
if 0 == len(password):
has_password = False
elif (username[-1] == '$') and (hostname.lower() == username[0:-1].lower()):
# Don't save the password of the host domain user (HOSTNAME$)
has_password = False
else:
has_password = True
has_lm = ("00000000000000000000000000000000" != lm_hash) has_lm = ("00000000000000000000000000000000" != lm_hash)
has_ntlm = ("00000000000000000000000000000000" != ntlm_hash) has_ntlm = ("00000000000000000000000000000000" != ntlm_hash)
if not logon_data_dictionary.has_key(username): if username not in logon_data_dictionary:
logon_data_dictionary[username] = {} logon_data_dictionary[username] = {}
if has_password: if has_password:
logon_data_dictionary[username]["password"] = password logon_data_dictionary[username]["password"] = password
@ -61,7 +70,7 @@ class MimikatzCollector:
logon_data_dictionary[username]["ntlm_hash"] = ntlm_hash logon_data_dictionary[username]["ntlm_hash"] = ntlm_hash
return logon_data_dictionary return logon_data_dictionary
except StandardError as ex: except StandardError:
LOG.exception("Error getting logon info") LOG.exception("Error getting logon info")
return {} return {}

View File

@ -1,7 +1,8 @@
import sys
import ctypes import ctypes
import logging import logging
import sys
from abc import ABCMeta, abstractmethod from abc import ABCMeta, abstractmethod
from config import WormConfiguration from config import WormConfiguration
__author__ = 'itamar' __author__ = 'itamar'
@ -28,7 +29,7 @@ class _SystemSingleton(object):
class WindowsSystemSingleton(_SystemSingleton): class WindowsSystemSingleton(_SystemSingleton):
def __init__(self): def __init__(self):
self._mutex_name = r"Global\%s" % (WormConfiguration.singleton_mutex_name, ) self._mutex_name = r"Global\%s" % (WormConfiguration.singleton_mutex_name,)
self._mutex_handle = None self._mutex_handle = None
@property @property
@ -84,7 +85,7 @@ class LinuxSystemSingleton(_SystemSingleton):
try: try:
sock.bind('\0' + self._unix_sock_name) sock.bind('\0' + self._unix_sock_name)
except socket.error, e: except socket.error as e:
LOG.error("Cannot acquire system singleton %r, error code %d, error: %s", LOG.error("Cannot acquire system singleton %r, error code %d, error: %s",
self._unix_sock_name, e.args[0], e.args[1]) self._unix_sock_name, e.args[0], e.args[1])
return False return False
@ -100,9 +101,12 @@ class LinuxSystemSingleton(_SystemSingleton):
self._sock_handle.close() self._sock_handle.close()
self._sock_handle = None self._sock_handle = None
if sys.platform == "win32": if sys.platform == "win32":
import winerror import winerror
SystemSingleton = WindowsSystemSingleton SystemSingleton = WindowsSystemSingleton
else: else:
import socket import socket
SystemSingleton = LinuxSystemSingleton SystemSingleton = LinuxSystemSingleton

View File

@ -1,10 +1,14 @@
import urllib, BaseHTTPServer, threading, os.path import BaseHTTPServer
import monkeyfs import os.path
from logging import getLogger
from base import TransportProxyBase, update_last_serve_time
from urlparse import urlsplit
import select import select
import socket import socket
import threading
import urllib
from logging import getLogger
from urlparse import urlsplit
import monkeyfs
from base import TransportProxyBase, update_last_serve_time
__author__ = 'hoffer' __author__ = 'hoffer'
@ -55,9 +59,9 @@ class FileServHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
f.close() f.close()
def send_head(self): def send_head(self):
if self.path != '/'+urllib.quote(os.path.basename(self.filename)): if self.path != '/' + urllib.quote(os.path.basename(self.filename)):
self.send_error (500, "") self.send_error(500, "")
return return None, 0, 0
f = None f = None
try: try:
f = monkeyfs.open(self.filename, 'rb') f = monkeyfs.open(self.filename, 'rb')
@ -163,7 +167,7 @@ class HTTPServer(threading.Thread):
@staticmethod @staticmethod
def report_download(dest=None): def report_download(dest=None):
LOG.info('File downloaded from (%s,%s)' % (dest[0],dest[1])) LOG.info('File downloaded from (%s,%s)' % (dest[0], dest[1]))
self.downloads += 1 self.downloads += 1
httpd = BaseHTTPServer.HTTPServer((self._local_ip, self._local_port), TempHandler) httpd = BaseHTTPServer.HTTPServer((self._local_ip, self._local_port), TempHandler)

View File

@ -1,14 +1,15 @@
import logging
import socket import socket
import struct import struct
import logging
from threading import Thread
from network.info import local_ips, get_free_tcp_port
from network.firewall import app as firewall
from transport.base import get_last_serve_time
from difflib import get_close_matches
from network.tools import check_port_tcp
from model import VictimHost
import time import time
from difflib import get_close_matches
from threading import Thread
from model import VictimHost
from network.firewall import app as firewall
from network.info import local_ips, get_free_tcp_port
from network.tools import check_port_tcp
from transport.base import get_last_serve_time
__author__ = 'hoffer' __author__ = 'hoffer'
@ -48,7 +49,7 @@ def _check_tunnel(address, port, existing_sock=None):
try: try:
sock.sendto("+", (address, MCAST_PORT)) sock.sendto("+", (address, MCAST_PORT))
except Exception, exc: except Exception as exc:
LOG.debug("Caught exception in tunnel registration: %s", exc) LOG.debug("Caught exception in tunnel registration: %s", exc)
if not existing_sock: if not existing_sock:
@ -91,7 +92,7 @@ def find_tunnel(default=None, attempts=3, timeout=DEFAULT_TIMEOUT):
sock.close() sock.close()
return address, port return address, port
except Exception, exc: except Exception as exc:
LOG.debug("Caught exception in tunnel lookup: %s", exc) LOG.debug("Caught exception in tunnel lookup: %s", exc)
continue continue
@ -104,7 +105,7 @@ def quit_tunnel(address, timeout=DEFAULT_TIMEOUT):
sock.sendto("-", (address, MCAST_PORT)) sock.sendto("-", (address, MCAST_PORT))
sock.close() sock.close()
LOG.debug("Success quitting tunnel") LOG.debug("Success quitting tunnel")
except Exception, exc: except Exception as exc:
LOG.debug("Exception quitting tunnel: %s", exc) LOG.debug("Exception quitting tunnel: %s", exc)
return return

View File

@ -46,9 +46,8 @@ class Monkey(flask_restful.Resource):
update['$set']['config_error'] = monkey_json['config_error'] update['$set']['config_error'] = monkey_json['config_error']
if 'tunnel' in monkey_json: if 'tunnel' in monkey_json:
host = monkey_json['tunnel'].split(":")[-2].replace("//", "") tunnel_host_ip = monkey_json['tunnel'].split(":")[-2].replace("//", "")
tunnel_host_id = NodeService.get_monkey_by_ip(host)["_id"] NodeService.set_monkey_tunnel(monkey["_id"], tunnel_host_ip)
NodeService.set_monkey_tunnel(monkey["_id"], tunnel_host_id)
return mongo.db.monkey.update({"_id": monkey["_id"]}, update, upsert=False) return mongo.db.monkey.update({"_id": monkey["_id"]}, update, upsert=False)
@ -98,10 +97,9 @@ class Monkey(flask_restful.Resource):
else: else:
monkey_json['parent'] = db_monkey.get('parent') + [parent_to_add] monkey_json['parent'] = db_monkey.get('parent') + [parent_to_add]
tunnel_host_id = None tunnel_host_ip = None
if 'tunnel' in monkey_json: if 'tunnel' in monkey_json:
host = monkey_json['tunnel'].split(":")[-2].replace("//", "") tunnel_host_ip = monkey_json['tunnel'].split(":")[-2].replace("//", "")
tunnel_host_id = NodeService.get_monkey_by_ip(host)["_id"]
monkey_json.pop('tunnel') monkey_json.pop('tunnel')
mongo.db.monkey.update({"guid": monkey_json["guid"]}, mongo.db.monkey.update({"guid": monkey_json["guid"]},
@ -112,8 +110,8 @@ class Monkey(flask_restful.Resource):
new_monkey_id = mongo.db.monkey.find_one({"guid": monkey_json["guid"]})["_id"] new_monkey_id = mongo.db.monkey.find_one({"guid": monkey_json["guid"]})["_id"]
if tunnel_host_id is not None: if tunnel_host_ip is not None:
NodeService.set_monkey_tunnel(new_monkey_id, tunnel_host_id) NodeService.set_monkey_tunnel(new_monkey_id, tunnel_host_ip)
existing_node = mongo.db.node.find_one({"ip_addresses": {"$in": monkey_json["ip_addresses"]}}) existing_node = mongo.db.node.find_one({"ip_addresses": {"$in": monkey_json["ip_addresses"]}})

View File

@ -89,9 +89,8 @@ class Telemetry(flask_restful.Resource):
def process_tunnel_telemetry(self, telemetry_json): def process_tunnel_telemetry(self, telemetry_json):
monkey_id = NodeService.get_monkey_by_guid(telemetry_json['monkey_guid'])["_id"] monkey_id = NodeService.get_monkey_by_guid(telemetry_json['monkey_guid'])["_id"]
if telemetry_json['data']['proxy'] is not None: if telemetry_json['data']['proxy'] is not None:
host = telemetry_json['data']['proxy'].split(":")[-2].replace("//", "") tunnel_host_ip = telemetry_json['data']['proxy'].split(":")[-2].replace("//", "")
tunnel_host_id = NodeService.get_monkey_by_ip(host)["_id"] NodeService.set_monkey_tunnel(monkey_id, tunnel_host_ip)
NodeService.set_monkey_tunnel(monkey_id, tunnel_host_id)
else: else:
NodeService.unset_all_monkey_tunnels(monkey_id) NodeService.unset_all_monkey_tunnels(monkey_id)

View File

@ -506,7 +506,7 @@ SCHEMA = {
"skip_exploit_if_file_exist": { "skip_exploit_if_file_exist": {
"title": "Skip exploit if file exists", "title": "Skip exploit if file exists",
"type": "boolean", "type": "boolean",
"default": True, "default": False,
"description": "Determines whether the monkey should skip the exploit if the monkey's file is already on the remote machine" "description": "Determines whether the monkey should skip the exploit if the monkey's file is already on the remote machine"
} }
} }

View File

@ -22,7 +22,7 @@ class EdgeService:
@staticmethod @staticmethod
def edge_to_displayed_edge(edge): def edge_to_displayed_edge(edge):
services = {} services = []
os = {} os = {}
exploits = [] exploits = []
if len(edge["scans"]) > 0: if len(edge["scans"]) > 0:
@ -52,6 +52,7 @@ class EdgeService:
exploit_container["end_timestamp"] = new_exploit["timestamp"] exploit_container["end_timestamp"] = new_exploit["timestamp"]
displayed_edge = EdgeService.edge_to_net_edge(edge) displayed_edge = EdgeService.edge_to_net_edge(edge)
displayed_edge["ip_address"] = edge["ip_address"] displayed_edge["ip_address"] = edge["ip_address"]
displayed_edge["services"] = services displayed_edge["services"] = services
displayed_edge["os"] = os displayed_edge["os"] = os

View File

@ -148,7 +148,8 @@ class NodeService:
upsert=False) upsert=False)
@staticmethod @staticmethod
def set_monkey_tunnel(monkey_id, tunnel_host_id): def set_monkey_tunnel(monkey_id, tunnel_host_ip):
tunnel_host_id = NodeService.get_monkey_by_ip(tunnel_host_ip)["_id"]
NodeService.unset_all_monkey_tunnels(monkey_id) NodeService.unset_all_monkey_tunnels(monkey_id)
mongo.db.monkey.update( mongo.db.monkey.update(
{"_id": monkey_id}, {"_id": monkey_id},
@ -156,7 +157,7 @@ class NodeService:
upsert=False) upsert=False)
tunnel_edge = EdgeService.get_or_create_edge(monkey_id, tunnel_host_id) tunnel_edge = EdgeService.get_or_create_edge(monkey_id, tunnel_host_id)
mongo.db.edge.update({"_id": tunnel_edge["_id"]}, mongo.db.edge.update({"_id": tunnel_edge["_id"]},
{'$set': {'tunnel': True}}, {'$set': {'tunnel': True, 'ip_address': tunnel_host_ip}},
upsert=False) upsert=False)
@staticmethod @staticmethod

View File

@ -10,6 +10,8 @@ let groupNames = ['clean_linux', 'clean_windows', 'exploited_linux', 'exploited_
'manual_linux', 'manual_linux_running', 'manual_windows', 'manual_windows_running', 'monkey_linux', 'manual_linux', 'manual_linux_running', 'manual_windows', 'manual_windows_running', 'monkey_linux',
'monkey_linux_running', 'monkey_windows', 'monkey_windows_running']; 'monkey_linux_running', 'monkey_windows', 'monkey_windows_running'];
let legend = require('../../images/map-legend.png');
let getGroupsOptions = () => { let getGroupsOptions = () => {
let groupOptions = {}; let groupOptions = {};
for (let groupName of groupNames) { for (let groupName of groupNames) {
@ -28,6 +30,7 @@ let options = {
improvedLayout: false improvedLayout: false
}, },
edges: { edges: {
width: 2,
smooth: { smooth: {
type: 'curvedCW' type: 'curvedCW'
} }
@ -61,7 +64,7 @@ class MapPageComponent extends React.Component {
case 'exploited': case 'exploited':
return '#c00'; return '#c00';
case 'tunnel': case 'tunnel':
return '#aaa'; return '#0058aa';
case 'scan': case 'scan':
return '#f90'; return '#f90';
case 'island': case 'island':
@ -129,6 +132,9 @@ class MapPageComponent extends React.Component {
<Col xs={12}> <Col xs={12}>
<h1 className="page-title">Infection Map</h1> <h1 className="page-title">Infection Map</h1>
</Col> </Col>
<Col xs={12}>
<img src={legend}/>
</Col>
<Col xs={8}> <Col xs={8}>
<Graph graph={this.state.graph} options={options} events={this.events}/> <Graph graph={this.state.graph} options={options} events={this.events}/>
</Col> </Col>

View File

@ -134,13 +134,18 @@ class RunMonkeyPageComponent extends React.Component {
Run on C&C Server Run on C&C Server
{ this.renderIconByState(this.state.runningOnIslandState) } { this.renderIconByState(this.state.runningOnIslandState) }
</button> </button>
<a {
// TODO: implement button functionality
/*
<button
className="btn btn-default" className="btn btn-default"
disabled={this.state.runningOnClientState !== 'not_running'} disabled={this.state.runningOnClientState !== 'not_running'}
style={{'marginLeft': '1em'}}> style={{'marginLeft': '1em'}}>
Download and run locally Download and run locally
{ this.renderIconByState(this.state.runningOnClientState) } { this.renderIconByState(this.state.runningOnClientState) }
</a> </button>
*/
}
</p> </p>
<div className="run-monkey-snippets" style={{'marginBottom': '3em'}}> <div className="run-monkey-snippets" style={{'marginBottom': '3em'}}>
<p> <p>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB