Nmap Security Scanner
*Ref Guide
Security Lists
Security Tools
Site News
Advertising
About/Contact
Credits
Sponsors





Intro Reference Guide Book Install Guide
Download Changelog Zenmap GUI Docs
Bug Reports OS Detection Propaganda Related Projects
In the Movies In the News
Example Scripts
Prev Chapter 9. Nmap Scripting Engine Next

Example Scripts

This section should probably provide 2–3 scripts which show a diverse and interesting set of NSE features. Each script should probably have its own sect2 containing a brief description of the script and anything noteworthy about it, followed by the script itself with annotations (lineannotation tag) as you can see, for example, at http://nmap.org/vscan/vscan-technique-demo.html

DT: perhaps include an optional version field

Finger-Test Script

The finger script (finger.nse) is a perfect example of how short typical NSE scripts are.

first the information fields are filled out, note that the id field is kept short, this is important since it is printed in Nmap's output. A detailed description of what the script actually does should go in the description field.

id="Finger Results"

description="attempts to get a list of usernames via the finger service"

author = "Eddie Bell <ejlbell@gmail.com>"

license = "See nmaps COPYING for licence"

The categories field is a table containing all the categories the script belongs to—These are used for script selection through the --script option.

categories = {"discovery"}

You can use the facilities provided by the nselib (the section called “Lua Extensions”) by requiring them. Here we want to use shorter port rules.

require "shortport"

We want to check whether the service behind the port is finger, or whether it runs on finger's well known port 79. Through this we can use the information gathered during the version scan (if finger runs on a non-standard port) or still run against at least the port we expect it, should the version detection information not be available.

portrule = shortport.port_or_service(79, "finger")

action = function(host, port)
  local socket = nmap.new_socket()
  local results = ""
  local status = true

The function err_catch() will be called for clean up, through NSE's exception handling mechanism. Here it only closes the previously opened socket (which should be enough in most cases).

local err_catch = function()
  socket:close()
end

The clean up function gets registered for exception handling via a call to nmap.new_try()

  local try = nmap.new_try(err_catch())

The script sets a timeout of 5000, which is equivalent to 50 seconds. Should any operation require more time we'll receive a TIMEOUT error message.

  socket:set_timeout(5000)

For actually using exception handling we need to wrap calls to functions, which may return an error inside try()

  try(socket:connect(host.ip, port.number, port.protocol))
  try(socket:send("\n\r"))

The call to receive_lines() is not wrapped in try(), because we don't want to abort the script just because we didn't receive the data we expected. Note that there is less data than requested (100 lines), we still receive it and the status is true —consequent calls would yield a false status.

  status, results = socket:receive_lines(100)
  socket:close()

The script returns a string only if we got the data we wanted, otherwise nil is returned (automatically, since scripts return one result).

  if not(status) then
    return results
  end
end

Service Owner Lookup via Identd

showOwner.nse demonstrates the flexibility of the NSE, which is unmatched by other parts of Nmap. If the target is running an identd daemon it connects to it for each running service and tries to identify its owner.

id = "Service owner"

description = "Opens a connection to the scanned port, opens a connection to \
port 113, queries the owner of the service on the scanned port and prints it."

author = "Diman Todorov <diman.todorov@gmail.com>"

license = "See nmaps COPYING for licence"

categories = {"safe"}

Portrules are not restricted to those provided by the short-port module (the section called “Short Portrules”). They can be any function taking a host- and a porttable as argument and returning a boolean.

portrule = function(host, port) 
  local identd, decision

In order to determine the state of a port, which is not provided as argument we just have to construct a table describing the port (i.e. its number and the protocol it's using) and pass it to nmap.get_port_state() which returns a table filled with the information Nmap has about the port.

  local auth_port = { number=113, protocol="tcp" }
  identd = nmap.get_port_state(host, auth_port)

  if 
    identd ~= nil
    and identd.state == "open" 
  then
    decision = true
  else
    decision = false
  end

  return decision
end

action = function(host, port)
  local owner = ""

Scripts can open any number of connection they want.

  local client_ident = nmap.new_socket()
  local client_service = nmap.new_socket()

  local catch = function()
    client_ident:close()
    client_service:close()
  end

  local try = nmap.new_try(catch)

  try(client_ident:connect(host.ip, 113))
  try(client_service:connect(host.ip, port.number))

  local localip,localport,remoteip,remoteport = try(client_service:get_info())

  local request = port.number .. ", " .. localport .. "\n"

  try(client_ident:send(request))

  owner = try(client_ident:receive_lines(1))

  if string.match(owner, "ERROR") then 
    owner = nil
  else
    owner = string.match(owner, "USERID : .+ : (.+)\n", 1)
  end

  try(client_ident:close())
  try(client_service:close())

  return owner
end

Prev Up Next
Version Detection using NSE Home Implementation
[ Nmap | Sec Tools | Mailing Lists | Site News | About/Contact | Advertising | Privacy ]