CIFS: Common Insecurities Fail Scrutiny
=======================================

*Hobbit*, Avian Research, hobbit@avian.org, January 1997

Abstract
========

An analysis of TCP/IP NetBIOS file-sharing protocols is presented, and the steps involved in making a client to server SMB connection described in some detail. Emphasis is placed on protocol and administrative vulnerabilities at various stages and fixes/workarounds for some of them, with the hope that the reader will better understand attacks and defenses alike. Several examples are presented, based upon using programs from the Unix Samba package to probe a target IP network and survey it for potential problems.

Introduction
============

We will explore the Shared Message Block protocol and related issues, at the network level and higher, in the interest of presenting useful knowledge about Microsoft networking [loosely aka any of CIFS, NetBEUI/NetBIOS, Lan Manager compatible] security issues. Microsoft systems and applications, based on NT and various flavors of Windows, are forcibly entering homes and offices the world over and all expecting to speak SMB-based filesharing protocols among themselves as well as with products from other vendors. As the network security community has come to expect from most commercial offerings, these systems are distributed with poorly configured security settings which are seldom changed or even reviewed by their new owners before being plugged into the Internet. This leaves many of them vulnerable to trivial attacks, and administrators who *do* try to address the security issues often miss or misconfigure things, perhaps making their systems less obviously vulnerable but nonetheless still vulnerable. A major factor in the difficulty is that many security practitioners are venturing into new territory here, which turns out to be riddled with unexpected and undocumented pitfalls. People relatively new to the overall networking security field, including many of those implementing and installing said operating systems, often lack the experience gained from other OSes and environments and have no idea where to look for potential problems.

No specific audience is targeted here, but administrators with a primarily Unix and NFS background that are now being asked to also support Windows and NT environments may benefit the most from this. A necessarily Unix-centric viewpoint is taken, since that is where the author's main strengths are, but more importantly because Unix-based source code for a protocol implementation is freely available. Andy Tridgell's Samba package represents an amazing amount of very solid and still-evolving work, and allows Unix systems to interoperate with Microsoft and Lan Manager platforms to access files and other resources over TCP/IP networks. The examples and discussion herein refer to the "stable release" version 1.9.15 patchlevel 8 of Samba, with some minimal modifications geared toward exploring the security aspects of the protocol. While not the latest release, it suffices here, and the documentation that comes with it is highly recommended reading. The evolving Internet-draft for the Common Internet File System, or CIFS, is also a key reference work that expands upon original or "core" SMB and explains most of what the boys in Redmond hope will become a full Internet standard. Their own implementations mostly adhere to the draft, and many other vendors already support CIFS or some subset thereof. A few issues specific to NT necessarily appear, but NT security itself is a whole different bucket of worms and is mostly outside the scope of this text.

So far there seems to be very little hard information available about this, although I am aware of at least one other ongoing related effort. Several megabytes of NT-security archives, random whitepapers, RFCs, the CIFS spec, the Samba stuff, a few MS knowledge-base articles, strings extracted from binaries, and packet dumps have been dutifully waded through during the information-gathering stages of this project, and there are *still* many missing pieces. Some compatible platforms were unavailable for testing, notably OS/2. While often tedious, at least the way has been generously littered with occurrences of clapping hand to forehead and muttering "crikey, what are they *thinking*?!" The intent is not to compete against other works in progress, it is rather to aid them in moving forward.

This document may be freely copied and quoted in whole or part, provided that proper attribution is included. Many of the ideas contained herein are not new, although it is possible that one or two hitherto unknown problems or methods have been independently discovered. The point is to collect the information into one place and describe a stepwise procedure for evaluating this type of network environment, in a way that those of us who have hitherto mostly shunned any dealings with Microsoft and other PC network products can readily understand.

Groundwork: What's out there?
=============================

Little needs to be said here. Given a target network or set of IP addresses, well-known methods can be used for finding the target hosts -- the procedure which at least one large contractor refers to as "network contour assessment." DNS zone dumps in conjunction with tools such as "fping" can quickly locate active machines. To specifically locate potential SMB servers, scanning for TCP port 139 is a fairly safe bet. In the absence of packet filtering, connection attempts there either open or get refused so it is unnecessary to wait around for long timeouts. If machines respond to pinging or other connectivity tests but TCP connections to 139 time out, then it is likely that there is a packet filter in the way protecting against NetBIOS traffic. A Unix parallel would be running something like "rpcinfo -p" against a set of targets to find NFS servers, which may or may not be protected by a filter blocking traffic to the portmapper at TCP/UDP 111.

