Skip to content

Instantly share code, notes, and snippets.

@jhart-r7
Created August 3, 2016 00:39
Show Gist options
  • Save jhart-r7/79b5c4cd82795bcfede2532c8de9bf74 to your computer and use it in GitHub Desktop.
Save jhart-r7/79b5c4cd82795bcfede2532c8de9bf74 to your computer and use it in GitHub Desktop.
[ jhart@jhart-laptop (08/02/16 17:37:52) ~/rapid7/metasploit-framework/modules/auxiliary/scanner/netbios ]
$ diff nbname.rb nbname_probe.rb -uN
--- nbname.rb 2016-05-16 17:27:36.000000000 -0700
+++ nbname_probe.rb 2016-08-02 17:31:57.000000000 -0700
@@ -10,70 +10,125 @@
class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Report
- include Msf::Auxiliary::UDPScanner
+ include Msf::Auxiliary::Scanner
+ include Msf::Module::Deprecated
+
+ deprecated(Date.new(2016, 9, 1), 'auxiliary/scanner/netbios/nbname')
def initialize
super(
- 'Name' => 'NetBIOS Information Discovery',
- 'Description' => 'Discover host information through NetBIOS',
- 'Author' => 'hdm',
+ 'Name' => 'NetBIOS Information Discovery Prober',
+ 'Description' => 'Discover host information using sequential NetBIOS Probes',
+ 'Author' => ['hdm', 'todb'],
'License' => MSF_LICENSE
)
register_options(
[
+ Opt::CHOST,
Opt::RPORT(137)
], self.class)
end
- def scanner_prescan(batch)
- print_status("Sending NetBIOS requests to #{batch[0]}->#{batch[-1]} (#{batch.length} hosts)")
- @results = {}
+ def rport
+ datastore['RPORT'].to_i
end
- def scan_host(ip)
- scanner_send(create_netbios_status(ip), ip, datastore['RPORT'])
- end
+ # Fingerprint a single host
+ def run_host(ip)
- def scanner_postscan(batch)
+ @thost = ip
- cnt = 0
+ @results = {}
+ begin
+ udp_sock = nil
- # Perform a second pass based on responsive hosts
- @results.keys.each do |ip|
- next if not @results[ip][:name]
- scanner_send(create_netbios_lookup(@results[ip][:name]), ip, datastore['RPORT'])
- cnt += 1
- end
+ # Create an unbound UDP socket if no CHOST is specified, otherwise
+ # create a UDP socket bound to CHOST (in order to avail of pivoting)
+ udp_sock = Rex::Socket::Udp.create( {
+ 'LocalHost' => datastore['CHOST'] || nil,
+ 'PeerHost' => ip, 'PeerPort' => rport,
+ 'Context' => {'Msf' => framework, 'MsfExploit' => self}
+ })
+ add_socket(udp_sock)
+
+ begin
+ data = create_netbios_status(ip)
+ udp_sock.put(data)
+ rescue ::Interrupt
+ raise $!
+ rescue ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Rex::ConnectionRefused
+ nil
+ end
- # Wait for the final replies to trickle in
- scanner_recv(10) if cnt > 0
+ while (r = udp_sock.recvfrom(65535, 0.1) and r[1])
+ parse_reply(r)
+ end
- @results.keys.each do |ip|
+ while (r = udp_sock.recvfrom(65535, 3) and r[1])
+ parse_reply(r)
+ end
+
+ # Second pass to find additional IPs per host name
+
+ @results.keys.each do |ip|
+ next if not @results[ip][:name]
+ begin
+ data = create_netbios_lookup(@results[ip][:name])
+ udp_sock.put(data)
+ rescue ::Interrupt
+ raise $!
+ rescue ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Rex::ConnectionRefused
+ nil
+ end
+
+ while (r = udp_sock.recvfrom(65535, 0.1) and r[1])
+ parse_reply(r)
+ end
+
+ end
+
+ while (r = udp_sock.recvfrom(65535, 3) and r[1])
+ parse_reply(r)
+ end
+
+ rescue ::Interrupt
+ raise $!
+ rescue ::Errno::ENOBUFS
+ print_status("Socket buffers are full, waiting for them to flush...")
+ while (r = udp_sock.recvfrom(65535, 0.1) and r[1])
+ parse_reply(r)
+ end
+ select(nil, nil, nil, 0.25)
+ rescue ::Exception => e
+ print_error("Unknown error: #{e.class} #{e}")
+ end
+ @results.keys.each do |ip|
+ next unless inside_workspace_boundary?(ip)
host = @results[ip]
user = ""
os = "Windows"
- if (host[:user] and host[:mac] != "00:00:00:00:00:00")
+ if(host[:user] and host[:mac] != "00:00:00:00:00:00")
user = " User:#{host[:user]}"
end
- if (host[:mac] == "00:00:00:00:00:00")
+ if(host[:mac] == "00:00:00:00:00:00")
os = "Unix"
end
names = ""
- if (host[:names])
+ if host[:names]
names = " Names:(" + host[:names].map{|n| n[0]}.uniq.join(", ") + ")"
end
addrs = ""
- if (host[:addrs])
+ if(host[:addrs])
addrs = "Addresses:(" + host[:addrs].map{|n| n[0]}.uniq.join(", ") + ")"
end
- if (host[:mac] != "00:00:00:00:00:00")
+ if(host[:mac] != "00:00:00:00:00:00")
report_host(:host => ip, :mac => host[:mac])
else
report_host(:host => ip)
@@ -101,7 +156,7 @@
virtual = 'Virtual Computer Inc'
end
- if (virtual)
+ if(virtual)
extra = "Virtual Machine:#{virtual}"
report_note(
:host => ip,
@@ -110,7 +165,7 @@
)
end
- if (host[:addrs])
+ if(host[:addrs])
aliases = []
host[:addrs].map{|n| n[0]}.uniq.each do |addr|
next if addr == ip
@@ -133,7 +188,16 @@
end
- def scanner_process(data, shost, sport)
+ def parse_reply(pkt)
+ # Ignore "empty" packets
+ return if not pkt[1]
+
+ addr = pkt[1]
+ if(addr =~ /^::ffff:/)
+ addr = addr.sub(/^::ffff:/, '')
+ end
+
+ data = pkt[0]
head = data.slice!(0,12)
@@ -151,8 +215,6 @@
hname = nil
uname = nil
- @results[shost] ||= {}
-
case rtype
when 0x21
rcnt = buff.slice!(0,1).unpack("C")[0]
@@ -166,15 +228,17 @@
end
maddr = buff.slice!(0,6).unpack("C*").map{|c| "%.2x" % c }.join(":")
- @results[shost][:names] = names
- @results[shost][:mac] = maddr
+ @results[addr] = {
+ :names => names,
+ :mac => maddr
+ }
- if (!hname and @results[shost][:names].length > 0)
- @results[shost][:name] = @results[shost][:names][0][0]
+ if (!hname and @results[addr][:names].length > 0)
+ @results[addr][:name] = @results[addr][:names][0][0]
end
- @results[shost][:name] = hname if hname
- @results[shost][:user] = uname if uname
+ @results[addr][:name] = hname if hname
+ @results[addr][:user] = uname if uname
inf = ''
names.each do |name|
@@ -188,23 +252,24 @@
end
inf << maddr
- report_service(
- :host => shost,
- :mac => (maddr and maddr != '00:00:00:00:00:00') ? maddr : nil,
- :host_name => (hname) ? hname.downcase : nil,
- :port => datastore['RPORT'],
- :proto => 'udp',
- :name => 'netbios',
- :info => inf
- )
-
+ if inside_workspace_boundary?(addr)
+ report_service(
+ :host => addr,
+ :mac => (maddr and maddr != '00:00:00:00:00:00') ? maddr : nil,
+ :host_name => (hname) ? hname.downcase : nil,
+ :port => pkt[2],
+ :proto => 'udp',
+ :name => 'netbios',
+ :info => inf
+ )
+ end
when 0x20
1.upto(rlen / 6.0) do
tflag = buff.slice!(0,2).unpack('n')[0]
taddr = buff.slice!(0,4).unpack("C*").join(".")
names << [ taddr, tflag ]
end
- @results[shost][:addrs] = names
+ @results[addr][:addrs] = names
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment