
Nmap Development mailing list archives
A Comment on the Versatility of Nmap+V
From: "Jay Freeman \(saurik\)" <saurik () saurik com>
Date: Tue, 2 Sep 2003 17:35:56 -0700
Multiple people have now used the term "banner grabbing" to describe the functionality that nmap+V provides, which indicates to me that I haven't spent enough time describing the functionality of nmap+V, how it works, what's implemented, and where I want it to go. "Banner grabbing" is an extremely simplistic tool, that, while possible for implementing a large percentage of the "protocol detection" tasks, doesn't live up to the "network mapping" vision that Fyodor puts forward for nmap in his recent e-mail. My eventual goal with Nmap+V, since I started working on it over three years ago all the way up until today, is to have a versatile platform for doing extensive service scanning. Using my scan engine I want it to be easy to develop scans that not only determine the protocol/application, but can also determine a variety of other things other things that are associated with services running on given ports. I will get more into this later in this e-mail. Possibly more importantly, however, I don't want to stop short with a 90% solution for the protocol / application version detection case. If there's some reasonably used protocol out there that the system is unable to get good information back from, then I don't consider it to be a "quality implementation" (as laid out in Fyodor's e-mail of the goals for what he would like to see implemented in nmap). To illustrate this problem I tend to use the example of IRC. If you connect to irc.saurik.com on port 6667 you will receive this immediately: :irc.saurik.net NOTICE AUTH :*** Looking up your hostname... :irc.saurik.net NOTICE AUTH :*** Found your hostname (cached) :irc.saurik.net NOTICE AUTH :*** Checking ident... :irc.saurik.net NOTICE AUTH :*** Checking for open socks server... :irc.saurik.net NOTICE AUTH :*** No socks server found (good!)... This isn't always true of IRC servers, some don't reply at all. Regardless, this alone doesn't tell you much about the remote implementation. Most modern IRC servers, each with very different capabilities once you've actually logged in, send back the exact same strings (down to the capitalization). The next step is to attempt to login: USER bob bob bob bob NICK bob This comes back as following: :irc.saurik.net NOTICE AUTH :*** No ident response; username prefixed with ~ :irc.saurik.net NOTICE bob :*** If you are having problems connecting due to ping timeouts, please type /quote pong 67AE11 or /raw pong 67AE11 now. PING :67AE11 Now, at this point you may be able to determine that this is UnrealIRCd (as I don't know much about the timeouts string), but that string has nothing to do with the protocol and is sometimes customized to make it more obvious for the end users of this particular server. The important point here is the "PING" that is sent. This is done to verify that we aren't spoofing our return address. To this we must reply: PONG :67AE11 At which point we actually get some useful information: :irc.saurik.net 001 bob :Welcome to the IRC IRC Network bob!~bob () ip68-6-65-181 sb sd cox net :irc.saurik.net 002 bob :Your host is irc.saurik.net, running version Unreal3.1.3-Komara :irc.saurik.net 003 bob :This server was created Fri Jun 28 2002 at 06:25:56 CDT :irc.saurik.net 004 bob irc.saurik.net Unreal3.1.3-Komara oOiwghskSaHANTcCfrxeWqBFIzdvtGj lvhopsmntikrRcaqOALQbSeKVfHGCuzN ... With nmap+V, I actually perform these steps (with random user information) in order to obtain the version from the server. I do it rather quickly as well as I have a strong implementation of parallel port requests and short circuiting when I get enough information to determine the match. Most importantly, however, defining this query wasn't that complicated using my new file format from 2.99: <probe name="IRC" ports="6665-6669"> <label name="IRC"/> <send data="USER \R-----+ \R-----+ \R-----+ \R-----+\nNICK \R-----+\n"/> <switch timeout="5000000"> <match regex="PING ([^\r\n]+)"> <send data="PONG $1\n"/> </match> </switch> <switch timeout="500000"> <match regex=":[^ ]+ 004 [^ ]+ [^ ]+ ([^ ]+)"> <set-value name="Service" value="IRC"/> <set-value name="Version" value="$1"/> <match regex=":[^ ]+ 001 [^ ]+ :Welcome to the ([^\n]+) Network"> <set-value name="Network" value="$1"/> </match> </match> </switch> </probe> This definition is arguably more complex than the equivilant TCL/Expect script (largely because it was written in an XML format and has some information duplication due to that), but TCL/Expect does horribly with binary protocols (even in the simpler cases, nmap+V can currently handle most of the simple cases and I have plans for how to make it handle the more complex ones). Also, TCL/Expect isn't easily run in parallel against numerous ports at the same time without resorting to running multiple instances or trying to use a threaded version of TCL and running each port in a seperate thread. The requirements of a fast "scan an entire series of computers" system is therefor much different. I have also mentioned the usage of external languages for this purpose to people at various times on various lists (including this one a few years back), and their first reaction is usually one of "bloat" (which I disagree with, but it _is_ a concern if users see it that way). I am definitely still open to discussions about possible paths including "try to integrate either some -isms from language X or just use language X with this cool option that let's you control it's execution slicing". Now that I've gone over that, looking at the language you can probably see how a lot of differen things could rather easily be determined, and still determined efficiently, from the myriad of protocols available on a given computer: o statistics about the computer (obtaining the MAC address, the number of open MySQL connections, what time the computer responds to NTP requests with) o specific configuration of applications (what Apache modules are installed, what extensions are supported by the telnet daemon, what the administrative policies of the SMTP server are) o general recon on the state of the machine (finding out what DNS zones it is authoritative for, custom responses to identd) o information about the content served by the computer (what IRC network the IRC server is connected to, what the title of the default website is) A lot of these are already possible with Nmap+V's current implementation (although not actually implemented in the service probes file, which is rather sparse and mainly concentrates on some particular examples involving HTTP). Some of these still need more time, but I have plans for how to add the required functionality to the language in a general enough way that it could be easily applied to numerous other situations. A lot of it comes down to making the language feel more like XSL/T and making it more turing complete, as well as providing some helper functions that you can call on string match arguments in order to do some binary mangling. An example of what I'm talking about with the latter case is allowing you to do: <set-value name="# of Connections" value="{int($1)}"/> I recently came to the realization that a rather good option on each of these fronts is to design a new language that draws as much from an existing language as possible and to use XML wherever it makes sense to make things easier to parse and generate from other tools. As you can see my current plan revolves around mimicking XSL/T's paradigms (as indicated in the above with $ variables and {} execution context escaping). Given all of this, I implore people to think twice before just labeling this as "banner grabbing". It is so much more than that :). _However_, even so, nmap+V isn't "overpowered" for the task of service/version scanning. Even if you feel that simplistic banner grabbing is the best way to approach the problem, nmap+V is still extremely leightweight and I will argue capable of executing just as fast as something that is specialized for "send probe, receive one of a number of responses" (possibly eating up a small amount more CPU in the process, but A) it is negligable and B) this is an I/O bound problem anyway). nmap+V simply offers the flexibility to occasionally add extra information gathering to the pipeline (as I do with HTTP for Apache modules and <title/> tags), or the ability to get the version from more complicated protocols (such that might require a handshaking step at the outset). This more simplistic usage case is how I've been using nmap+V's configuration language thus far in my distributions. ====================================================================== Here is an example of a more complex use case: Maybe you would like to find SMTP servers that seem to have open relays; maybe you administrate a corporate/university network and want to make sure none of the computers on it are accidentally configured such that a spammer might utilize it. You could load the following script and a -sVVV scan would do that for you (note that the <clear/> command here is really important and is not present in 2.99; you will need to get nmap+V from CVS or wait until 3.00 tomorrow): ---------------------------------------------------------------------- <?xml version="1.0"?> <switch timeout="5000000" xmlns="http://saurik.com/nmap+V/3.00"> <match regex="^220 ([^ ]*) .*SMTP"> <set-value name="Service" value="SMTP"/> <send data="EHLO $1\r\nMAIL From: <spam@test.unknown>\r\nRCPT To: <spam@test.unknown>\r\nDATA\r\n"/> <set-value name="Open Relay?" value="No :)"/> <switch timeout="5000000"> <match regex="\n354 "> <clear/> <send data=".\r\n"/> <switch timeout="1000000"> <match regex="^250 "> <set-value name="Open Relay?" value="Yes! :("/> </match> </switch> </match> <match regex="\n550"/> </switch> </match> </switch> ---------------------------------------------------------------------- Here is some example output from that (localhost comes up as relay here because I have 127.0.0.1 in my /etc/mail/access file so it was a useful example): ---------------------------------------------------------------------- [root(2)@ironclad nmap]# ./nmap -sVVV -p25 localhost mx1.mail.yahoo.com maila.microsoft.com Starting nmap 3.30+V ( http://www.insecure.org/nmap/ ) at 2003-09-01 05:18 CDT Interesting ports on localhost.localdomain (127.0.0.1): Port State Service Protocol Version 25/tcp open smtp SMTP Open Relay?: Yes! :( Interesting ports on mta-v20.level3.mail.yahoo.com (64.156.215.5): Port State Service Protocol Version 25/tcp open smtp SMTP Open Relay?: No :) Interesting ports on mail1.microsoft.com (131.107.3.125): Port State Service Protocol Version 25/tcp open smtp SMTP Open Relay?: No :) Nmap run completed -- 3 IP addresses (3 hosts up) scanned in 1.924 seconds [root(2)@ironclad nmap]# ---------------------------------------------------------------------- Now, this scan chose to directly target port 25, but this wasn't a requirement. As the script detected SMTP before attempting to send the commands for relaying, it wouldn't be an issue to run this on multiple ports. However, it _will_ take irritatingly long becuase it will wait for a "220 something SMTP" for up to 5 seconds before giving up on that port (and even with 8 ports at a time or whatever the default is, this could take a while on each computer). So, to fix this, we add a short circuit to our switch. Now, unfortunately I'm not currently using libpcre or any kind of advanced regex engine, so the best I can do is to look for a string that starts with something other than a '2' (at least, with my knowledge of regex): <match regex="^[^2]"/> Adding this to the outermost switch should make processing immediately stop on ports that at least respond. From here it would be a matter of tweaking the timeout for your needs. Sincerely, Jay Freeman (saurik) saurik () saurik com --------------------------------------------------------------------- For help using this (nmap-dev) mailing list, send a blank email to nmap-dev-help () insecure org . List run by ezmlm-idx (www.ezmlm.org).
Current thread:
- A Comment on the Versatility of Nmap+V Jay Freeman (saurik) (Sep 02)