We will therefore assume having collected a list of potential SMB servers, and proceed to attack a single target therein. Note however that information gleaned from neighboring machines may be useful, just as in the traditional Unix-based environment. Remembering various information about a network as a whole and plugging it back into specific host attacks is a classic approach amply detailed in numerous papers.

Phase 0: Name determination
===========================

To establish an SMB session to a typical target, one must not only have its IP address but also know its "computer name." This is an arbitrary name similar to a DNS hostname assigned by an administrator, unique within an organization or at least a given LAN, and in many installations the computername and DNS name are the same for administrative convenience. Name resolution is by definition a separate entity from SMB itself, and employs a variety of methods including static files, DNS, WINS, and local-wire broadcasts. When a machine is running NetBIOS over TCP/IP, or "NBT", it attaches its own little name service to UDP port 137, which makes a continual effort to both locate and disseminate as much info as it can about services on the local LAN. One of its functions is periodically broadcasting its own set of names on to the local wire, to notify immediate neighbors that it exists and offers services. IP routers generally do not forward these broadcasts, so passive receivers outside an immediate subnet will not learn these names or which IP hosts they belong to. Fortunately there is usually an easy way to remotely determine the name, known as a "node status query." The name service also replies to direct queries about certain names associated with its own particular host, and if it is running as a WINS server it can give out even more information.

There are two basic query types -- IP address, and node status. Status query might be more properly called name query, since sending one should elicit an answer containing all of a target's NetBIOS names. Both are remarkably similar in structure to DNS queries, and are indeed a variant of the DNS protocol itself. A NetBIOS address query is for resource record type 32 and a status query is type 33; both of class IN or 1. With traditional NetBEUI over non-IP transports such as with local-LAN IPX, computer names are normally uppercase, 16 bytes long, and padded with spaces which are illegal characters in the DNS spec for hostnames. To get around this in IP environments, NetBIOS names are mangled into a rather bizarre format. The official spec for this is in RFCs 1001 and 1002, but to quickly sum it up: Each ASCII character in a name is split into 4-bit halves, and each half is added to ascii value 0x41 [uppercase "A"] to form a new byte. Each original character therefore becomes two mangled characters in the range A-P, doubling the entire length to 32 bytes. Thus, the name "FEH" gets padded out with spaces and becomes

        ascii string "FEH             "  -- is
        hex 46 45 48 20 20 20 20 20 20 20 20 20 20 20 20 20  -- split into
        hex 4 6 4 5 4 8 2 0 2 0 2 0 2 0 2 0 2 0 ...etc...  -- add to "A" gives
        hex 45 47 45 46 45 49 43 41 43 41 43 41 ...etc...  -- which is
        mangled string "EGEFEICACACACACACACACACACACACACA"
The name_mangle() routine in Samba's util.c does this translation. The characteristic "...CACACACA" string trailer makes NetBIOS names easily recognizable when they show up in packet dumps and such. Of particular interest is the wildcard name "*", but padded with *nulls* instead of spaces. This mangles to "CKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA". Under most circumstances, name-service listeners are required to reply to queries for this wildcard name as well as for their own computernames. Therefore sending a status query for this "*" name is very likely to produce a name reply as resource records containing the target's NetBIOS names, which oddly enough come back in *non-mangled* format. Multiple copies of some names usually show up, but they are subtly different. In practice the 16th byte of a non-mangled name is a type byte, which is a different animal from a DNS resource-record type! When a NetBIOS machine comes up its "name registration" broadcasts contain multiple instances of its own name and other strings, but with several different *NetBIOS* name types that can indicate different services. Note herein that mangled names are of length 32 or 0x20, address queries are RR type 32, and several returned names have *type* 0x20. Therefore a lot of 0x20s show up in these DNS-style packets and can make things rather confusing. There seem to be many name types, not particularly well documented except maybe in knowledge bases or resource kits, but the important ones are
        0x00    base computernames and workgroups, also in "*" queries
        0x01    master browser, in magic __MSBROWSE__ cookie
        0x03    messaging/alerter service; name of logged-in user
        0x20    resource-sharing "server service" name
        0x1B    domain master-browser name
        0x1C    domain controller name
        0x1E    domain/workgroup master browser election announcement ?
