Introduction to Nmap Scripting

Nmap Logo

All people working with networks know the wonderful tool called Nmap.

Basically, Nmap is a network scanner. It allows you to detect hosts on a network and services running on them. Just type “nmap <hostname|ip>” to perform a simple port scan. But Nmap can do much more! Host discovery, multiple scan techniques, version description and OS detection. All of them with optional performance tuning and/or evasive techniques.

Interesting options are:

  • -sT (TCP scan)
  • -sU (UDP scan)
  • -sV (Probe versions)
  • -O (OS detection – fingerprinting)

For a detailed list of options, check out the online documentation.

But Nmap has much more interesting features. For quite a long time, scripting is supported and increases the power of the scanner. Script can be launched from Nmap and add several nice features like: vulnerability detection, auditing and deeper services detection. I was aware of the scripting engine but never used it.

A few days ago, I performed a security assessment and found via Google a Nmap script to detect weak SSH key. It was so convenient that I investigated deeper how scripts are working.

The NSE (“The Nmap Scripting Engine“) executes the script in parallel with the ongoing scan. Scripts are written in the embedded Lua programming language.

Basically, a script is port or host based. All scripts must have a “hostrule” or “portrule” and an “action” rule. In the example below, the block “action” is executed if Nmap detects an open HTTP port:

portrule = function(host, port)
    local svc = { std = { ["http"] = 1 } }
    if port.protocol ~= 'tcp' or not svc.std[port.service] then
        return false
    end
    return true
end

action = function(host, port)
    -- This block will be executed if the host has
    -- an open HTTP port
    string = ("Script output");
  return string
end

While started, Nmap loads the scripts (all of the available in the repository if “-sC” is given on the command line, or only the given ones via “–script=<scriptname>”). The script is parsed and if a portrule is present, saved in the porttests table with a portrule key and file closure value. Otherwise, if the script has a hostrule, it is saved in the hosttests table in the same manner. During the scan, a thread is created for each of the matching script-target combinations. More details about how scripts are implemented are available here.

Each thread contains detailed information such as the runlevel, target, port (if a porttest), host and port tables, and the script type (service or host script). The value returned by the “action” block will be printed in the Nmap output below the port:

Starting Nmap ( http://nmap.org )
Interesting ports on flog (127.0.0.1):
PORT     STATE SERVICE
80/tcp   open  http
|_ Script output

Nmap done: 1 IP address (1 host up) scanned in 0.50 seconds

Now, a few words about writing rules and documentation. You have to follow some basic rules. All Nmap scripts must start with description variables (the “header”):

description     = "This is a simple nmap script"
author          = "Xavier Mertens "
license         = "See http://nmap.org/book/man-legal.html"
categories      = { "default", "discovery", "safe" }
runlevel       = 1.0

The most important is categories. It describes the script behavior and can be a mix of the following keywords: auth, default, discovery, external, intrusive, malware, safe, version, and vuln. Check out the online documentation for a full description of each category.

If you check your <installprefix>/share/nmap/scripts directory you will find a lot of scripts ready to be used.

I wrote my first script: html-match.nse. Based on html-title.nse, if an open HTTP port is found, it grabs the HTML code and look for the provided string. It can be useful to detect compromised websites with malicious JavaScript code. Example:

nmap --script=html-match.nse \
     --script-args string='<script src=http://mcuve.cn/1.js>' \
     -p 80 x.y.z.0/24

As you can see, it’s possible to pass arguments to a Nmap script using ‘–script-args’. In the example above, Nmap will look for the string ‘<script src=http://mcuve.cn/1.js>’ into the home page of all web servers found in the subnet x.y.z.0/24. To conclude, the Nmap scripting engine is a wonderful tool to automate all boring tasks in a network environment.

2 comments

Leave a Reply

Your email address will not be published. Required fields are marked *