nbtscan - NETBIOS nameserver scanner

Does this site look plain?

This site uses advanced css techniques

NOTE: The Windows version of this tool MUST run in an MS-DOS window!

Table of Contents

This is a command-line tool that scans for open NETBIOS nameservers on a local or remote TCP/IP network, and this is a first step in finding of open shares. It is based on the functionality of the standard Windows tool nbtstat, but it operates on a range of addresses instead of just one. I wrote this tool because the existing tools either didn't do what I wanted or ran only on the Windows platforms: mine runs on just about everything.


Download

Windows - The Win32 version of the tool, which works well on Windows 9x, NT and 2000, is available below as nbtscan.exe. It's written in portable C and is less than 40 kbytes, requires no special libraries or DLLs, and is run in an MS-DOS command window. I promise that the tools have no viruses, backdoors, or any other kind of overt bad behavior. I don't promise that there are no bugs.

LINUX - the code works fine on Linux, and a version built on Red Hat Linux 6.2 is available as well. I have reports that this binary works on Red Hat Linux 6.0 - 8.0, Debian "woody", and Mandrake 8.1 (we don't think we've found a Red Hat, CentOS, or Fedora system that it didn't run on).

Note: the source compiles under *ix and Windows, but the Windows tools require the command-line compilers, not Visual Studio.

Background

NETBIOS is commonly known as the Windows "Network Neighborhood" protocol, and (among other things), it provides a nameservice that listens on UDP port 137. When it receives a query on this port, it responds with a list of all services it offers. Windows ships with a standard tool nbtstat which queries a single IP address when given the -A parameter. When run against a machine on the local network (a development box), it shows:

C:\> nbtstat -A 192.168.1.99
       NetBIOS Remote Machine Name Table

   Name               Type         Status
---------------------------------------------
XPDEV          <00>  UNIQUE      Registered
UNIXWIX        <00>  GROUP       Registered
XPDEV          <03>  UNIQUE      Registered
XPDEV          <20>  UNIQUE      Registered
UNIXWIX        <1E>  GROUP       Registered

MAC Address = 00-50-04-6D-50-37

The numeric code (in hexadecimal) and the type serve to identify the service being offered, and (for instance) a UNIQUE code of <20> indicates that the machine is running the file-sharing service. Unfortunately, nbtstat only reports the codes, and it requires looking up the meanings elsewhere. The References section at the end of this document lists some resources to learn what all the codes mean.

Machines participating in NETBIOS listen on UDP port 137 for these queries and respond accordingly. Simple configurations might only have a few resource records (as above), but an NT server supporting a large enterprise could easily have more than a dozen. Though it's sometimes useful to examine the full set of resource records for a given machine, in practice it's more useful to summarize them into the key "interesting" services.

Our tool has taken this approach. Not only does it scan ranges of addresses -- instead of just one machine -- but it can fully decode most of the resource record types and can summarize the interesting data on a one-line display.

On our network we have quite a few machines, but it appears that only three respond to our queries:

C:\> nbtscan 192.168.1.0/24
192.168.1.3     MTNDEW\WINDEV               SHARING DC
192.168.1.5     MTNDEW\TESTING
192.168.1.9     MTNDEW\WIZ                  SHARING U=STEVE
192.168.1.99    MTNDEW\XPDEV                SHARING

The first column is the IP address, then the NT domain and machine name, followed by the list of "interesting" services about each one. In many cases, the summary information is based on guesses, observations, and highly incomplete information, and we invite submissions by others who can help us pinpoint more entries like this.

Token Meaning
SHARING The machine in question is running the file and print sharing service, but this does not necessarily mean any shares are published or that we'll be able to see any of them. Actual enumeration of the shares is done via a different mechanism outside the scope of this program.
DC This machine appears to be a Windows NT domain controller, either primary or secondary.
U=user This machine appears to have a logged-in user with the name indicated. This is often only a guess, and it's common for our algorithms to miss a valid user (especially if the user name is the same as the machine name).
IIS This machine appears to have Microsoft's Internet Information Server (IIS) installed, though we believe that there are related tools that can cause this to appear as well. It doesn't necessarily mean that IIS is actually running.
EXCHANGE This machine appears to be running Microsoft Exchange.
NOTES This machine appears to be running Lotus Notes
? This means that the remote is advertising a NETBIOS resource record that we don't understand, and it can prompt us to run the scan again with the -f option and research it: we hope to use this feedback to make the program smarter in the future.

Specifying Target Ranges

We try very hard to make it easy to describe the list of machines that are to be scanned, and our "add_target" library function is used by most of our scanning tools. Accordingly, this explanatory text will be shared as well.

In the simplest form, one or more IP addresses or host names can be listed individually, and each will be tried in turn. It's a fatal error if any IP address is malformed or if a domain name is not resolvable, but it's allowed (and pointless) to mention the same address more than once.

$ nbtscan 192.168.1.4 10.4.2.3 www.yahoo.com

To scan an entire range of address, it's much easier to specify the netmask in /nbits notation rather than list dozens or hundreds of hosts. The number after the slash gives the number of bits (out of 32) are the "network" part, the reset being "host". For instance, 192.168.7.0/24 is a full class C from 192.168.7.0 to 192.168.7.255. Traditionally, the slash notation has requird that the "base" address be at the start of the given range, but our tool determines this automatically, so any address will do.

This is a summary of all /nbits notations for 16-30. The values /31 or /32 don't specify valid netmasks, and /1 to /15 cover so much ground that we don't recommend scanning them. Please see Netmask Reference.

When scanning a remote network with the slash notation, the tool excludes the first and last address of the range that would otherwise be implied by the netmask. This is because the first and last addresses are usually reserved for broadcast to the local network segment. For instance, when considering 10.1.1.0/24, the addresses 10.1.1.0 and 10.1.1.255 are not included.

However, this is only useful if the netmask chosen matches the netmask used by the other end. If it doesn't match, the two excluded addresses could very match an address being checked. For instance, trying to scan 10.1.1.32/29 would run from 10.1.1.33 to 10.1.1.38, which corresponds to the /29 network of 8 address (less two used by broadcast). But if the remote network is not a /29 but is (say), a /24, then the dot-32 address could very well be a valid one and would be ignored.

To remedy this case, the double-slash notation of //nbits can be used to include every address within the range, including the purported broadcast addresses, and this should be used when the remote netmask is not known. Example: 10.1.1.32//29 or www.unixwiz.net//27.

In addition to the /nbits notation, targets can be specified with a "range" notation in the last octet. This can be used to specify a range that doesn't correspond to standard subnet, and an example is 10.1.1.17-93. The range notation is incompatible with the /nbits notation and cannot be used with a hostname.

Command Line Parameters

When nbtscan is run without command-line arguments, it reports a short "help" listing that summarizes the options available, which are expanded on here.

--version
-V
This simply shows the current version information, and I try to keep it updated on each rebuild. Version history is below.
-f
This shows the full NBT resource record responses for each machine scanned, not just the one-line summary. This is recommended when studying one single machine, but it's much less useful when scanning a larger range.
-O outfile
Send results to outfile rather than to the standard output.
-H
Generate an HTTP header. During penetration testing, sometimes we are able to install the nbtscan.exe program on a remote IIS web server and run it with the "Unicode" exploit, but since the output is "regular" text, the output gets confused by the web server that thinks it's a broken CGI script. The -H option addes a simple Content-type: text/plain header with a blank line that makes the output show up correctly.
-P
Generate Perl hashref output, which can be loaded into an existing program for easier processing. This is much easier than parsing text output.
-v
This turns on some more verbose debugging, but this is really only meant for the developer's use and probably won't help an end-user that much. The code considered "verbose" changes from release to release as bugs are tracked down, and we make no effort to make this useful in the general case.
-n
In a few reporting modes, the IP address of the remote machine is used as a key to look up the "inverse" name. This is normally helpful, but many nameservers are misconfigured in a way that make this appear to "hang", so -n turns off this inverse name lookup.
-p port
This allows specification of a UDP port number to be used as the source in sending a query. Normally the program picks a random ephemeral port number, and this is entirely sufficient in most cases.
But some Windows 95 machines send their responses to port 137 no matter where the query came from (we consider this a bug), so using -p 137 will force nbtscan to bind to this port instead of the random one. In addition, some older versions of the ZoneAlarm personal firewall would incorrectly allow NETBIOS queries if the source port is 53 (DNS).
But note that you can't bind to a port that already is in use, and on Windows this usually means that port 137 is unavailable to you.
-m
Include the MAC (aka "Ethernet") addresses in the response, which is already implied by the -f option.
-T secs
When scanning a large range of addresses, it's not always clear when we are "finished". If we send out (say) five queries, we're clearly done when we get five responses, but if any machine does not respond, we have to rely on timeouts. The -T option controls how long we'll wait for any response, and the default is 2 seconds.
-w msecs
Unless the local network is being scanned, we cannot typically blast many queries lest packets be lost on the way. We normally pause for a short time after each network write operation to allow things to clear out before sending another, and this allows the "tuning" of that time. It is specified in milliseconds, and the default is 10 milliseconds.
-t tries
Try each address up to tries times, which is useful when dealing with a remote network that is (somehow) dropping packets. Once a given machine has responded, it won't be queried again. Default = 1.
-n
Don't look up inverse DNS names in the full listing (show IP addresses).
-1
Force the use of Winsock version 1 (Windows only) rather than the default which is usually version 2.

Firewall Issues

You might run into some problems if you're using a packet-filtering router. UDP has no concept of an "established" connection, and you probably don't wish to allow all inbound UDP traffic to hit your workstation. So, we have made some limited provisions for this. If you're running a "real" firewall that is either stateful or uses NAT (Network Address Transslation), this section won't apply to you.

When an outgoing UDP probe is made, the source port number is generally hardcoded to a fixed value (usually "1234"), so the returning packets will be directed to this port and can be recognized by a filter.

Assuming that your workstation is 192.168.1.1, the Cisco access-list rule would be:

access-list n permit udp   any eq 137   host 192.168.1.1 eq 1234

This permits all the returning packets without allowing too much bad stuff, and we've used this rule for a long time. Note that you have to replace n with the access list associated with the proper inbound filter.

Note that some older Windows clients will respond to port 137 even if the source port is something else, and these will be blocked at the firewall. If you're running nbtscan on a Windows machine, the program will never bind to this port anyway, so it's just as well that the firewall blocks it.

Update: starting with version 1.0.27, the source port is now an ephemeral ("random, non-privileged") port, mainly because my dumb packet filtering router has been out of the picture for more than a year. The additional side effect of this change is that I can be running two independent scans on the same machine.

References

Version history

This is a simple mirror of the revision log in our development environment, but it might lag a bit behind the version of the executable actually found on the web.

Tue Apr  8 16:24:16 PDT 2008 -- version 1.0.35
- added ZIP-file maker option (makefile only)

Tue Apr  8 16:06:13 PDT 2008 -- version 1.0.34
- for -P mode, now quote all the 'name' => value tags (for Ruby)

Fri Mar 16 12:21:41 PST 2007 -- version 1.0.33
- recompiled with MSVC6

Tue Aug 30 07:28:01 PDT 2005 -- version 1.0.32
- minor cleanups: disabled non-working CIFS and other unused commands

Thu Oct  2 10:30:49 PDT 2003 -- version 1.0.31
- replaced email address in version string with web URL

Mon May 27 13:20:18 PDT 2002 -- version 1.0.29
- properly look up hostnames that contain a dash

Mon Mar 11 21:18:50 PST 2002 -- version 1.0.28
- now report Dr. Solomon AV Management NETBIOS names

Sun Mar 10 12:13:58 PST 2002 -- version 1.0.27
- now by default bind to random UDP port number

Sun Mar 10 10:01:25 PST 2002 -- version 1.0.26
- on summary line, write "?" if we don't recognize a NETBIOS resource
  type. Will give us a clue that we ought to investigate.

Fri Mar  8 13:21:35 PST 2002 -- version 1.0.25
- enabled "-P" for perl hashref generation

Thu Mar  7 12:42:23 PST 2002 -- version 1.0.24
- expanded display of "-v -v" packet dumps a bit

Sat Apr 21 09:37:38 PDT 2001 -- version 1.0.23
- added default values to the help message

Mon Feb 12 15:40:16 PST 2001 -- version 1.0.22
- recompiled with library that does no DNS lookups if /## is present

Fri Jan 12 18:25:21 PST 2001 -- version 1.0.21
- fixed problem with types > 0x7F

Fri Jan 12 16:47:03 PST 2001 -- version 1.0.20
- minor port fixes for SCO Open Server 5

Sun Oct 29 15:05:00 PDT 2000 -- version 1.0.18
- added -H for HTTP headers
- now put quotes around user names that have spaces in them

Tue Oct 24 13:01:22 PDT 2000 -- version 1.0.17
- recompiled after library fixes

Tue Oct 17 12:41:22 PDT 2000 -- version 1.0.16
- fixed assertion failure in the library

Fri Oct  6 12:46:28 PDT 2000 -- version 1.0.15
- now show user name in the short listing (U=)

Fri Oct  6 09:13:47 PDT 2000 -- version 1.0.14
- now attempt to recognize a domain controller in the listing (first try)
  fixed a small core-dump bug.

Thu Jun 22 21:32:44 PDT 2000 -- version 1.0.13
- figured out the no-names thing

Thu Jun 22 11:31:10 PDT 2000 -- version 1.0.12
- started fixing the parse_nbtscan() processing for the no-names error

Tue Jun 20 08:12:08 PDT 2000 -- version 1.0.11
- dumped all proxy crap, now use library "parse_target()"

Fri Jun  9 11:08:33 PDT 2000 -- version 1.0.10
- checking into new Perforce depot structure

Wed May 17 12:31:40 PDT 2000 -- version 1.0.9
- portability fixes

Thu Apr 20 20:45:43 PDT 2000 -- version 1.0.8
- added reasonable usage() message (finally!)
- lots of PC-Lint cleanups

Mon Apr 10 16:49:27 PDT 2000 -- version 1.0.7
- now only require Winsock 1.1 on NT platforms (no UNIX changes)

Mon Apr 10 14:42:01 PDT 2000 -- version 1.0.6
- added multiple-target support, started adding good retry support

Sun Apr  9 19:56:51 PDT 2000 -- version 1.0.5
- tried to implement broadcast mode (didn't work)

Sun Apr  9 08:09:51 PDT 2000 -- version 1.0.4
- minor porting fixes to Unixware
- now require sleep_msecs() function to have a real body!

Sun Apr  9 07:31:57 PDT 2000 -- version 1.0.3
- added DNS lookups for target specifications (finally!)
- show inverse DNS name along with ether address
- added '-V' for version information
- now proxy support must be specifically compiled

Sat Apr  8 09:27:03 PDT 2000
- ported to NT (easy!)