The mangling example above has 0x20 as its type byte, therefore building the name variant used when connecting to fileservers. Server and workstation machines alike can provide various different services, and are thus usually aware of more than one name/type at once. In fact most of them return a group of five or so in a status reply, including the base computer name and whatever "workgroup" the target is a member of. Name type 0 should be used with the special "*" query which is null-padded anyway, or a response is unlikely. If NO name of type 0x20 is present in the list, it is unlikely that the machine in question has been configured to share any of its own resources and attempts to connect sessions to it will likely fail. Name type 0x3 in the reply often reveals the username logged in at the machine's console, and should be collected as a potential username to try against this or neighboring targets. The base name may also be the same as a username, since in typical small office environments the machines are often associated with specific people. The special name "^A^B__MSBROWSE__^B^A" [last char being control-A, or type 1] indicates a "master browser" which is a machine that collects info about neighboring machines -- in particular, their IP addresses. A master browser is a fortunate find since we can likely get a "browse list" from that machine [described later] and then possibly query that same target for all the other names and addresses it claims to know about.

One can do "nbtstat -A {ip-addr}" from a Microsoft platform to direct "*" queries to a specific IP-aware target and obtain its name list. In the absence of a mapping in an LMHOSTS file or some other mechanism, a specific machine can be found using "nbtstat -a \\NAME" if it is on the local wire. An address query is sent to the broadcast address of the connected subnet, and if a machine responds then a unicast status query is sent to it. For reasons unfathomable Microsoft platforms usually send status replies FROM UDP 137 TO UDP 137, regardless of the UDP source ports of query packets, so the querying application must locally bind to 137 [requiring root on Unix boxes] to ensure that replies can be received. Oddly enough, *address* replies are normally returned to whatever source port the query was from! To handle this fine example of the IP savvy out there in Redmond, a tiny patch is needed for the "nmblookup" Samba program, which as it comes grabs a high port and is unlikely to receive status replies. It will then work similarly to "nbtstat" when run as root, sending the "*" query if given the "-S \*" argument [quoting "*" to the shell], and also accepts a *unicast* target IP as the -B argument. Nmblookup also has an interesting feature that allows setting the hex name type in a query -- for example, a name of the form "TARGET#1C" forces the name type to be 0x1C. A slightly more "raw" equivalent of the generic "*" query, which sometimes elicits a response containing no names but a response nonetheless, can be done using netcat to locally bind UDP port 137 and send a query. Feed the following input bytes into "nc -v -u -w 3 -p 137 target 137" and the output through "cat -v":

        0x00 # . 1
        0x03 # . 2      # xid
        0x00 # . 3
        0x00 # . 4      # flags
        0x00 # . 5
        0x01 # . 6      # qcnt
        0x00 # . 7
        0x00 # . 8      # rcnt
        0x00 # . 9
        0x00 # . 10     # nscnt
        0x00 # . 11
        0x00 # . 12     # acnt
        0x20 #   13     # namelen
        0x43 # C 14     # mangled "*" ...
        0x4b # K 15
        0x41 # A 16
        0x41 # A 17
        0x41 # A 18
        0x41 # A 19
        0x41 # A 20
        0x41 # A 21
        0x41 # A 22
        0x41 # A 23
        0x41 # A 24
        0x41 # A 25
        0x41 # A 26
        0x41 # A 27
        0x41 # A 28
        0x41 # A 29
        0x41 # A 30
        0x41 # A 31
        0x41 # A 32
        0x41 # A 33
        0x41 # A 34
        0x41 # A 35
        0x41 # A 36
        0x41 # A 37
        0x41 # A 38
        0x41 # A 39
        0x41 # A 40
        0x41 # A 41
        0x41 # A 42
        0x41 # A 43
        0x41 # A 44
        0x41 # A 45     # [embedded type byte]
        0x00 # . 46     # terminator
        0x00 # . 47
        0x21 # ! 48     # querytype NBTSTAT
        0x00 # . 49
        0x01 # . 50     # class IN
In rare cases, an additional "scope ID" may be tacked on to mangled names in the format "EGEFEICACACACACACACACACACACACACA.scope" just like in multipart DNS names. A scope does not contain spaces, and therefore can and indeed is sent unchanged in hostname queries. Scope names are further discussed later under "defenses", since they can play a role therein.

Firing "*" queries at either selected hosts or the IP subnet's directed broadcast is another way of probing around for active SMB hosts. Most routers do not forward directed-subnet broadcast, but ones that do may get you all the answers in one or two shots! In most cases, scanning for TCP port 139 and following up with unicast UDP status queries is still likely to be faster and more reliable, especially when a target for some reason won't respond to "*" queries. This sometimes happens if the messaging or alerter service is shut down on the target, which is one recommended security procedure in several documents. If you suspect this case, try asking for "WORKGROUP", parts of the target's DNS name, and other likely strings like variants on the name of the organization or people within it. Status-querying explicitly for a machine's name or workgroup using type 0 should also cause it to respond, and a lack of any type 0x3 names in the list would confirm that messaging is disabled. Whether due to packet filters or some other reason, getting *no* reply for all this effort is still not a reason to give up -- it is UDP after all, and further name guesses can be plugged in during the next phase.

