Merge pull request #1865 from guardicore/1613-agent-timeouts

1613 agent timeouts
This commit is contained in:
Mike Salvatore 2022-04-06 11:39:54 -04:00 committed by GitHub
commit 252b314dc2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 62 additions and 33 deletions

View File

@ -87,7 +87,7 @@ class Configuration(object):
# Configuration servers to try to connect to, in this order. # Configuration servers to try to connect to, in this order.
command_servers = [] command_servers = []
keep_tunnel_open_time = 60 keep_tunnel_open_time = 30
########################### ###########################
# testing configuration # testing configuration

View File

@ -86,13 +86,15 @@ class SSHExploiter(HostExploiter):
self.exploit_result.exploitation_success = True self.exploit_result.exploitation_success = True
self.report_login_attempt(True, user, ssh_key=ssh_string) self.report_login_attempt(True, user, ssh_key=ssh_string)
return ssh return ssh
except Exception: except paramiko.AuthenticationException as err:
ssh.close() ssh.close()
logger.debug( logger.info(
"Error logging into victim %r with %s" " private key", self.host, ssh_string f"Failed logging into victim {self.host} with {ssh_string} private key: {err}",
) )
self.report_login_attempt(False, user, ssh_key=ssh_string) self.report_login_attempt(False, user, ssh_key=ssh_string)
continue continue
except Exception as err:
logger.error(f"Unknown error while attempting to login with ssh key: {err}")
raise FailedExploitationError raise FailedExploitationError
def exploit_with_login_creds(self, port) -> paramiko.SSHClient: def exploit_with_login_creds(self, port) -> paramiko.SSHClient:
@ -130,16 +132,18 @@ class SSHExploiter(HostExploiter):
self.report_login_attempt(True, user, current_password) self.report_login_attempt(True, user, current_password)
return ssh return ssh
except Exception as exc: except paramiko.AuthenticationException as err:
logger.debug( logger.debug(
"Error logging into victim %r with user" " %s: (%s)", "Failed logging into victim %r with user" " %s: (%s)",
self.host, self.host,
user, user,
exc, err,
) )
self.report_login_attempt(False, user, current_password) self.report_login_attempt(False, user, current_password)
ssh.close() ssh.close()
continue continue
except Exception as err:
logger.error(f"Unknown error occurred while trying to login to ssh: {err}")
raise FailedExploitationError raise FailedExploitationError
def _exploit_host(self) -> ExploiterResultData: def _exploit_host(self) -> ExploiterResultData:

View File

@ -343,6 +343,7 @@ class InfectionMonkey:
def cleanup(self): def cleanup(self):
logger.info("Monkey cleanup started") logger.info("Monkey cleanup started")
deleted = None
try: try:
if self._master: if self._master:
self._master.cleanup() self._master.cleanup()
@ -357,7 +358,7 @@ class InfectionMonkey:
firewall.remove_firewall_rule() firewall.remove_firewall_rule()
firewall.close() firewall.close()
InfectionMonkey._self_delete() deleted = InfectionMonkey._self_delete()
InfectionMonkey._send_log() InfectionMonkey._send_log()
@ -365,13 +366,12 @@ class InfectionMonkey:
is_done=True, version=get_version() is_done=True, version=get_version()
).send() # Signal the server (before closing the tunnel) ).send() # Signal the server (before closing the tunnel)
# TODO: Determine how long between when we
# send telemetry and the monkey actually exits
InfectionMonkey._close_tunnel() InfectionMonkey._close_tunnel()
self._singleton.unlock() self._singleton.unlock()
except Exception as e: except Exception as e:
logger.error(f"An error occurred while cleaning up the monkey agent: {e}") logger.error(f"An error occurred while cleaning up the monkey agent: {e}")
InfectionMonkey._self_delete() if deleted is None:
InfectionMonkey._self_delete()
logger.info("Monkey is shutting down") logger.info("Monkey is shutting down")
@ -400,9 +400,10 @@ class InfectionMonkey:
ControlClient.send_log(log) ControlClient.send_log(log)
@staticmethod @staticmethod
def _self_delete(): def _self_delete() -> bool:
status = ScanStatus.USED if remove_monkey_dir() else ScanStatus.SCANNED status = ScanStatus.USED if remove_monkey_dir() else ScanStatus.SCANNED
T1107Telem(status, get_monkey_dir_path()).send() T1107Telem(status, get_monkey_dir_path()).send()
deleted = False
if -1 == sys.executable.find("python"): if -1 == sys.executable.find("python"):
try: try:
@ -421,11 +422,14 @@ class InfectionMonkey:
close_fds=True, close_fds=True,
startupinfo=startupinfo, startupinfo=startupinfo,
) )
deleted = True
else: else:
os.remove(sys.executable) os.remove(sys.executable)
status = ScanStatus.USED status = ScanStatus.USED
deleted = True
except Exception as exc: except Exception as exc:
logger.error("Exception in self delete: %s", exc) logger.error("Exception in self delete: %s", exc)
status = ScanStatus.SCANNED status = ScanStatus.SCANNED
if status: if status:
T1107Telem(status, sys.executable).send() T1107Telem(status, sys.executable).send()
return deleted

View File

