Back to Articles

gograbber: When Pentesting Tools Choose Speed Over Polish

[ View on GitHub ]

gograbber: When Pentesting Tools Choose Speed Over Polish

Hook

Most web enumeration tools scan deep into a single domain. gograbber does the opposite—it scans wide across entire network ranges, combining three separate pentesting workflows into one concurrent pipeline that treats speed as a feature, not a bug.

Context

Traditional web application security testing follows a sequential workflow: first you scan for open ports with nmap, then you enumerate directories with gobuster or dirbuster, and finally you capture screenshots with tools like EyeWitness or aquatone. Each step requires managing output from the previous tool, correlating results across different formats, and maintaining context about which findings belong to which hosts.

This fragmentation becomes exponentially more painful during network penetration tests where you’re dealing with CIDR ranges containing dozens or hundreds of potential web servers. You might discover 50 hosts with port 80 or 443 open, but only 30 actually serve HTTP content. Of those 30, perhaps 20 have meaningful directory structures to enumerate. The context-switching between tools, the manual correlation of results, and the repetitive setup of each tool for each discovered service creates friction that slows down reconnaissance phases. gograbber emerged from this frustration, attempting to collapse the entire workflow into a single concurrent pipeline that maintains context from port discovery through screenshot capture.

Technical Insight

Concurrency Control

Open ports

Valid paths

Confirmed findings

Controls

Controls

Input Parser

URLs/IPs/CIDR

Port Scanner

Concurrent Goroutines

Directory Enumerator

Gobuster-style

Soft-404 Detector

Wildcard Filter

PhantomJS

Screenshot Capture

Output Generator

Markdown + Text

Semaphore

Rate Limiter

System architecture — auto-generated

gograbber’s architecture revolves around a three-stage concurrent pipeline: host discovery and port scanning, directory enumeration on discovered services, and screenshot capture of findings. The tool accepts remarkably flexible input—individual URLs, hostnames, IP addresses, or CIDR ranges—and normalizes everything into a common format for processing.

The port scanning stage demonstrates Go’s concurrency model effectively. Rather than blocking on each host sequentially, gograbber spawns goroutines for each target and uses channels to aggregate results. Here’s the conceptual flow:

// Simplified illustration of gograbber's concurrent scanning approach
func scanHosts(targets []string, ports []int) <-chan ScanResult {
    results := make(chan ScanResult)
    var wg sync.WaitGroup
    
    // Semaphore pattern to limit concurrent connections
    sem := make(chan struct{}, maxThreads)
    
    for _, target := range targets {
        for _, port := range ports {
            wg.Add(1)
            go func(host string, p int) {
                defer wg.Done()
                sem <- struct{}{}        // Acquire
                defer func() { <-sem }() // Release
                
                if isPortOpen(host, p) {
                    results <- ScanResult{
                        Host: host,
                        Port: p,
                        Service: identifyService(host, p),
                    }
                }
            }(target, port)
        }
    }
    
    go func() {
        wg.Wait()
        close(results)
    }()
    
    return results
}

This pattern appears throughout gograbber—spawn goroutines aggressively, but gate them with semaphores to prevent resource exhaustion. The configurable thread counts for different operations (scanning, enumeration, screenshots) acknowledge that these operations have different resource profiles: network I/O-bound scanning can sustain higher concurrency than CPU-intensive screenshot rendering.

The directory enumeration stage borrows heavily from gobuster’s design patterns. For each discovered web service, gograbber performs wordlist-based bruteforcing while implementing soft-404 detection—a critical feature for dealing with wildcard responses. Many web applications return 200 OK with a generic error page instead of proper 404 responses, which would otherwise flood results with false positives. gograbber establishes a baseline by requesting randomized non-existent paths, fingerprints the response (status code, content length, specific strings), and filters subsequent findings that match this baseline pattern.

The screenshot integration via PhantomJS represents both the tool’s ambition and its Achilles’ heel. PhantomJS, a headless WebKit browser, was deprecated in 2018 after Chrome and Firefox introduced their own headless modes. Yet gograbber’s dependency on it reflects a specific design choice: PhantomJS was easier to embed as a standalone binary without requiring complex browser installations. The tool shells out to PhantomJS for each discovered service, capturing rendered screenshots that help analysts quickly triage which services warrant deeper investigation.

The output format reveals gograbber’s intended audience: penetration testers writing reports. Rather than JSON or XML, it generates markdown files with embedded screenshots and greppable text files. This design choice prioritizes human readability and copy-paste integration into pentest reports over machine parsing. The markdown output includes tables of discovered services, directory listings organized by host, and inline screenshot references—essentially pre-formatted report sections.

One particularly clever aspect is the context preservation throughout the pipeline. When gograbber discovers a directory on a specific host and port, that context flows through to the screenshot filename and markdown output, making it trivial to correlate findings without manual cross-referencing. This seems obvious but represents a genuine improvement over chaining separate tools where you’re constantly matching IP addresses and ports across different output formats.

Gotcha

The PhantomJS dependency isn’t just a maintenance concern—it’s a practical liability. PhantomJS hasn’t received security updates since 2018, uses an outdated WebKit engine that renders modern JavaScript frameworks incorrectly, and fails outright on sites requiring contemporary browser features. During testing against modern web applications using React, Vue, or Angular, you’ll frequently encounter blank screenshots or JavaScript errors because PhantomJS can’t execute ES6+ code. This defeats the primary purpose of screenshot capture: quickly identifying what’s running on discovered services.

The ‘pre-alpha’ stability warning in the README isn’t false modesty. Users report crashes during large network scans, inconsistent behavior with certain web server configurations, and minimal error handling that makes debugging failures difficult. The tool assumes cooperative network conditions and well-behaved web servers. Edge cases like servers with extremely slow response times, unusual TLS configurations, or aggressive rate limiting can cause goroutines to hang indefinitely because timeout handling is rudimentary. There’s no graceful degradation—gograbber either completes successfully or fails in ways that require reading stack traces to diagnose. For production penetration testing where reliability and consistent results matter, this instability is disqualifying regardless of the tool’s conceptual elegance.

Verdict

Use if: You’re conducting time-boxed network penetration tests against IP ranges (not single domains), you need quick visual triage of discovered services across dozens of hosts, you’re comfortable working with unstable tooling and debugging failures, and you’re already managing PhantomJS in your toolkit for other legacy tools. The combined horizontal and vertical enumeration genuinely saves time when scanning large internal networks where you expect many hosts but don’t know which have interesting content. Skip if: You need production-stable tooling with active maintenance, you’re testing modern web applications that require current browser engines for accurate rendering, you’re doing deep enumeration of a single domain (gobuster and aquatone are more focused), or you can’t accept the security and compatibility implications of depending on an orphaned project. For most use cases, chaining httpx with nuclei and using a modern screenshot tool like GoWitness provides better reliability and maintainability despite requiring more setup.

// ADD TO YOUR README
[![Featured on Starlog](https://starlog.is/api/badge/automation/swarley7-gograbber.svg)](https://starlog.is/api/badge-click/automation/swarley7-gograbber)