Phase 1: The TCP session
========================

Next we open a TCP connection to port 139 on the target. There is no longer a need for any special local ports, so smbclient can run as a normal Unix user. The "called" target's computername of the appropriate type and the "caller" client name are name-mangled and plugged into a Session Request block sent to the server. The idea here is to sanity-check the name determination step and ensure that one is conversing with the correct machine -- especially wise in the inevitable cases of outdated LMHOSTS files or DNS data. If the target server's name is right a "positive response" is sent back, and the connection remains open. If the wrong server name is passed in, a "negative response" is sent along with an error code, and the server end of the connection starts a TCP shutdown by sending a FIN. Nothing further can be done with the failed connection; a new one must be opened to try a different servername. The name of the connecting client is largely irrelevant and can even be null, although its name type is generally 0. However, the name the client supplies is the name that gets logged during later phases such as user logins. The client name may also affect behavior against NT machines which have such settable parameters as which workstations a given user may log in from. It appears that the source IP address is *completely* irrelevant to Microsoft-based servers, which simply accept the given client name. This is a first hint about how much functionality is left up to the client. A vague Unix parallel might be faking the client hostname in mount requests to be something in the target's export list, which usually worked against early NFS implementations.

This session request is only the first of many steps taken behind the scenes by most client commands. From a command prompt on a Microsoft box one does "net use \\TARGET\SHARENAME" to begin access to a filesystem, or "net view \\TARGET" to see a target's list of available services. Samba's "smbclient" accepts the same syntax, although the backslashes need to be isolated from the shell by enclosing in quotes or specifying \\\\TARGET\\RESOURCE. It also accepts "-L TARGET" to list the available resources, which in any case is what we want to do first. Smbclient by default picks up the caller name from the hostname of the Unix machine it is running on, but we can specify "-n fakename" to set it to something arbitrary.

An error response is usually one of two: either the passed servername wasn't correct, or the name was right but no service of the requested name type is running. Smbclient translates these errors respectively as "called name not present" or "not listening on called name." Usually if server-name/type 0x20 is unreachable, the target is not sharing its resources at all and there isn't much more we can do with it. Sessions to server-name/type 0x3 may work to reach the messaging service and is sometimes a way to check if we got at least one name right, but short of sending annoying messages to the console user it is not particularly useful. Smbclient has a "-M" argument to do message sending. The spec provides for a "not listening for CALLING name" error, implying a potential facility for access restriction by specific client, but today's implementations don't seem to care.

If all UDP name queries above have failed, the same sorts of guessing at the target's computername can be tried here, one per TCP connection. If the connection is relayed via an intermediate machine such as a proxy, the client must still supply the correct name of the target server. Microsoft clients can be faked out with an appropriate LMHOSTS entry with the name of the final destination but the IP address of the *relayer*. As long as the final target sees its own name in the request, it doesn't matter how it got there. An example fast way to script up different LMHOSTS names on the fly would be having "#INCLUDE ramdisk-file-name" in the main LMHOSTS file, to avoid repeatedly writing to the hard drive just to test a bunch of targets. The CIFS spec mentions that the magic target name "*SMBSERVER" is supposed to be some sort of wildcard, but it is optional and no current Microsoft platforms seem to accept it to open sessions. Samba does, simply because by design it accepts any old pair of names for sessions and more sensibly logs the client's IP address if appropriately configured.

Using a relay host can foil backtracing efforts by someone who notices odd network activity or log entries and goes to investigate. A suitable relayer program can take just about any form, such a simple netcat script, a SOCKS gateway, or even Microsoft's own "Catapult" proxy package. The relay would presumably listen on TCP 139 and forward the connection, but with smbclient the relay can listen on any other port and we can supply the "-p {portnum}" argument to reach it. If a high-port relay is already behind a packet filter that blocks TCP 139 but allows >1024, not only is the firewall bypassed but the resulting server connection may look like a completely normal one from a trusted inside host.

Some Linux distributions anticipate being used as Samba servers, and come with an "nbsession" entry in inetd.conf but no server program to handle the connection. These will listen on TCP 139 but immediately close, while noting an appropriate error in the syslog.

(next page)

(this whitepaper written by hobbit and found on http://www.avian.org .. refer to paragraph five above [or if you're a finical little twit (just kidding of course) you may look at the original text on the aforementioned site] to verify the legality of this reproduction.)

Log in or register to write something here or to contact authors.