Welcome back! In our previous lesson, we outlined the five phases of the penetration testing lifecycle: Reconnaissance, Scanning, Exploitation, Post-Exploitation, and Reporting. Now, we are moving from theory into practice by entering the Scanning phase. While reconnaissance involves gathering passive information, scanning is where we actively interact with the target system to identify potential entry points.
To do this, we will use Nmap (Network Mapper), the industry standard for network discovery and security auditing. Nmap allows us to map out a network, finding which hosts are up and what services they are offering. In this lesson, we will use Nmap to scan our target "Pastebin" application, discover that it is running on port 3000, identify it as a Node.js application, and uncover specific configuration weaknesses that an attacker could exploit.
The first step in analyzing a specific machine is identifying which ports are open. Think of an IP address as a house address and ports as the doors and windows. To enter the house, you first need to know which doors are unlocked. In networking terms, a port is a communication endpoint; if a port is "open," it means a service (like a web server or database) is listening for connections.
We need to scan ports because every open port represents a potential attack surface. If we miss an open port, we might miss the only vulnerable service on the machine. Therefore, it is best practice to scan all possible ports to ensure we have a complete picture of the target.
Here is how we perform a comprehensive port scan using Nmap:
Let's break down this command:
nmap: The command to run the tool.-p-: This tellsNmapto scan all 65,535TCPports, not just the most common 1,000.--min-rate=1000: This instructsNmapto send packets at a rate of at least 1,000 per second, significantly speeding up the scan. Be cautious about setting this value too high; an excessively fast scan rate can reduce accuracy, potentially causingNmapto misidentify or skip ports entirely.localhost: The target we are scanning.
In the CodeSignal environment, this scan will run quickly. You might see output similar to this:
This output tells us that Port 3000 is open. Nmap guesses the service name based on standard assignments (in this case, it might guess ppp or hbci), but this is just a guess based on the port number. To know what is actually running, we need more advanced commands.
Finding an open port is only the first step; we need to know exactly what software is listening on that port. This is called Service Version Detection. Simply knowing that "something" is on port 3000 isn't enough to plan an attack. We need to know if it is an Apache server, a Python script, or a Node.js application.
This information is critical because vulnerabilities are often specific to software versions. If we identify that a target is running an outdated version of a specific library, we can look up known exploits (CVEs) for that exact version. Without version detection, we are essentially guessing in the dark.
To perform version detection, we use the -sV flag:
Here, we specified -p 3000 to focus only on the port we discovered earlier, saving time. The -sV flag probes the open port and analyzes the response to determine the service details.
The output has now changed significantly. Nmap correctly identified the service as http and the version as Node.js Express framework. This is valuable intelligence: we now know the technology stack we are dealing with.
Nmap is not just a port scanner; it is also a powerful scripting engine. The Nmap Scripting Engine (NSE) allows users to write and share scripts that automate a wide variety of networking tasks, from advanced version detection to vulnerability exploitation.
Using the default scripts is a standard part of the scanning workflow. We enable the default script set using the -sC flag, which is equivalent to --script=default. It is common to combine this with version detection:
The -sC flag runs a collection of scripts that are considered useful for discovery. However, note that some scripts in this default category are considered intrusive — always ensure you have explicit written permission before running them against any target. When run against our Pastebin app, the output provides even more detail:
The script http-title successfully grabbed the title of the webpage ("Pastebin"). This confirms that the service is indeed a web application and gives us a hint about its purpose.
Since we confirmed the target is a web application running on HTTP, we can use scripts specifically designed for web reconnaissance. HTTP Enumeration involves digging deeper into the web server's configuration to find hidden folders, supported commands, and technology headers.
We specifically want to check which HTTP Methods (like GET, POST, DELETE) are supported. If a server supports dangerous methods like PUT or DELETE on public endpoints, an attacker might be able to upload malicious files or delete legitimate data. We also look for Headers that leak information about the server's internal setup.
We can invoke specific scripts using the --script argument:
The output identifies several key pieces of information:
This scan reveals the X-Powered-By: Express header, which confirms the server technology and makes it easier for attackers to tailor their exploits.
Because our application runs on the non-standard port 3000, Nmap cannot reliably identify the service as HTTP and the http-methods script will not execute. In this situation, use curl directly to probe which methods the server accepts:
A 200 response means PUT is accepted — an unnecessary risk. A 405 means it is properly blocked. This reveals a critical finding: the server accepts dangerous methods like PUT on the /api/snippets route. If these are not properly secured, we might have found a way to compromise the application's data.
In a professional penetration test, if you didn't document it, it didn't happen. Documentation is vital for creating the final report and for proving that you performed the assessment thoroughly. You should never rely on just scrolling back through your terminal history to find results.
Nmap provides a feature to output scans in three different formats simultaneously: Normal (readable text), XML (for importing into other tools), and Grepable (for easy searching via command line). We use the -oA (Output All) flag for this.
This command runs the scan and creates three files: pastebin_scan.nmap, pastebin_scan.xml, and pastebin_scan.gnmap. Having these files ensures you have concrete evidence of your findings, which you can later attach to your report or parse with other automation tools.
As a penetration tester, your job isn't just to break things; it's to help fix them. Now that we have identified that our application leaks information via headers and supports potentially dangerous methods, we need to apply defense-in-depth measures.
The first issue we found was the X-Powered-By header. This is a form of information leakage. While removing it doesn't fix a vulnerability, it makes fingerprinting harder for automated bots. In Express, we can disable this with a single line of code. We can also use a library called Helmet, which automatically sets various HTTP headers to secure the app.
Here is how we secure the application setup in src/server/index.ts:
The second issue was the presence of unsecured HTTP methods. Specifically, PUT has no business purpose in this application and should be blocked. While DELETE is legitimately needed for users to remove their snippets, it should only be permitted on routes that explicitly handle it. We can write middleware to reject any method that has no defined role on a given route.
By implementing these changes, a subsequent Nmap scan would show fewer headers and restricted methods, indicating a more hardened target.
In this lesson, we utilized Nmap to perform the Scanning phase of our penetration test. We started with a broad port scan (-p-), narrowed down our target with version detection (-sV), and used the Nmap Scripting Engine (-sC and --script) to uncover specific web vulnerabilities. We also learned the importance of documenting our work with -oA.
Finally, we wore our "defender hat" and learned how to mitigate these discoveries in a Node.js application by disabling banner headers and restricting HTTP methods. In the upcoming practice exercises, you will run these scans yourself against a live environment and implement the code fixes to secure the application.
