forked from p15670423/monkey
Agent: Wrap log4shell LDAP server in a process
A Twisted reactor can only be started and stopped once. It cannot be restarted after it has been stopped. To work around this, the reactor is configured and run in a separate process. This allows us to run multiple LDAP servers sequentially or simultaneously and stop each one when we're done with it.
This commit is contained in:
parent
aef7beedb3
commit
6b934d6de5
|
@ -1,3 +1,5 @@
|
||||||
|
import logging
|
||||||
|
import multiprocessing
|
||||||
import tempfile
|
import tempfile
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
@ -10,6 +12,8 @@ from twisted.internet.protocol import ServerFactory
|
||||||
from twisted.python import log
|
from twisted.python import log
|
||||||
from twisted.python.components import registerAdapter
|
from twisted.python.components import registerAdapter
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
EXPLOIT_RDN = "dn=Exploit"
|
EXPLOIT_RDN = "dn=Exploit"
|
||||||
|
|
||||||
|
|
||||||
|
@ -63,33 +67,50 @@ class LDAPExploitServer:
|
||||||
def __init__(
|
def __init__(
|
||||||
self, ldap_server_port: int, http_server_ip: str, http_server_port: int, storage_dir: Path
|
self, ldap_server_port: int, http_server_ip: str, http_server_port: int, storage_dir: Path
|
||||||
):
|
):
|
||||||
LDAPExploitServer.output_twisted_logs_to_python_logger()
|
self._ldap_server_port = ldap_server_port
|
||||||
|
self._http_server_ip = http_server_ip
|
||||||
|
self._http_server_port = http_server_port
|
||||||
|
self._storage_dir = storage_dir
|
||||||
|
|
||||||
|
# A Twisted reactor can only be started and stopped once. It cannot be restarted after it
|
||||||
|
# has been stopped. To work around this, the reactor is configured and run in a separate
|
||||||
|
# process. This allows us to run multiple LDAP servers sequentially or simultaneously and
|
||||||
|
# stop each one when we're done with it.
|
||||||
|
self._server_process = multiprocessing.Process(
|
||||||
|
target=self._run_twisted_reactor, daemon=True
|
||||||
|
)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
self._server_process.start()
|
||||||
|
self._server_process.join()
|
||||||
|
|
||||||
|
def _run_twisted_reactor(self):
|
||||||
|
self._configure_twisted_reactor()
|
||||||
|
logger.debug(f"Starting log4shell LDAP server on port {self._ldap_server_port}")
|
||||||
|
reactor.run()
|
||||||
|
|
||||||
|
def _configure_twisted_reactor(self):
|
||||||
|
LDAPExploitServer._output_twisted_logs_to_python_logger()
|
||||||
|
|
||||||
registerAdapter(lambda x: x.root, LDAPServerFactory, IConnectedLDAPEntry)
|
registerAdapter(lambda x: x.root, LDAPServerFactory, IConnectedLDAPEntry)
|
||||||
|
|
||||||
tree = Tree(http_server_ip, http_server_port, storage_dir)
|
tree = Tree(self._http_server_ip, self._http_server_port, self._storage_dir)
|
||||||
factory = LDAPServerFactory(tree.db)
|
factory = LDAPServerFactory(tree.db)
|
||||||
factory.debug = True
|
factory.debug = True
|
||||||
|
|
||||||
application = service.Application("ldaptor-server")
|
application = service.Application("ldaptor-server")
|
||||||
service.IServiceCollection(application)
|
service.IServiceCollection(application)
|
||||||
reactor.listenTCP(ldap_server_port, factory)
|
reactor.listenTCP(self._ldap_server_port, factory)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def output_twisted_logs_to_python_logger():
|
def _output_twisted_logs_to_python_logger():
|
||||||
# Configures Twisted to output its logs using the standard python logging module instead of
|
# Configures Twisted to output its logs using the standard python logging module instead of
|
||||||
# the Twisted logging module.
|
# the Twisted logging module.
|
||||||
# https://twistedmatrix.com/documents/current/api/twisted.python.log.PythonLoggingObserver.html
|
# https://twistedmatrix.com/documents/current/api/twisted.python.log.PythonLoggingObserver.html
|
||||||
log_observer = log.PythonLoggingObserver()
|
log_observer = log.PythonLoggingObserver()
|
||||||
log_observer.start()
|
log_observer.start()
|
||||||
|
|
||||||
def run(self):
|
|
||||||
# For an explaination of installSignalHandlers=0, see
|
|
||||||
# https://twistedmatrix.com/trac/wiki/FrequentlyAskedQuestions#Igetexceptions.ValueError:signalonlyworksinmainthreadwhenItrytorunmyTwistedprogramWhatswrong
|
|
||||||
reactor.run(installSignalHandlers=0)
|
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
# Since `reactor.run()` may not be running on the main thread, reactor.stop() must be
|
# The Twisted reactor registers signal handlers so it can catch SIGTERM and gracefully
|
||||||
# invoked with reactor.callFromThread()
|
# shutdown.
|
||||||
# https://twistedmatrix.com/documents/12.2.0/core/howto/threading.html
|
self._server_process.terminate()
|
||||||
reactor.callFromThread(reactor.stop)
|
|
||||||
|
|
Loading…
Reference in New Issue