metasploit-framework/modules/post/windows/recon/outbound_ports.rb

197 lines
6.6 KiB
Ruby
Raw Normal View History

# -*- coding: binary -*-
##
2014-12-23 07:02:09 +00:00
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'rex'
2016-03-08 13:02:44 +00:00
class MetasploitModule < Msf::Post
include Msf::Post::Windows::Priv
def initialize(info={})
super( update_info( info,
2015-01-16 22:30:52 +00:00
'Name' => 'Windows Outbound-Filtering Rules',
2014-11-25 23:35:07 +00:00
'Description' => %q{
This module makes some kind of TCP traceroute to get outbound-filtering rules.
It will try to make a TCP connection to a certain public IP address (this IP
does not need to be under your control) using different TTL incremental values.
2014-12-31 17:45:14 +00:00
This way if you get an answer (ICMP TTL time exceeded packet) from a public IP
2014-11-25 23:35:07 +00:00
device you can infer that the destination port is allowed. Setting STOP to
true the module will stop as soon as you reach a public IP (this will generate
less noise in the network).
},
'License' => MSF_LICENSE,
2014-12-23 07:00:21 +00:00
'Author' => 'Borja Merino <bmerinofe[at]gmail.com>',
'Platform' => 'win',
'SessionTypes' => ['meterpreter'],
2014-11-25 23:35:07 +00:00
'References' => [
2014-12-23 07:00:21 +00:00
['URL', 'http://www.shelliscoming.com/2014/11/getting-outbound-filtering-rules-by.html']
]
2014-11-25 23:35:07 +00:00
))
register_options(
[
2014-12-23 07:00:21 +00:00
OptAddress.new('ADDRESS' , [ true, 'Destination IP address.']),
OptInt.new('HOPS', [true, 'Number of hops to get.', 3]),
OptInt.new('MIN_TTL', [true, 'Starting TTL value.', 1]),
OptString.new('PORTS', [true, 'Ports to test (e.g. 80,443,100-110).','80,443']),
OptInt.new('TIMEOUT', [true, 'Timeout for the ICMP socket.', 3]),
2014-12-15 15:26:39 +00:00
OptBool.new('STOP', [true, 'Stop when it finds a public IP.', true])
], self.class)
end
def icmp_setup
handler = client.railgun.ws2_32.socket("AF_INET", "SOCK_RAW", "IPPROTO_ICMP")
2014-12-23 07:00:21 +00:00
if handler['GetLastError'] == 0
vprint_status("ICMP raw socket created successfully")
else
print_error("There was an error setting the ICMP raw socket; GetLastError: #{handler['GetLastError']}")
return nil
end
2014-11-26 16:51:05 +00:00
r = client.railgun.ws2_32.bind(handler['return'],"\x02\x00\x00\x00" << Rex::Socket.addr_aton(session.session_host) << "\x00"*8 ,16)
2014-12-23 07:00:21 +00:00
if r['GetLastError'] == 0
vprint_status("ICMP socket successfully bound to #{session.session_host}")
else
print_error("There was an error binding the ICMP socket to #{session.session_host}; GetLastError: #{r['GetLastError']}")
return nil
end
# int WSAIoctl(
# _In_ SOCKET s,
# _In_ DWORD dwIoControlCode,
# _In_ LPVOID lpvInBuffer,
# _In_ DWORD cbInBuffer,
# _Out_ LPVOID lpvOutBuffer,
# _In_ DWORD cbOutBuffer,
# _Out_ LPDWORD lpcbBytesReturned,
# _In_ LPWSAOVERLAPPED lpOverlapped,
# _In_ LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
# );
sio_rcvall = 0x98000001
2014-12-23 07:00:21 +00:00
r = client.railgun.ws2_32.WSAIoctl(handler['return'], sio_rcvall, "\x01", 4, nil, 0 ,4, nil, nil)
if r['GetLastError'] == 0
return handler['return']
else
print_error("There was an error calling WSAIoctl (ICMP raw socket); GetLastError: #{r['GetLastError']}")
return nil
end
end
def tcp_setup(ttl)
2014-12-23 07:00:21 +00:00
handler = client.railgun.ws2_32.socket('AF_INET', 'SOCK_STREAM', 'IPPROTO_TCP')
if handler['GetLastError'] == 0
vprint_status('TCP socket created successfully')
else
print_error("There was an error setting the TCP socket; GetLastError: #{handler['GetLastError']}")
return nil
end
# 0x8004667E = FIONBIO
# Enable non-blocking mode when *argp (third parameter in ioctlsocket) is set to a nonzero value
2014-11-25 23:35:07 +00:00
cmd = 0x8004667E
r = client.railgun.ws2_32.ioctlsocket(handler['return'], cmd, 1)
2014-12-23 07:00:21 +00:00
if r['GetLastError'] == 0
vprint_status('TCP socket successfully configured in non-blocking mode')
else
print_error("There was an error setting the TCP socket in non-blocking mode; GetLastError: #{r['GetLastError']}")
return nil
end
# int setsockopt(
# _In_ SOCKET s,
# _In_ int level,
# _In_ int optname,
# _In_ const char *optval,
#_In_ int optlen
# );
2014-11-25 23:35:07 +00:00
ipproto_ip = 0
ip_ttl = 4
r = client.railgun.ws2_32.setsockopt(handler['return'], ipproto_ip, ip_ttl, [ttl].pack('C'), 4)
2014-12-23 07:00:21 +00:00
if r['GetLastError'] == 0
vprint_status("TTL value successfully set to #{ttl}")
return handler['return']
else
print_error("There was an error setting the TTL value; GetLastError: #{r['GetLastError']}")
return nil
end
end
2014-11-25 23:35:07 +00:00
def connections(remote, dst_port, h_icmp, h_tcp, to)
2014-12-23 07:00:21 +00:00
sock_addr = "\x02\x00"
sock_addr << [dst_port].pack('n')
sock_addr << Rex::Socket.addr_aton(remote)
sock_addr << "\x00" * 8
r = client.railgun.ws2_32.connect(h_tcp, sock_addr, 16)
2014-11-26 16:51:05 +00:00
# A GetLastError == 1035 is expected since the socket is set to non-blocking mode
2014-12-23 07:00:21 +00:00
unless r['GetLastError'] == 10035
print_error("There was an error creating the connection to the peer #{remote}; GetLastError: #{r['GetLastError']}")
return
end
2014-12-23 07:00:21 +00:00
from = ' ' * 16
begin
::Timeout.timeout(to) do
2014-12-14 17:58:48 +00:00
r = client.railgun.ws2_32.recvfrom(h_icmp, "\x00" * 100, 100, 0, from, 16)
hop = Rex::Socket.addr_ntoa(r['from'][4..7])
return hop
end
rescue ::Timeout::Error
return nil
end
end
def run
2014-11-25 23:35:07 +00:00
unless is_admin?
print_error("You don't have enough privileges. Try getsystem.")
return
end
2014-11-25 23:35:07 +00:00
if sysinfo['OS'] =~ /XP/
print_error('Windows XP is not supported')
return
end
2014-11-25 23:35:07 +00:00
output = cmd_exec('netsh',' advfirewall firewall add rule name="All ICMP v4" dir=in action=allow protocol=icmpv4:any,any')
print_status("ICMP firewall IN rule established: #{output}")
session.railgun.ws2_32
remote = datastore['ADDRESS']
to = datastore['TIMEOUT']
ports = Rex::Socket.portspec_crack(datastore['PORTS'])
ports.each do |dport|
2014-12-15 15:26:39 +00:00
pub_ip = false
print_status("Testing port #{dport}...")
2014-12-23 07:00:21 +00:00
0.upto(datastore['HOPS'] - 1) do |i|
i = i + datastore['MIN_TTL']
h_icmp = icmp_setup
2014-11-25 23:35:07 +00:00
return if h_icmp.nil?
h_tcp = tcp_setup(i)
2014-12-23 07:00:21 +00:00
return if h_tcp.nil?
hop = connections(remote, dport, h_icmp, h_tcp, to)
2014-12-23 07:00:21 +00:00
if hop.nil?
print_error("#{i} *")
else
print_good("#{i} #{hop}")
2014-12-23 07:00:21 +00:00
unless Rex::Socket.is_internal?(hop)
2014-12-15 15:26:39 +00:00
pub_ip = true
2014-12-23 07:00:21 +00:00
break if datastore['STOP']
end
end
client.railgun.ws2_32.closesocket(h_tcp)
client.railgun.ws2_32.closesocket(h_icmp)
2014-12-23 07:00:21 +00:00
end
print_good("Public IP reached. The TCP port #{dport} is not filtered") if pub_ip
end
end
end