Merge branch '2269-publish-events-from-log4shell-exploiter' into develop

PR #2397
This commit is contained in:
Mike Salvatore 2022-10-06 17:26:06 -04:00
commit 77d37bdb21
2 changed files with 50 additions and 14 deletions

View File

@ -4,6 +4,11 @@ from pathlib import PurePath
from common import OperatingSystem from common import OperatingSystem
from common.common_consts.timeouts import LONG_REQUEST_TIMEOUT, MEDIUM_REQUEST_TIMEOUT from common.common_consts.timeouts import LONG_REQUEST_TIMEOUT, MEDIUM_REQUEST_TIMEOUT
from common.tags import (
T1105_ATTACK_TECHNIQUE_TAG,
T1110_ATTACK_TECHNIQUE_TAG,
T1203_ATTACK_TECHNIQUE_TAG,
)
from common.utils import Timer from common.utils import Timer
from infection_monkey.exploit.log4shell_utils import ( from infection_monkey.exploit.log4shell_utils import (
LINUX_EXPLOIT_TEMPLATE_PATH, LINUX_EXPLOIT_TEMPLATE_PATH,
@ -26,12 +31,26 @@ from infection_monkey.utils.threading import interruptible_iter
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
LOG4SHELL_EXPLOITER_TAG = "log4shell-exploiter"
VICTIM_WAIT_SLEEP_TIME_SEC = 0.050
class Log4ShellExploiter(WebRCE): class Log4ShellExploiter(WebRCE):
_EXPLOITED_SERVICE = "Log4j" _EXPLOITED_SERVICE = "Log4j"
SERVER_SHUTDOWN_TIMEOUT = LONG_REQUEST_TIMEOUT SERVER_SHUTDOWN_TIMEOUT = LONG_REQUEST_TIMEOUT
REQUEST_TO_VICTIM_TIMEOUT = MEDIUM_REQUEST_TIMEOUT REQUEST_TO_VICTIM_TIMEOUT = MEDIUM_REQUEST_TIMEOUT
_EXPLOITER_TAGS = (
LOG4SHELL_EXPLOITER_TAG,
T1110_ATTACK_TECHNIQUE_TAG,
T1203_ATTACK_TECHNIQUE_TAG,
)
_PROPAGATION_TAGS = (
LOG4SHELL_EXPLOITER_TAG,
T1203_ATTACK_TECHNIQUE_TAG,
T1105_ATTACK_TECHNIQUE_TAG,
)
def _exploit_host(self) -> ExploiterResultData: def _exploit_host(self) -> ExploiterResultData:
self._open_ports = [ self._open_ports = [
int(port[0]) for port in WebRCE.get_open_service_ports(self.host, self.HTTP, ["http"]) int(port[0]) for port in WebRCE.get_open_service_ports(self.host, self.HTTP, ["http"])
@ -146,24 +165,37 @@ class Log4ShellExploiter(WebRCE):
f"on port {port}" f"on port {port}"
) )
try: try:
timestamp = time.time()
url = exploit.trigger_exploit(self._build_ldap_payload(), self.host, port) url = exploit.trigger_exploit(self._build_ldap_payload(), self.host, port)
except Exception as ex: except Exception as err:
logger.warning( error_message = (
"An error occurred while attempting to exploit log4shell on a " "An error occurred while attempting to exploit log4shell on a "
f"potential {exploit.service_name} service: {ex}" f"potential {exploit.service_name} service: {err}"
) )
if self._wait_for_victim(): logger.warning(error_message)
self._publish_exploitation_event(timestamp, False, error_message=error_message)
# TODO: _wait_for_victim() gets called even if trigger_exploit() raises an
# exception. Is that the desired behavior?
if self._wait_for_victim(timestamp):
self.exploit_info["vulnerable_service"] = { self.exploit_info["vulnerable_service"] = {
"service_name": exploit.service_name, "service_name": exploit.service_name,
"port": port, "port": port,
} }
self.exploit_info["vulnerable_urls"].append(url) self.exploit_info["vulnerable_urls"].append(url)
def _wait_for_victim(self) -> bool: def _wait_for_victim(self, timestamp: float) -> bool:
victim_called_back = self._wait_for_victim_to_download_java_bytecode() victim_called_back = self._wait_for_victim_to_download_java_bytecode()
if victim_called_back: if victim_called_back:
self._wait_for_victim_to_download_agent() self._publish_exploitation_event(timestamp, True)
victim_downloaded_agent = self._wait_for_victim_to_download_agent()
self._publish_propagation_event(success=victim_downloaded_agent)
else:
error_message = "Timed out while waiting for victim to download the java bytecode"
logger.debug(error_message)
self._publish_exploitation_event(timestamp, False, error_message=error_message)
return victim_called_back return victim_called_back
@ -176,19 +208,20 @@ class Log4ShellExploiter(WebRCE):
self.exploit_result.exploitation_success = True self.exploit_result.exploitation_success = True
return True return True
time.sleep(1) time.sleep(VICTIM_WAIT_SLEEP_TIME_SEC)
logger.debug("Timed out while waiting for victim to download the java bytecode")
return False return False
def _wait_for_victim_to_download_agent(self): def _wait_for_victim_to_download_agent(self) -> bool:
timer = Timer() timer = Timer()
timer.set(LONG_REQUEST_TIMEOUT) timer.set(LONG_REQUEST_TIMEOUT)
while not timer.is_expired(): while not timer.is_expired():
if self._agent_http_server_thread.downloads > 0: if self._agent_http_server_thread.downloads > 0:
self.exploit_result.propagation_success = True self.exploit_result.propagation_success = True
break return True
# TODO: if the http server got an error we're waiting for nothing here # TODO: if the http server got an error we're waiting for nothing here
time.sleep(1) time.sleep(VICTIM_WAIT_SLEEP_TIME_SEC)
return False

View File

@ -1,4 +1,5 @@
from typing import List, Optional from pathlib import PurePath
from typing import List, Optional, Union
from infection_monkey.config import GUID from infection_monkey.config import GUID
from infection_monkey.exploit.tools.helpers import AGENT_BINARY_PATH_LINUX, AGENT_BINARY_PATH_WIN64 from infection_monkey.exploit.tools.helpers import AGENT_BINARY_PATH_LINUX, AGENT_BINARY_PATH_WIN64
@ -9,7 +10,9 @@ DROPPER_TARGET_PATH_LINUX = AGENT_BINARY_PATH_LINUX
DROPPER_TARGET_PATH_WIN64 = AGENT_BINARY_PATH_WIN64 DROPPER_TARGET_PATH_WIN64 = AGENT_BINARY_PATH_WIN64
def build_monkey_commandline(servers: List[str], depth: int, location: Optional[str] = None) -> str: def build_monkey_commandline(
servers: List[str], depth: int, location: Union[str, PurePath, None] = None
) -> str:
return " " + " ".join( return " " + " ".join(
build_monkey_commandline_explicitly( build_monkey_commandline_explicitly(
@ -25,7 +28,7 @@ def build_monkey_commandline_explicitly(
parent: Optional[str] = None, parent: Optional[str] = None,
servers: Optional[List[str]] = None, servers: Optional[List[str]] = None,
depth: Optional[int] = None, depth: Optional[int] = None,
location: Optional[str] = None, location: Union[str, PurePath, None] = None,
) -> List[str]: ) -> List[str]:
cmdline = [] cmdline = []