@ -1,18 +1,23 @@
import logging
import platform import platform
import subprocess import subprocess
import sys import sys
from common.common_consts.timeouts import SHORT_REQUEST_TIMEOUT
logger = logging.getLogger(__name__)
def _run_netsh_cmd(command, args): def _run_netsh_cmd(command, args):
cmd = subprocess.Popen( output = subprocess.check_output(
"netsh %s %s" "netsh %s %s"
% ( % (
command, command,
" ".join(['%s="%s"' % (key, value) for key, value in list(args.items()) if value]), " ".join(['%s="%s"' % (key, value) for key, value in list(args.items()) if value]),
), ),
stdout=subprocess.PIPE, timeout=SHORT_REQUEST_TIMEOUT,
) )
return cmd.stdout.read().strip().lower().endswith("ok.") return output.strip().lower().endswith(b"ok.")
class FirewallApp(object): class FirewallApp(object):
@ -44,19 +49,23 @@ class WinAdvFirewall(FirewallApp):
def is_enabled(self): def is_enabled(self):
try: try:
cmd = subprocess.Popen("netsh advfirewall show currentprofile", stdout=subprocess.PIPE) out = subprocess.check_output(
out = cmd.stdout.readlines() "netsh advfirewall show currentprofile", timeout=SHORT_REQUEST_TIMEOUT
)
for line in out: except subprocess.TimeoutExpired:
if line.startswith("State"): return None
state = line.split()[-1].strip()
return state == "ON"
except Exception: except Exception:
return None return None
for line in out.decode().splitlines():
if line.startswith("State"):
state = line.split()[-1].strip()
return state == "ON"
return None
def add_firewall_rule( def add_firewall_rule(
self, name="Firewall", direction="in", action="allow", program=sys.executable, **kwargs self, name="MonkeyRule", direction="in", action="allow", program=sys.executable, **kwargs
): ):
netsh_args = {"name": name, "dir": direction, "action": action, "program": program} netsh_args = {"name": name, "dir": direction, "action": action, "program": program}
netsh_args.update(kwargs) netsh_args.update(kwargs)
@ -66,8 +75,11 @@ class WinAdvFirewall(FirewallApp):
return True return True
else: else:
return False return False
except Exception: except subprocess.CalledProcessError as err:
return None logger.info(f"Failed adding a firewall rule: {err.stdout}")
except subprocess.TimeoutExpired:
logger.info("Timeout expired trying to add a firewall rule.")
return None
def remove_firewall_rule(self, name="Firewall", **kwargs): def remove_firewall_rule(self, name="Firewall", **kwargs):
netsh_args = {"name": name} netsh_args = {"name": name}

View File

@ -2,6 +2,7 @@ import time
from threading import Thread from threading import Thread
g_last_served = None g_last_served = None
PROXY_TIMEOUT = 2.5
class TransportProxyBase(Thread): class TransportProxyBase(Thread):

View File

@ -7,7 +7,11 @@ from logging import getLogger
from urllib.parse import urlsplit from urllib.parse import urlsplit
from infection_monkey.network.tools import get_interface_to_target from infection_monkey.network.tools import get_interface_to_target
from infection_monkey.transport.base import TransportProxyBase, update_last_serve_time from infection_monkey.transport.base import (
PROXY_TIMEOUT,
TransportProxyBase,
update_last_serve_time,
)
logger = getLogger(__name__) logger = getLogger(__name__)
@ -227,6 +231,6 @@ class LockedHTTPServer(threading.Thread):
class HTTPConnectProxy(TransportProxyBase): class HTTPConnectProxy(TransportProxyBase):
def run(self): def run(self):
httpd = http.server.HTTPServer((self.local_host, self.local_port), HTTPConnectProxyHandler) httpd = http.server.HTTPServer((self.local_host, self.local_port), HTTPConnectProxyHandler)
httpd.timeout = 10 httpd.timeout = PROXY_TIMEOUT
while not self._stopped: while not self._stopped:
httpd.handle_request() httpd.handle_request()

View File

@ -3,16 +3,20 @@ import socket
from logging import getLogger from logging import getLogger
from threading import Thread from threading import Thread
from infection_monkey.transport.base import TransportProxyBase, update_last_serve_time from infection_monkey.transport.base import (
PROXY_TIMEOUT,
TransportProxyBase,
update_last_serve_time,
)
READ_BUFFER_SIZE = 8192 READ_BUFFER_SIZE = 8192
DEFAULT_TIMEOUT = 10 SOCKET_READ_TIMEOUT = 10
logger = getLogger(__name__) logger = getLogger(__name__)
class SocketsPipe(Thread): class SocketsPipe(Thread):
def __init__(self, source, dest, timeout=DEFAULT_TIMEOUT): def __init__(self, source, dest, timeout=SOCKET_READ_TIMEOUT):
Thread.__init__(self) Thread.__init__(self)
self.source = source self.source = source
self.dest = dest self.dest = dest
@ -51,7 +55,7 @@ class TcpProxy(TransportProxyBase):
pipes = [] pipes = []
l_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) l_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
l_socket.bind((self.local_host, self.local_port)) l_socket.bind((self.local_host, self.local_port))
l_socket.settimeout(DEFAULT_TIMEOUT) l_socket.settimeout(PROXY_TIMEOUT)
l_socket.listen(5) l_socket.listen(5)
while not self._stopped: while not self._stopped:

View File

@ -9,7 +9,7 @@ INTERNAL = {
"keep_tunnel_open_time": { "keep_tunnel_open_time": {
"title": "Keep tunnel open time", "title": "Keep tunnel open time",
"type": "integer", "type": "integer",
"default": 60, "default": 30,
"description": "Time to keep tunnel open before going down after last exploit " "description": "Time to keep tunnel open before going down after last exploit "
"(in seconds)", "(in seconds)",
}, },