An Nmap script is basically categorized into three sections, which are discussed here. We will use the script from https://svn.nmap.org/nmap/scripts/smtp-enum-users.nse as an example to define the data in these categories:
- Head: This section holds the descriptive and dependency related data to the script, the below are the various supported components:
- description: This field acts as metadata to the script and describes important information about the script's function in order for the user to make use of it. It attempts to enumerate the users on a SMTP server by issuing the VRFY, EXPN, or RCPT TO commands. The goal of this script is to discover all of the user accounts in the remote system. The script will output the list of usernames that were found. The script will stop querying the SMTP server if authentication is enforced. If an error occurs while testing the target host, the error will be printed with the list of any combinations that were found prior to the error. The user can specify which methods to use and in which order. The script will ignore repeated methods. If not specified, the script will use RCPT first, then VRFY and EXPN. An example of how to specify the methods to use and the order is shown as follows:
description = [[
<code>smtp-enum-users.methods={EXPN,RCPT,VRFY}</code>
]]
-
- Categories: This field allows the user to map the nature of the script by mentioning the category it belongs to. As seen in the preceding introduction, we can mention the categories by using the following syntax from the smtp-enum-users.nse script:
categories = {"auth","external","intrusive"}
-
- author: This field allows the author of the script to provide information about themselves such as their name, contact information, website, email, and so on:
author = "Duarte Silva <duarte.silva@serializing.me>"
-
- license: This field is used to mention any license details required to distribute the script, along with the standard Nmap installation:
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
-
- dependencies: This field defines the run level of the script, which means if any script is dependent on the output from any other script, the same can be mentioned here, allowing the dependent script to be executed first. This output can then be passed to script two:
dependencies = {"dependant script"}
-
- Script libraries: Nmap Script Engine uses variables to allow different scripts to be built upon a similar service. By using dependencies from libraries, authors can write comprehensive and small scripts. The following table explains some of the scan libraries:
Ajp |
cassandra |
Amqp |
citrixxml |
asn1 |
Comm |
base32 |
Creds |
base64 |
Cvs |
Bin |
Datafiles |
Bit |
Dhcp |
Bitcoin |
dhcp6 |
Bittorrent |
Dns |
Bjnp |
Dnsbl |
Brute |
Dnssd |
Eigrp |
Drda |
ftp |
Eap |
For reference, we can look at the script at https://svn.nmap.org/nmap/scripts/smtp-enum-users.nse to see how the libraries are defined:
local nmap = require "nmap"
local shortport = require "shortport"
local smtp = require "smtp"
local stdnse = require "stdnse"
local string = require "string"
local table = require "table"
local unpwdb = require "unpwdb"
These libraries have various functions defined in them, for which we can pass arguments using the following syntax: <function name>(arg1, arg2, arg3). For example, smtp.check_reply("MAIL", response).
- Rules: The script rules are used to determine whether a remote host is to be scanned or not based on the Boolean outcome of true or false. The host is only scanned when the rule returns true. Here are the rules which are applied on the host by a script:
- prerule(): This rule is executed before the scan is performed on the hosts
- hostrule(host),portrule(host, port): These rules are executed after each set of hosts have been scanned using the provided script
- postrule(): This rule is executed once all the host scans are completed
The following is the rule used in the example script smtp-enum-users.nse:
portrule = shortport.port_or_service({ 25, 465, 587 },
{ "smtp", "smtps", "submission" })
- Action: This section consists of the actions to be performed by the script. Once the action is executed, it returns a specific result based on which the end result seen by the user is determined. The following is the action section from the example script smtp-enum-users.nse:
action = function(host, port)
local status, result = go(host, port)
-- The go function returned true, lets check if it
-- didn't found any accounts.
if status and #result == 0 then
return stdnse.format_output(true, "Couldn't find any accounts")
end
Some of the libraries require the script to be in specific formats and must use the NSEDoc format. We will see how to fit the script into such a format in this recipe. In this recipe, we will have a look at creating a script to identify whether default Tomcat files are present on a remote host.