This chapter dives deep into the Nmap Scripting Engine (NSE), one of the most powerful features for penetration testers and a key exam topic under Recon Enumeration (Objective 2.2). You will learn how NSE works internally, how to use it effectively, and how to write custom scripts. Expect roughly 10-15% of exam questions to touch on NSE, often in scenarios requiring service enumeration, vulnerability detection, or custom automation. Mastery of NSE separates a basic Nmap user from an advanced penetration tester.
Jump to a section
Imagine a Swiss Army knife that comes with a set of pre-made tools — blades, screwdrivers, scissors — that you can use out of the box. But the knife also has an expansion slot where you can insert custom modules, each designed for a specific task like opening a particular type of lock or testing a specific material. Each module is a script that contains step-by-step instructions: first apply pressure here, then rotate 90 degrees, then listen for a click. The knife's handle has a sensor that reads the environment (like a port scan) and automatically selects the right module based on what it detects (e.g., if it sees a screw head, it picks the screwdriver module). If you want a new task, you write a new module and slide it into the slot. The knife doesn't just use the tools blindly — it can combine them, run them in sequence, and report back what it found. In the same way, NSE scripts are modular, event-driven, and can be chained. The NSE engine is the handle that provides common services (like socket handling, HTTP parsing, SSL negotiation) so each script doesn't need to reinvent the wheel. Just as a custom lock-picking module might fail if the lock is a different brand, an NSE script might fail if the target service doesn't match the expected banner — but the engine catches that gracefully and moves on.
What is NSE and Why Does It Exist?
The Nmap Scripting Engine (NSE) is a powerful extension that allows users to write and run scripts to automate a wide variety of networking tasks. Before NSE, Nmap was primarily a port scanner and OS/fingerprinting tool. With NSE, it becomes a full-fledged vulnerability scanner, service enumerator, and even a brute-forcing tool. The key motivation: penetration testers need to not only find open ports but also determine what services are running, their versions, and whether they have known vulnerabilities. NSE scripts can perform banner grabbing, SSL/TLS testing, brute-force attacks on authentication, and even exploit certain vulnerabilities.
How NSE Works Internally
NSE is built on the Lua programming language (version 5.3 in modern Nmap). Each script is a .nse file that contains a set of functions and rules. The NSE engine (the Nmap executable) loads scripts, parses their metadata (categories, dependencies, port rules), and executes them in parallel using a cooperative multitasking scheduler. The scheduler uses Lua coroutines — each script runs as a coroutine that can yield control back to the engine when waiting for network I/O. This allows hundreds of scripts to run concurrently without the overhead of threads or processes.
When Nmap starts with NSE enabled (e.g., via -sC or --script), it first performs the normal Nmap phases: target enumeration, host discovery, port scanning, and service/version detection. After that, it enters the script phase. The engine checks each script's prerule (a function that determines if the script should run before any scan), hostrule (runs once per host after scanning), portrule (runs per open port), or postrule (runs after all scans). Most scripts use portrule to target specific services (e.g., HTTP on port 80, SSH on port 22). The engine evaluates these rules and schedules scripts for execution.
Key Components, Values, and Defaults
Script Categories: NSE scripts are organized into categories like safe, default, discovery, auth, brute, intrusive, exploit, dos, fuzzer, malware, vuln, and external. The -sC flag runs all scripts in the default category. The safe category includes scripts that are unlikely to crash services or cause disruption. intrusive scripts may be noisy or disruptive. vuln scripts check for specific vulnerabilities.
Script Arguments: Many scripts accept arguments via the --script-args option. For example, --script-args=userdb=users.txt,passdb=pass.txt for brute-force scripts.
Script Database: Nmap ships with over 600 scripts. The script database file is scripts/script.db (a plain text file listing script names and their categories). You can update it with nmap --script-updatedb which downloads the latest scripts from the Nmap repository.
Default Scripts: The default category includes scripts that are considered safe and provide useful information. Running -sC is equivalent to --script=default.
Script Execution Order: Scripts are executed in parallel, but dependencies can be defined using the dependencies field in the script metadata. For example, a script that needs HTTP title extraction may depend on http-title.
Timing and Performance: NSE scripts are subject to Nmap's timing templates (-T0 to -T5). More aggressive timing reduces delays between script probes. The --script-timeout option sets a maximum time (in seconds) per script.
Configuration and Verification Commands
List all available scripts: ls /usr/share/nmap/scripts/ (or nmap --script-help to get descriptions).
Run default scripts: nmap -sC target or nmap --script=default target.
Run specific scripts: nmap --script=http-title,ssl-heartbleed target.
Run scripts by category: nmap --script=vuln target.
Run all scripts except intrusive: nmap --script "not intrusive" target.
Provide script arguments: nmap --script=http-brute --script-args=userdb=users.txt,passdb=pass.txt target.
Update script database: nmap --script-updatedb.
Write custom scripts: Scripts are stored in ~/.nmap/scripts/ or /usr/share/nmap/scripts/. After adding a script, run nmap --script-updatedb to register it.
How NSE Interacts with Related Technologies
Nmap Service Detection: NSE scripts often rely on Nmap's service detection (-sV) to determine which service is running on a port. The script's portrule can check the service name (e.g., port.service == "http").
Nmap OS Detection: Some scripts use OS detection results (-O) to tailor their behavior (e.g., Windows-specific checks).
SSL/TLS: The NSE library tls.lua provides functions for SSL/TLS handshakes, certificate parsing, and cipher suite testing. Scripts like ssl-enum-ciphers and ssl-heartbleed leverage this.
HTTP: The http.lua library handles HTTP requests, cookie management, and response parsing. Many web application scripts depend on it.
Brute-Force: NSE includes a brute library that provides a framework for writing brute-force scripts with threading, delay, and retry logic.
Writing Custom NSE Scripts
A basic NSE script has the following structure:
local nmap = require "nmap"
local shortport = require "shortport"
local stdnse = require "stdnse"
-- Rule to run only on open port 80
portrule = shortport.portnumber(80, "tcp")
-- Action function
action = function(host, port)
local socket = nmap.new_socket()
socket:connect(host, port)
socket:send("GET / HTTP/1.0\r
\r
")
local response = socket:receive_lines(1)
socket:close()
return response
endThis script connects to port 80, sends an HTTP GET request, and returns the first line of the response. For the exam, you should understand the structure: description (metadata), author, license, categories, portrule, and action.
Advanced Scripting Concepts
Dependencies: A script can declare dependencies on other scripts. For example, http-title depends on http-headers to ensure headers are fetched first.
Running Scripts in Parallel: NSE's coroutine-based model means scripts run concurrently. You can control parallelism with --max-scan-delay and --min-rate.
Script Output: Scripts return strings or tables. The NSE engine formats output into the standard Nmap output (normal, XML, grepable). Use stdnse.format_output for structured output.
Error Handling: Use nmap.registry to share data between scripts. Use stdnse.debug for debugging.
Common NSE Scripts for PenTesting
http-title: Grabs the title of a web page. Useful for identifying web applications.
http-enum: Enumerates directories and files on a web server using a wordlist.
ssl-heartbleed: Checks for the Heartbleed vulnerability (CVE-2014-0160).
smb-enum-shares: Enumerates SMB shares on Windows systems.
ftp-anon: Checks if FTP anonymous login is allowed.
mysql-empty-password: Checks for MySQL accounts with empty passwords.
dns-brute: Brute-forces DNS subdomains.
vuln: Category including many vulnerability checks like ms17-010 (EternalBlue).
NSE Performance Considerations
Running many scripts can be slow. Use --script-timeout to limit each script's runtime (default is 10 minutes). The --script-trace option shows detailed script execution (useful for debugging). For large scans, consider running only safe scripts first, then vuln on identified services.
NSE and the Exam
The PT0-002 exam expects you to know:
How to run NSE scripts (-sC, --script).
Common script categories and their safety levels.
How to provide script arguments.
How to update the script database.
How to write a basic custom script (structure: description, portrule, action).
The difference between safe and intrusive scripts.
How to use NSE for service enumeration and vulnerability detection.
Trap: Candidates often confuse -sC (default scripts) with -sV (version detection). Remember: -sC is for scripts, -sV is for version detection. Another trap: using --script=all runs every script, including intrusive ones that may crash services or trigger alarms. In a pentest, you typically start with safe and escalate.
Identify Target and Port Scan
Begin by running a standard Nmap scan to discover live hosts and open ports. Use `nmap -sn 192.168.1.0/24` for ping sweep, then `nmap -p- 192.168.1.10` for full port scan. This step is crucial because NSE scripts run after port discovery; without open ports, most scripts will not execute. The engine evaluates port rules only for ports marked as open or filtered. You can combine with `-sV` to detect service versions, which many scripts use to tailor their probes. For example, `nmap -sV -p 80,443 target` will detect HTTP/HTTPS and then NSE scripts like `http-title` will automatically target those ports.
Run Default NSE Scripts
Execute `nmap -sC target` to run all scripts in the `default` category. This includes safe scripts like `http-title`, `ssh-hostkey`, `ssl-cert`, and `banner`. The engine loads each script, evaluates its `portrule` against the scan results, and runs matching scripts concurrently. Output is interleaved in the console but structured in XML. On the exam, remember that `-sC` is equivalent to `--script=default`. Common mistake: thinking `-sC` runs all scripts — it only runs the `default` category. To run all scripts, you'd use `--script=all` (not recommended in production).
Run Category-Specific Scripts
Use `--script=vuln` to check for known vulnerabilities, or `--script=safe` for non-disruptive enumeration. For example, `nmap --script=vuln target` will run all scripts in the `vuln` category, such as `ssl-heartbleed`, `ms17-010`, and `http-shellshock`. The engine filters scripts by category metadata. You can combine categories: `--script=default,safe` or exclude: `--script "not intrusive"`. On the exam, know that `intrusive` scripts may cause service crashes or log alerts, so they are avoided in stealthy engagements.
Provide Script Arguments
Many scripts accept arguments to customize behavior. For instance, `http-brute` needs a username and password list: `nmap --script=http-brute --script-args=userdb=users.txt,passdb=pass.txt target`. Arguments are passed as key=value pairs, separated by commas. The engine parses these and makes them available to scripts via `nmap.registry.args`. On the exam, expect questions about how to pass arguments, especially for brute-force scripts. Trap: forgetting to quote paths with spaces, or using `--script-args` without the `=` sign (correct: `--script-args=userdb=users.txt`).
Analyze Output and Iterate
Review the NSE output to identify services, versions, and potential vulnerabilities. For example, if `http-title` returns "Welcome to Apache Tomcat", you might then run `tomcat-default-logins`. If a vulnerability is found (e.g., Heartbleed), you can proceed to exploitation. The output includes script names and their results. Use `-oX` to save XML for parsing. On the exam, you may be asked to interpret NSE output to determine the next step. For instance, if `smb-enum-shares` shows a writable share, the next step might be to upload a payload.
Enterprise Scenario 1: Internal Network Penetration Test
A pentester is engaged to assess an internal network with 500 hosts. The goal is to identify vulnerable services without causing disruption. The pentester starts with a ping sweep (nmap -sn 10.0.0.0/16) to find live hosts, then runs a TCP SYN scan on top 1000 ports (nmap -sS -T4 --top-ports 1000 10.0.0.0/16 -oA initial). After identifying open ports, the pentester runs NSE default scripts (-sC) on each host. This reveals that several Windows servers have SMB signing disabled (smb-security-mode), a web server is running Apache 2.4.49 (vulnerable to path traversal via http-vuln-cve2021-41773), and an FTP server allows anonymous login (ftp-anon). The pentester then runs --script=vuln on those specific hosts to confirm vulnerabilities. The NSE output is saved as XML and imported into a reporting tool. Scale: scanning 500 hosts with default scripts takes about 30 minutes with -T4. Performance consideration: using --max-scan-delay 1000 prevents overwhelming the network. Misconfiguration: running --script=all would have included dos scripts that could crash services, alerting the blue team prematurely.
Enterprise Scenario 2: External Web Application Assessment
A pentester targets a public-facing web application. After discovering open ports 80 and 443, they run NSE scripts against the web server: nmap -p 80,443 --script=http-* target. This runs all HTTP-related scripts, including http-enum (directory brute-force), http-headers, http-methods, http-csrf, http-xssed, and http-sql-injection. The http-enum script uses a wordlist to find hidden directories like /admin and /backup. The http-methods script checks for dangerous HTTP methods (e.g., PUT, DELETE). The http-sql-injection script attempts basic SQL injection payloads. The pentester finds that the server allows PUT on /uploads, allowing file upload. They then use http-put script (custom) to upload a test file. Common pitfall: running http-sql-injection on a login page may cause account lockouts due to failed login attempts. The pentester should first run safe scripts, then intrusive ones with caution.
Enterprise Scenario 3: Cloud Environment (AWS)
A pentester is testing an AWS VPC. Since Nmap scans can be noisy and may trigger IDS/IPS, they use a stealthy approach: nmap -sS -T2 --script=default --script-args=userdb=users.txt target. They focus on a single instance to minimize logs. The default scripts reveal an open Redis port (6379) without authentication (redis-info). The pentester then runs redis-brute to guess the password. They also run ssl-enum-ciphers on port 443 to check for weak ciphers. In cloud environments, NSE scripts like http-enum can be used to enumerate S3 buckets if the web application leaks bucket names. Performance: scanning across the internet requires careful timing to avoid rate limiting. Misconfiguration: forgetting to exclude the Nmap scanner's own IP from the target list (e.g., scanning a subnet that includes the scanner's own host).
The PT0-002 exam tests NSE under Objective 2.2 (Recon Enumeration) and also within vulnerability scanning (Objective 3.1). Expect 3-5 questions directly referencing NSE. Key areas:
Script Categories: Know the difference between safe, default, intrusive, vuln, exploit. The exam loves to ask: 'Which script category would you use to avoid disrupting services?' Answer: safe. Another: 'Which category includes scripts that may crash services?' Answer: intrusive.
Command Syntax: You must know -sC (default scripts), --script=<script>, --script-args=<args>, --script-updatedb. Trap: The exam may show --script=default and -sC as equivalent. Another trap: -sV is version detection, not scripts.
Common Scripts: Be familiar with http-title, ssl-heartbleed, smb-enum-shares, ftp-anon, dns-brute, http-enum. The exam may describe a scenario and ask which script to use. For example: 'You find an open SMB port. Which script enumerates shares?' Answer: smb-enum-shares.
Custom Script Structure: The exam may show a partial Lua script and ask what is missing or what the portrule does. Remember that portrule returns true/false to determine if the script runs on that port. The action function returns the output.
Performance and Timing: Know that --script-timeout limits script runtime (default 10 minutes). -T4 increases speed but may cause dropped packets. The exam may ask: 'Which option prevents a script from hanging indefinitely?' Answer: --script-timeout.
Common Wrong Answers:
Choosing -sV when the question asks for service enumeration via scripts.
Thinking -sC runs all scripts.
Believing that NSE scripts can only be run after a full port scan (they can be run with just a target, but they rely on port scan results).
Confusing --script with --script-args.
Edge Cases:
If no open ports are found, most scripts won't run (except those with prerule or hostrule).
Scripts can be run against hosts that are down if using -Pn (skip host discovery).
The external category scripts may send data to third-party services (e.g., whois lookups).
How to Eliminate Wrong Answers: Read the scenario carefully. If it mentions 'stealth' or 'avoid disruption', eliminate intrusive and exploit categories. If it mentions 'vulnerability check', look for vuln category or specific script names. If it mentions 'custom script', look for Lua code. If it mentions 'update', look for --script-updatedb. If it mentions 'arguments', look for --script-args.
NSE scripts are written in Lua and stored in .nse files.
The `-sC` flag runs all scripts in the `default` category.
Categories include `safe`, `default`, `intrusive`, `vuln`, `exploit`, `auth`, `brute`, `dos`, `fuzzer`, `malware`, `discovery`, and `external`.
Use `--script=<script-name>` to run a specific script.
Script arguments are passed with `--script-args=key=value`.
Update the script database with `nmap --script-updatedb`.
The `portrule` function determines if a script runs on a given port.
The `action` function returns the script's output.
NSE scripts run concurrently using Lua coroutines.
Default timeout per script is 10 minutes; use `--script-timeout` to change it.
These come up on the exam all the time. Here's how to tell them apart.
NSE (Nmap Scripting Engine)
Automates hundreds of tests with a single command.
Built-in parallel execution via coroutines.
Over 600 pre-written scripts for common tasks.
Structured output (XML, grepable) for reporting.
Can be extended with custom Lua scripts.
Manual Testing with Netcat/OpenSSL
Requires manual commands for each test (e.g., `nc -v target port`).
Single-threaded; must script loops in bash.
No pre-built library; must know exact probes.
Output is raw text; parsing is manual.
No built-in framework; reinventing the wheel.
Mistake
-sC runs all available NSE scripts.
Correct
-sC only runs scripts in the `default` category, which is a curated set of safe and useful scripts. To run all scripts, you need `--script=all`, which includes intrusive and potentially disruptive scripts.
Mistake
NSE scripts can only be run after a full port scan.
Correct
NSE scripts can be run at any time, but they rely on Nmap's scan results. If you run `nmap --script=http-title target` without a port scan, Nmap will first perform a default port scan (top 1000 ports) to find open ports. You can also provide a list of ports with `-p` to limit scanning.
Mistake
NSE scripts are written in Python.
Correct
NSE scripts are written in Lua (version 5.3). Nmap embeds a Lua interpreter. Python is not used for NSE; however, Nmap can be controlled via Python using the python-nmap library, but that is not NSE.
Mistake
Running `--script=default` is the same as `-sV`.
Correct
`-sV` enables version detection, which probes services to determine exact version numbers. `-sC` (or `--script=default`) runs NSE scripts. They are separate features, though often used together (`-sCV`). The exam tests this distinction.
Mistake
You cannot run a single script without running others.
Correct
You can run a single script by specifying its name: `nmap --script=http-title target`. Only that script will execute, along with any scripts it depends on. Dependencies are automatically resolved.
Reveal each answer, then mark whether you got it right. Score 60%+ to unlock the next chapter.
Use `nmap --script=vuln target`. This runs every script categorized as `vuln`. You can combine categories with commas, e.g., `--script=vuln,safe`. To exclude a category, use `--script "not intrusive"`. Remember that `vuln` scripts are generally safe but may send exploit-like payloads that could trigger IDS.
There is no difference. `-sC` is a shorthand for `--script=default`. Both run the scripts in the `default` category. The exam uses both notations, so you must recognize them as equivalent. Never confuse `-sC` with `-sV` (version detection).
Create a .nse file in `~/.nmap/scripts/` or `/usr/share/nmap/scripts/`. The script must define a `description` table (with `description`, `author`, `license`, `categories`), a `portrule` function (returns true/false), and an `action` function (returns output). Example: `portrule = shortport.portnumber(80, "tcp")` and `action = function(host, port) return "Hello" end`. Then run `nmap --script-updatedb` and use `--script=yourscript`.
Yes. NSE includes a `brute` library and many scripts like `http-brute`, `ssh-brute`, `mysql-brute`, `smb-brute`. Use `--script-args=userdb=users.txt,passdb=pass.txt` to provide wordlists. These scripts are in the `brute` category and are considered `intrusive` because they generate many login attempts. On the exam, know that brute-force scripts require argument files.
It sets the maximum time (in seconds) that a single script can run before being terminated. Default is 600 seconds (10 minutes). Use `--script-timeout 30s` to limit to 30 seconds. This prevents a hanging script from delaying the entire scan. The exam may ask which option prevents indefinite hangs.
Run `nmap --script-updatedb`. This downloads the latest scripts from the Nmap repository and updates the `scripts/script.db` file. You need internet access. On the exam, this is the correct answer for 'how to get the latest scripts'.
Possible reasons: (1) The target has no open ports that match the script's `portrule`. (2) The script's category was excluded (e.g., you used `--script=safe` but the script is `intrusive`). (3) The script has unmet dependencies. (4) You forgot to run `--script-updatedb` after adding a custom script. Check with `--script-trace` for debugging.
You've just covered Advanced Nmap: Scripting Engine (NSE) — now see how well it sticks with free PT0-002 practice questions. Full explanations included, no account needed.
Done with this chapter?