Merge remote-tracking branch 'upstream/develop' into attack_module_load
This commit is contained in:
commit
92f66ba907
|
@ -3,12 +3,6 @@ language: python
|
||||||
cache: pip
|
cache: pip
|
||||||
python:
|
python:
|
||||||
- 2.7
|
- 2.7
|
||||||
- 3.6
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- python: 3.7
|
|
||||||
dist: xenial # required for Python 3.7 (travis-ci/travis-ci#9069)
|
|
||||||
sudo: required # required for Python 3.7 (travis-ci/travis-ci#9069)
|
|
||||||
install:
|
install:
|
||||||
#- pip install -r requirements.txt
|
#- pip install -r requirements.txt
|
||||||
- pip install flake8 # pytest # add another testing frameworks later
|
- pip install flake8 # pytest # add another testing frameworks later
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import hashlib
|
||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
import sys
|
import sys
|
||||||
|
@ -13,9 +14,11 @@ GUID = str(uuid.getnode())
|
||||||
|
|
||||||
EXTERNAL_CONFIG_FILE = os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), 'monkey.bin')
|
EXTERNAL_CONFIG_FILE = os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), 'monkey.bin')
|
||||||
|
|
||||||
|
SENSITIVE_FIELDS = ["exploit_password_list", "exploit_user_list"]
|
||||||
|
HIDDEN_FIELD_REPLACEMENT_CONTENT = "hidden"
|
||||||
|
|
||||||
|
|
||||||
class Configuration(object):
|
class Configuration(object):
|
||||||
|
|
||||||
def from_kv(self, formatted_data):
|
def from_kv(self, formatted_data):
|
||||||
# now we won't work at <2.7 for sure
|
# now we won't work at <2.7 for sure
|
||||||
network_import = importlib.import_module('infection_monkey.network')
|
network_import = importlib.import_module('infection_monkey.network')
|
||||||
|
@ -53,6 +56,12 @@ class Configuration(object):
|
||||||
result = self.from_kv(formatted_data)
|
result = self.from_kv(formatted_data)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def hide_sensitive_info(config_dict):
|
||||||
|
for field in SENSITIVE_FIELDS:
|
||||||
|
config_dict[field] = HIDDEN_FIELD_REPLACEMENT_CONTENT
|
||||||
|
return config_dict
|
||||||
|
|
||||||
def as_dict(self):
|
def as_dict(self):
|
||||||
result = {}
|
result = {}
|
||||||
for key in dir(Configuration):
|
for key in dir(Configuration):
|
||||||
|
@ -272,5 +281,17 @@ class Configuration(object):
|
||||||
PBA_linux_filename = None
|
PBA_linux_filename = None
|
||||||
PBA_windows_filename = None
|
PBA_windows_filename = None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def hash_sensitive_data(sensitive_data):
|
||||||
|
"""
|
||||||
|
Hash sensitive data (e.g. passwords). Used so the log won't contain sensitive data plain-text, as the log is
|
||||||
|
saved on client machines plain-text.
|
||||||
|
|
||||||
|
:param sensitive_data: the data to hash.
|
||||||
|
:return: the hashed data.
|
||||||
|
"""
|
||||||
|
password_hashed = hashlib.sha512(sensitive_data).hexdigest()
|
||||||
|
return password_hashed
|
||||||
|
|
||||||
|
|
||||||
WormConfiguration = Configuration()
|
WormConfiguration = Configuration()
|
||||||
|
|
|
@ -168,7 +168,8 @@ class ControlClient(object):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
unknown_variables = WormConfiguration.from_kv(reply.json().get('config'))
|
unknown_variables = WormConfiguration.from_kv(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.hide_sensitive_info(WormConfiguration.as_dict()),))
|
||||||
except Exception as 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",
|
||||||
|
|
|
@ -123,8 +123,9 @@ class MSSQLExploiter(HostExploiter):
|
||||||
# Core steps
|
# Core steps
|
||||||
# Trying to connect
|
# Trying to connect
|
||||||
conn = pymssql.connect(host, user, password, port=port, login_timeout=self.LOGIN_TIMEOUT)
|
conn = pymssql.connect(host, user, password, port=port, login_timeout=self.LOGIN_TIMEOUT)
|
||||||
LOG.info('Successfully connected to host: {0}, '
|
LOG.info(
|
||||||
'using user: {1}, password: {2}'.format(host, user, password))
|
'Successfully connected to host: {0}, using user: {1}, password (SHA-512): {2}'.format(
|
||||||
|
host, user, self._config.hash_sensitive_data(password)))
|
||||||
self.add_vuln_port(MSSQLExploiter.SQL_DEFAULT_TCP_PORT)
|
self.add_vuln_port(MSSQLExploiter.SQL_DEFAULT_TCP_PORT)
|
||||||
self.report_login_attempt(True, user, password)
|
self.report_login_attempt(True, user, password)
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
|
@ -9,16 +9,16 @@ from rdpy.core.error import RDPSecurityNegoFail
|
||||||
from rdpy.protocol.rdp import rdp
|
from rdpy.protocol.rdp import rdp
|
||||||
from twisted.internet import reactor
|
from twisted.internet import reactor
|
||||||
|
|
||||||
|
from common.utils.attack_utils import ScanStatus, BITS_UPLOAD_STRING
|
||||||
|
from common.utils.exploit_enum import ExploitType
|
||||||
from infection_monkey.exploit import HostExploiter
|
from infection_monkey.exploit import HostExploiter
|
||||||
from infection_monkey.exploit.tools import HTTPTools, get_monkey_depth
|
from infection_monkey.exploit.tools import HTTPTools, get_monkey_depth
|
||||||
|
from infection_monkey.exploit.tools import build_monkey_commandline
|
||||||
from infection_monkey.exploit.tools import get_target_monkey
|
from infection_monkey.exploit.tools import get_target_monkey
|
||||||
from infection_monkey.model import RDP_CMDLINE_HTTP_BITS, RDP_CMDLINE_HTTP_VBS
|
from infection_monkey.model import RDP_CMDLINE_HTTP_BITS, RDP_CMDLINE_HTTP_VBS
|
||||||
from infection_monkey.network.tools import check_tcp_port
|
from infection_monkey.network.tools import check_tcp_port
|
||||||
from infection_monkey.exploit.tools import build_monkey_commandline
|
|
||||||
from infection_monkey.telemetry.attack.t1197_telem import T1197Telem
|
from infection_monkey.telemetry.attack.t1197_telem import T1197Telem
|
||||||
from infection_monkey.utils import utf_to_ascii
|
from infection_monkey.utils import utf_to_ascii
|
||||||
from common.utils.exploit_enum import ExploitType
|
|
||||||
from common.utils.attack_utils import ScanStatus, BITS_UPLOAD_STRING
|
|
||||||
|
|
||||||
__author__ = 'hoffer'
|
__author__ = 'hoffer'
|
||||||
|
|
||||||
|
@ -299,8 +299,8 @@ class RdpExploiter(HostExploiter):
|
||||||
for user, password in user_password_pairs:
|
for user, password in user_password_pairs:
|
||||||
try:
|
try:
|
||||||
# run command using rdp.
|
# run command using rdp.
|
||||||
LOG.info("Trying RDP logging into victim %r with user %s and password '%s'",
|
LOG.info("Trying RDP logging into victim %r with user %s and password (SHA-512) '%s'",
|
||||||
self.host, user, password)
|
self.host, user, self._config.hash_sensitive_data(password))
|
||||||
|
|
||||||
LOG.info("RDP connected to %r", self.host)
|
LOG.info("RDP connected to %r", self.host)
|
||||||
|
|
||||||
|
@ -327,8 +327,8 @@ class RdpExploiter(HostExploiter):
|
||||||
|
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
LOG.debug("Error logging into victim %r with user"
|
LOG.debug("Error logging into victim %r with user"
|
||||||
" %s and password '%s': (%s)", self.host,
|
" %s and password (SHA-512) '%s': (%s)", self.host,
|
||||||
user, password, exc)
|
user, self._config.hash_sensitive_data(password), exc)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
http_thread.join(DOWNLOAD_TIMEOUT)
|
http_thread.join(DOWNLOAD_TIMEOUT)
|
||||||
|
|
|
@ -68,8 +68,8 @@ class SmbExploiter(HostExploiter):
|
||||||
self._config.smb_download_timeout)
|
self._config.smb_download_timeout)
|
||||||
|
|
||||||
if remote_full_path is not None:
|
if remote_full_path is not None:
|
||||||
LOG.debug("Successfully logged in %r using SMB (%s : %s : %s : %s)",
|
LOG.debug("Successfully logged in %r using SMB (%s : (SHA-512) %s : %s : %s)",
|
||||||
self.host, user, password, lm_hash, ntlm_hash)
|
self.host, user, self._config.hash_sensitive_data(password), lm_hash, ntlm_hash)
|
||||||
self.report_login_attempt(True, user, password, lm_hash, ntlm_hash)
|
self.report_login_attempt(True, user, password, lm_hash, ntlm_hash)
|
||||||
self.add_vuln_port("%s or %s" % (SmbExploiter.KNOWN_PROTOCOLS['139/SMB'][1],
|
self.add_vuln_port("%s or %s" % (SmbExploiter.KNOWN_PROTOCOLS['139/SMB'][1],
|
||||||
SmbExploiter.KNOWN_PROTOCOLS['445/SMB'][1]))
|
SmbExploiter.KNOWN_PROTOCOLS['445/SMB'][1]))
|
||||||
|
@ -81,8 +81,8 @@ class SmbExploiter(HostExploiter):
|
||||||
|
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
LOG.debug("Exception when trying to copy file using SMB to %r with user:"
|
LOG.debug("Exception when trying to copy file using SMB to %r with user:"
|
||||||
" %s, password: '%s', LM hash: %s, NTLM hash: %s: (%s)", self.host,
|
" %s, password (SHA-512): '%s', LM hash: %s, NTLM hash: %s: (%s)", self.host,
|
||||||
user, password, lm_hash, ntlm_hash, exc)
|
user, self._config.hash_sensitive_data(password), lm_hash, ntlm_hash, exc)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if not exploited:
|
if not exploited:
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
|
import StringIO
|
||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import paramiko
|
import paramiko
|
||||||
import StringIO
|
|
||||||
|
|
||||||
import infection_monkey.monkeyfs as monkeyfs
|
import infection_monkey.monkeyfs as monkeyfs
|
||||||
|
from common.utils.exploit_enum import ExploitType
|
||||||
from infection_monkey.exploit import HostExploiter
|
from infection_monkey.exploit import HostExploiter
|
||||||
|
from infection_monkey.exploit.tools import build_monkey_commandline
|
||||||
from infection_monkey.exploit.tools import get_target_monkey, get_monkey_depth
|
from infection_monkey.exploit.tools import get_target_monkey, get_monkey_depth
|
||||||
from infection_monkey.model import MONKEY_ARG
|
from infection_monkey.model import MONKEY_ARG
|
||||||
from infection_monkey.network.tools import check_tcp_port
|
from infection_monkey.network.tools import check_tcp_port
|
||||||
from infection_monkey.exploit.tools import build_monkey_commandline
|
|
||||||
from common.utils.exploit_enum import ExploitType
|
|
||||||
|
|
||||||
__author__ = 'hoffer'
|
__author__ = 'hoffer'
|
||||||
|
|
||||||
|
@ -71,26 +71,26 @@ class SSHExploiter(HostExploiter):
|
||||||
|
|
||||||
exploited = False
|
exploited = False
|
||||||
|
|
||||||
for user, curpass in user_password_pairs:
|
for user, current_password in user_password_pairs:
|
||||||
try:
|
try:
|
||||||
ssh.connect(self.host.ip_addr,
|
ssh.connect(self.host.ip_addr,
|
||||||
username=user,
|
username=user,
|
||||||
password=curpass,
|
password=current_password,
|
||||||
port=port,
|
port=port,
|
||||||
timeout=None)
|
timeout=None)
|
||||||
|
|
||||||
LOG.debug("Successfully logged in %r using SSH (%s : %s)",
|
LOG.debug("Successfully logged in %r using SSH. User: %s, pass (SHA-512): %s)",
|
||||||
self.host, user, curpass)
|
self.host, user, self._config.hash_sensitive_data(current_password))
|
||||||
exploited = True
|
exploited = True
|
||||||
self.add_vuln_port(port)
|
self.add_vuln_port(port)
|
||||||
self.report_login_attempt(True, user, curpass)
|
self.report_login_attempt(True, user, current_password)
|
||||||
break
|
break
|
||||||
|
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
LOG.debug("Error logging into victim %r with user"
|
LOG.debug("Error logging into victim %r with user"
|
||||||
" %s and password '%s': (%s)", self.host,
|
" %s and password (SHA-512) '%s': (%s)", self.host,
|
||||||
user, curpass, exc)
|
user, self._config.hash_sensitive_data(current_password), exc)
|
||||||
self.report_login_attempt(False, user, curpass)
|
self.report_login_attempt(False, user, current_password)
|
||||||
continue
|
continue
|
||||||
return exploited
|
return exploited
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ class SSHExploiter(HostExploiter):
|
||||||
LOG.info("SSH port is closed on %r, skipping", self.host)
|
LOG.info("SSH port is closed on %r, skipping", self.host)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
#Check for possible ssh exploits
|
# Check for possible ssh exploits
|
||||||
exploited = self.exploit_with_ssh_keys(port, ssh)
|
exploited = self.exploit_with_ssh_keys(port, ssh)
|
||||||
if not exploited:
|
if not exploited:
|
||||||
exploited = self.exploit_with_login_creds(port, ssh)
|
exploited = self.exploit_with_login_creds(port, ssh)
|
||||||
|
|
|
@ -33,8 +33,10 @@ class WmiExploiter(HostExploiter):
|
||||||
creds = self._config.get_exploit_user_password_or_hash_product()
|
creds = self._config.get_exploit_user_password_or_hash_product()
|
||||||
|
|
||||||
for user, password, lm_hash, ntlm_hash in creds:
|
for user, password, lm_hash, ntlm_hash in creds:
|
||||||
LOG.debug("Attempting to connect %r using WMI with user,password,lm hash,ntlm hash: ('%s','%s','%s','%s')",
|
password_hashed = self._config.hash_sensitive_data(password)
|
||||||
self.host, user, password, lm_hash, ntlm_hash)
|
LOG.debug("Attempting to connect %r using WMI with "
|
||||||
|
"user,password (SHA-512),lm hash,ntlm hash: ('%s','%s','%s','%s')",
|
||||||
|
self.host, user, password_hashed, lm_hash, ntlm_hash)
|
||||||
|
|
||||||
wmi_connection = WmiTools.WmiConnection()
|
wmi_connection = WmiTools.WmiConnection()
|
||||||
|
|
||||||
|
@ -44,23 +46,23 @@ class WmiExploiter(HostExploiter):
|
||||||
self.report_login_attempt(False, user, password, lm_hash, ntlm_hash)
|
self.report_login_attempt(False, user, password, lm_hash, ntlm_hash)
|
||||||
LOG.debug("Failed connecting to %r using WMI with "
|
LOG.debug("Failed connecting to %r using WMI with "
|
||||||
"user,password,lm hash,ntlm hash: ('%s','%s','%s','%s')",
|
"user,password,lm hash,ntlm hash: ('%s','%s','%s','%s')",
|
||||||
self.host, user, password, lm_hash, ntlm_hash)
|
self.host, user, password_hashed, lm_hash, ntlm_hash)
|
||||||
continue
|
continue
|
||||||
except DCERPCException:
|
except DCERPCException:
|
||||||
self.report_login_attempt(False, user, password, lm_hash, ntlm_hash)
|
self.report_login_attempt(False, user, password, lm_hash, ntlm_hash)
|
||||||
LOG.debug("Failed connecting to %r using WMI with "
|
LOG.debug("Failed connecting to %r using WMI with "
|
||||||
"user,password,lm hash,ntlm hash: ('%s','%s','%s','%s')",
|
"user,password,lm hash,ntlm hash: ('%s','%s','%s','%s')",
|
||||||
self.host, user, password, lm_hash, ntlm_hash)
|
self.host, user, password_hashed, lm_hash, ntlm_hash)
|
||||||
continue
|
continue
|
||||||
except socket.error:
|
except socket.error:
|
||||||
LOG.debug("Network error in WMI connection to %r with "
|
LOG.debug("Network error in WMI connection to %r with "
|
||||||
"user,password,lm hash,ntlm hash: ('%s','%s','%s','%s')",
|
"user,password,lm hash,ntlm hash: ('%s','%s','%s','%s')",
|
||||||
self.host, user, password, lm_hash, ntlm_hash)
|
self.host, user, password_hashed, lm_hash, ntlm_hash)
|
||||||
return False
|
return False
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
LOG.debug("Unknown WMI connection error to %r with "
|
LOG.debug("Unknown WMI connection error to %r with "
|
||||||
"user,password,lm hash,ntlm hash: ('%s','%s','%s','%s') (%s):\n%s",
|
"user,password,lm hash,ntlm hash: ('%s','%s','%s','%s') (%s):\n%s",
|
||||||
self.host, user, password, lm_hash, ntlm_hash, exc, traceback.format_exc())
|
self.host, user, password_hashed, lm_hash, ntlm_hash, exc, traceback.format_exc())
|
||||||
return False
|
return False
|
||||||
|
|
||||||
self.report_login_attempt(True, user, password, lm_hash, ntlm_hash)
|
self.report_login_attempt(True, user, password, lm_hash, ntlm_hash)
|
||||||
|
@ -91,7 +93,8 @@ class WmiExploiter(HostExploiter):
|
||||||
# execute the remote dropper in case the path isn't final
|
# execute the remote dropper in case the path isn't final
|
||||||
elif remote_full_path.lower() != self._config.dropper_target_path_win_32.lower():
|
elif remote_full_path.lower() != self._config.dropper_target_path_win_32.lower():
|
||||||
cmdline = DROPPER_CMDLINE_WINDOWS % {'dropper_path': remote_full_path} + \
|
cmdline = DROPPER_CMDLINE_WINDOWS % {'dropper_path': remote_full_path} + \
|
||||||
build_monkey_commandline(self.host, get_monkey_depth() - 1, self._config.dropper_target_path_win_32)
|
build_monkey_commandline(
|
||||||
|
self.host, get_monkey_depth() - 1, self._config.dropper_target_path_win_32)
|
||||||
else:
|
else:
|
||||||
cmdline = MONKEY_CMDLINE_WINDOWS % {'monkey_path': remote_full_path} + \
|
cmdline = MONKEY_CMDLINE_WINDOWS % {'monkey_path': remote_full_path} + \
|
||||||
build_monkey_commandline(self.host, get_monkey_depth() - 1)
|
build_monkey_commandline(self.host, get_monkey_depth() - 1)
|
||||||
|
@ -118,3 +121,4 @@ class WmiExploiter(HostExploiter):
|
||||||
return success
|
return success
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
|
@ -68,7 +68,7 @@ def main():
|
||||||
else:
|
else:
|
||||||
print("Config file wasn't supplied and default path: %s wasn't found, using internal default" % (config_file,))
|
print("Config file wasn't supplied and default path: %s wasn't found, using internal default" % (config_file,))
|
||||||
|
|
||||||
print("Loaded Configuration: %r" % WormConfiguration.as_dict())
|
print("Loaded Configuration: %r" % WormConfiguration.hide_sensitive_info(WormConfiguration.as_dict()))
|
||||||
|
|
||||||
# Make sure we're not in a machine that has the kill file
|
# Make sure we're not in a machine that has the kill file
|
||||||
kill_path = os.path.expandvars(
|
kill_path = os.path.expandvars(
|
||||||
|
|
Loading…
Reference in New Issue