Nmap Security Scanner
*Intro
*Ref Guide
*Install Guide
*Download
*Changelog
*Book
*Docs
Security Lists
*Nmap Hackers
*Nmap Dev
*Bugtraq
*Full Disclosure
*Pen Test
*Basics
*More
Security Tools
*Pass crackers
*Sniffers
*Vuln Scanners
*Web scanners
*Wireless
*Exploitation
*Packet crafters
*More
Site News
Site Search:
Exploit World
Advertising
About/Contact
Credits
Sponsors:
edgeos



Intro Reference Guide Book Install Guide
Download Changelog Zenmap GUI Docs
Bug Reports OS Detection Propaganda Related Projects
In the Movies In the News

Implementation

Now how does all this work? The following section describes some interesting aspects of NSE. While the focus primarily lies on giving script writers a better feeling of what happens with scripts, it should also provide a starting point for understanding (and extending) the NSE sources.

Initialization Phase

During its initialization stage, Nmap loads the Lua interpreter, including its provided libraries. These libraries are documented in the Lua Reference Manual. Here is a summary:

  • The package library (namespace: package)—Lua's package-lib provides (among others) the require function, used to load modules from the nselib.

  • The table library (namespace: table)—The table manipulation library contains many functions used to operate on tables—Lua's central data structure.

  • The I/O library (namespace: io)—The Input/Output library offers functions such as reading files and reading the output from programs you execute.

  • The OS library (namespace: os)—The Operating System library provides facilities of the operating system, including filesystem operations (renaming/removing files, temporary file creation) and access to the environment.

  • The string library (namespace: string)—The string library helps you with functions used to manipulate strings inside Lua. Functions include: printf-style string formatting, pattern matching using Lua-style patterns, substring extraction, etc.

  • The math library (namespace: math)—Numbers in Lua usually correspond to the double C type, so the math library provides access to rounding functions, trigonometric functions, random number generation, and more.

  • The debug library (namespace: debug)—The debug library provides you with a somewhat lower level API to the Lua interpreter. Through it you can access functions along the execution stack, get function closures and object metatables, etc.

In addition to loading the libraries provided by Lua, the functions in the nmap namespace are loaded. The search paths are the same directories that Nmap searches for its data files and scripts, except that the nselib directory is appended to each. In this step the provided script arguments are stored inside the registry.

The next phase of NSE initialization is loading the chosen scripts, which are the arguments provided to the --script option or default, in case of a default script scan. The string version is appended, if version detection was enabled. The arguments afterwards are tried to be interpreted as script categories. This is done via a Lua C function in nse_init.cc called entry. Inside script.db, for each category of a script, there is a call to Entry. If the category was chosen then the script is loaded. Every argument of --script that could not be interpreted as a category is loaded as a file or directory. If the file or directory could not be located, then an error is raised and the Script Engine aborts.

All of the .nse files inside a loaded directory are loaded as files. Each file loaded is executed by Lua. If a portrule is present, then it is saved in the porttests table with a portrule key and file closure value. Otherwise, if the script has a hostrule , then it is saved in the hosttests table in the same manner.

Matching of Scripts to Targets

After the initialization is finished the hostrules and portrules are evaluated for each host in the current target group. At this check a list is built which contains the combinations of scripts and the hosts they will run against. It should be noted that the rules of all chosen scripts are checked against all hosts and their open and open|filtered ports. Therefore it is advisable to leave the rules as simple as possible and to do all the computation inside the action, as a script will only be executed if it is run against a specific target. After the check those script-target combinations get their own Lua thread. A thread running against a host will have only a hostrule passed to the action closure whereas a thread running against a port will have both a hostrule and portrule passed. Each thread is stored with information relevant to the thread. This information includes the runlevel, target, target port (if applicable), host and port tables (passed to action), its type (running against a host or port), and its id. The mainloop function will work on each runlevel grouping of threads in order.

Running Scripts

Nmap is able to perform NSE script scanning in parallel by making use of Lua language features. In particular, coroutines offer collaborative multi-threading so scripts can suspend themselves at defined points, and allow other coroutines to execute. Since network I/O, especially waiting for responses from remote host, is the part of scripts which would consume most time with waiting, this is the point where scripts suspend themselves and let others execute. Each call to some of the functions of the Nsock wrapper causes the calling script to yield (pause). Once the request is processed by the Nsock library, the callback causes the script to be pushed from the waiting queue to the running queue, which will eventually let it resume its operation.

The mainloop function will maintain two sets of threads, running and waiting. Threads will be moved back and forth between the sets; when a thread yields, it is moved to the waiting group. Threads run in the running set will either yield, complete, or error. After all scripts are resumed in the running set, mainloop will place all yielded threads ready to be run in the running set. Threads are made "ready" by calling process_waiting2running. This process of running threads and moving paused threads to the waiting and running sets is repeated until no threads exist in either waiting or running.

Adding C Modules to Nselib

This section gives a short walk-through for adding nselib modules written in C (or C++) to Nmap's build system, since this has shown to be sometimes tedious. Writing C modules is described at length in Programming in Lua, Second Edition. Basically C modules consist of the functions they provide to Lua, which have to be of type lua_CFunction. Additionally they have to contain a function which is used to actually open the module. By convention these function names are luaopen_<modulename>. A good starting point for writing such modules is provided by bit.c inside the nselib/ subdirectory of Nmap's source tree. bit is a C module already provided by the nselib. C modules basically are shared libraries which get loaded at runtime by Lua.

The Unix build system uses libtool for compilation in a platform independent way. As long as the new module does not depend on foreign libraries, you should only need to add <modulename>.so to the all and clean targets in Makefile.in and copy and adapt the lines from bit.so. If your module does have dependencies you will most probably have to add checks for those libraries to configure.ac and put the dependencies inside the libtool commands in Makefile.in.

Of course, theory and practice are rarely the same. Most of the trouble building nselib actually comes from the complications of building shared libraries and not nselib itself. Linking with static libraries (e.g. libnbase) sometimes leads to problems with exporting symbols on some platforms (in our case the x86_64-linux platform). To our knowledge no such problems occur when linking against already existing shared libraries.

The Windows build system requires C module developers to create a MS Visual Studio Project file for their module (<modulename>.vcproj) inside the nselib subdirectory. On Windows you have to include the liblua/ subdirectory as an additional include path as well as a library search path. In addition you have to tell the project to link against the liblua.lib static library provided with Nmap. Other properties of the project should be the same as for other nselib C modules (e.g. see nse_bitlib.vcproj). Afterwards you have to include the newly created project file in Nmap's Visual Studio solution file (mswin32\nmap.sln) and make sure that nse_bitlib.vcproj depends on your project, because it is there that nselib modules get copied to their final destinations and are included in Nmap.

[ Nmap | Sec Tools | Mailing Lists | Site News | About/Contact | Advertising | Privacy ]