> your AI agent picks dependencies from memory; give it dated facts — try starlog.dev ↗ vet your agent's deps ↗ vibe-coding is fine. vibe-importing isn’t. — try starlog.dev ↗ vibe-importing isn’t fine ↗ your agent has never seen your private packages — try starlog.dev ↗ facts for private packages ↗ a linter for the dependencies your AI agent picks — try starlog.dev ↗ a linter for agent deps ↗

Back to Articles

Gnmap-Parser: Why Security Teams Still Reach for Shell Scripts Over Modern JSON Parsers

[ View on GitHub ]

Gnmap-Parser: Why Security Teams Still Reach for Shell Scripts Over Modern JSON Parsers

Hook

In an era of microservices and JSON APIs, one of the most effective Nmap post-processing tools is a 300-line shell script that exclusively outputs plain text files.

Context

Penetration testers and security researchers face a recurring problem: after running multiple Nmap scans across different network segments, they end up with dozens of .gnmap files scattered across various directories. Each file contains valuable reconnaissance data, but extracting actionable intelligence requires tedious manual work—copying hosts into lists, identifying which systems have specific ports open, or generating input files for follow-up tools like screenshot utilities or vulnerability scanners.

Nmap offers three output formats (normal, XML, and greppable), and while XML has become the de facto standard for tool integration, the greppable format (.gnmap) was specifically designed for command-line text processing. Despite being less feature-rich than XML, the greppable format's consistent line structure makes it ideal for awk, grep, and sed operations. Gnmap-Parser emerged from this reality: security professionals who live in the terminal needed a lightweight way to aggregate and transform scan results without spinning up Python environments or writing one-off parsers for each engagement. The tool embodies the Unix philosophy—do one thing well, use text streams, and compose with other tools.

Technical Insight

Output Generation

Parsing Engine

Gathering Phase

copy files

copy files

concatenate

extract & filter

extract & filter

extract & filter

extract & filter

.gnmap Files

Extension Mode

find *.gnmap

Heuristic Mode

grep headers

Working Directory

Nmap-Files/

Text Processing

grep + awk

Host Lists

Port Inventories

CSV Matrices

Tool-Specific Formats

System architecture — auto-generated

Gnmap-Parser's architecture is deceptively simple but reveals thoughtful design decisions about file discovery, data extraction, and output generation. The script operates in two distinct phases: gathering and parsing, each optimized for different use cases.

The gathering phase addresses a practical problem: security professionals often run scans from multiple locations and need to consolidate results. The script offers two collection modes. The default mode uses file extension matching to recursively copy .gnmap files into a working directory:

find "$1" -name '*.gnmap' -exec cp {} Nmap-Files/ \;

This approach is fast but rigid—it only recognizes files with the .gnmap extension. The alternative heuristic mode examines file content rather than extension, searching for Nmap's characteristic header signature. This flexibility comes at a performance cost since it must read every file, but it catches improperly named scan outputs that would otherwise be missed.

The parsing engine is where the tool demonstrates the power of greppable format. Each line in a .gnmap file follows a predictable structure: "Host: IP (HOSTNAME) Status: STATE" followed by port information. This consistency enables targeted extraction using grep and awk patterns. For example, to extract all alive hosts, the script uses:

cat Nmap-Files/*.gnmap | grep "Status: Up" | awk '{print $2}' | sort -u > Alive-Hosts-ICMP.txt

This single pipeline accomplishes four operations: concatenate all scan files, filter for live hosts, extract IP addresses from the second field, and deduplicate with sorted output. The result is a clean list ready for import into other tools or further reconnaissance.

Port extraction demonstrates more sophisticated text processing. Since greppable format lists ports as "Ports: 80/open/tcp//http///," the script parses this structure to generate port-specific host lists:

cat Nmap-Files/*.gnmap | grep "Ports:" | grep "22/open" | awk '{print $2}' > Hosts-With-Port-22.txt

Gnmap-Parser generates multiple output formats simultaneously, including port matrices (CSV files showing which hosts have which ports open) and tool-specific inputs. The PeepingTom format, for instance, creates properly formatted URLs for web screenshot tools:

for port in 80 443 8080 8443; do
  grep "$port/open" combined.gnmap | awk -v p="$port" '{print "http://"$2":"p}' >> peepingtom.txt
done

This workflow automation is where gnmap-parser shines—it transforms raw scan data into actionable inputs for the next phase of testing without manual intervention. A pentester can run their scans, execute gnmap-parser, and immediately feed the generated lists into tools like Eyewitness, Aquatone, or custom scripts.

The script's output organization is methodical: separate files for alive hosts (by discovery method), port-specific host lists, service inventories, and various matrix formats. This multi-format approach acknowledges that different analysis tasks require different data views. A quick host count needs a simple list, while vulnerability correlation might need the CSV matrix showing port distributions across the network.

Gotcha

The tool's most significant limitation is its file-centric workflow. Gnmap-Parser must copy all .gnmap files into its working directory before parsing—it cannot process files in place. For large engagements with hundreds of scan files totaling gigabytes, this duplication consumes unnecessary disk space and adds I/O overhead. Modern tools that stream-process files or work with databases would handle this more efficiently.

The plain-text output format, while human-friendly, creates integration challenges with modern security platforms. Contemporary SIEM systems, vulnerability management platforms, and security orchestration tools expect structured data (JSON, XML) or direct API integrations. Feeding gnmap-parser's text files into these systems requires additional transformation layers. Additionally, the tool provides no filtering or query capabilities—you get all results for all hosts. If you need conditional extraction (e.g., "show me hosts with port 445 open but only if they also have 139 closed"), you'll need to write additional shell logic or use a more sophisticated parser with query capabilities. The lack of error handling means malformed .gnmap files could produce incomplete or incorrect output without clear warnings.

Verdict

Use if: You're conducting penetration tests or red team engagements where you need rapid, ad-hoc analysis of Nmap results across multiple scan files, especially when generating input lists for follow-up reconnaissance tools. It's ideal for terminal-centric workflows where piping text files between utilities is natural, and when you need multiple output formats (host lists, port matrices, tool inputs) generated simultaneously without writing custom parsers. The tool excels in air-gapped or resource-constrained environments where installing Python dependencies or complex parsing frameworks isn't practical. Skip if: You're building automated security pipelines that require structured data formats like JSON for programmatic processing, need real-time stream processing of scan results without file duplication, or require conditional filtering and complex queries beyond simple pattern matching. Also avoid if you're integrating with modern security orchestration platforms that expect API-based interactions rather than text file imports, or if your scans produce files too large for practical duplication into a working directory.