Skip to content

Use as a library

Vsevolod Djagilev edited this page May 2, 2022 · 4 revisions

It's possible to write golang code that allows to parse nmap xml and convert it to any format you want, or use parsed information further:

Convert to JSON using golang

package main

import (
	"encoding/xml"
	"os"

	"github.com/vdjagilev/nmap-formatter/formatter"
)

func main() {
	var nmap formatter.NMAPRun
	var config formatter.Config = formatter.Config{}

	// Read XML file that was produced by nmap (with -oX option)
	content, err := os.ReadFile("example.xml")
	if err != nil {
		panic(err)
	}
	// Unmarshal XML and map structure(s) fields accordingly
	if err = xml.Unmarshal(content, &nmap); err != nil {
		panic(err)
	}

	// Output data to console stdout
	// You can use any other io.Writer implementation
	// for example: os.OpenFile("file.json", os.O_CREATE|os.O_EXCL|os.O_WRONLY, os.ModePerm)
	config.Writer = os.Stdout
	// Formatting data to JSON, you can use:
	// CSVOutput, MarkdownOutput, HTMLOutput as well
	config.OutputFormat = formatter.JSONOutput

	// Setting formatter data/options
	templateData := formatter.TemplateData{
		NMAPRun: nmap, // NMAP output data itself
		OutputOptions: formatter.OutputOptions{
			JSONOptions: formatter.JSONOutputOptions{
				PrettyPrint: true, // Additional option to prettify JSON
			},
		},
	}

	// New formatter instance
	formatter := formatter.New(&config)
	if formatter == nil {
		// Not json/markdown/html/csv
		panic("wrong formatter provided")
	}

	// Attempt to format the data
	if err = formatter.Format(&templateData, "" /* no template content for JSON */); err != nil {
		// html template could not be parsed or some other issue occured
		panic(err)
	}
}

Use NMAPRun struct

In this example we parse example.xml, go through all hosts that are online, filtering out only those ports that have http services running. After that we attempt to make a request to that service via http, if that fails there is another attempt made to make a request via https, if that still fails we print those errors and continue to the next request.

package main

import (
	"encoding/xml"
	"fmt"
	"log"
	"net/http"
	"os"

	"github.com/vdjagilev/nmap-formatter/formatter"
)

func sendRequest(address string, port int, https bool) (*http.Response, error) {
	schema := "http"
	if https {
		schema = "https"
	}
	resp, err := http.Get(fmt.Sprintf("%s://%s:%d", schema, address, port))
	if err != nil {
		// I guess we fail
		return nil, err
	}
	return resp, err
}

func main() {
	var nmap formatter.NMAPRun
	// var config formatter.Config = formatter.Config{}

	// Read XML file that was produced by nmap (with -oX option)
	content, err := os.ReadFile("example.xml")
	if err != nil {
		panic(err)
	}
	// Unmarshal XML and map structure(s) fields accordingly
	if err = xml.Unmarshal(content, &nmap); err != nil {
		panic(err)
	}

	for _, host := range nmap.Host {
		// If host is up and receiving connections
		if host.Status.State == "up" {
			// Iterating over all ports on that host
			for _, port := range host.Port {
				// If this port is has http service on it
				if port.Service.Name == "http" {
					resp, err := sendRequest(host.HostAddress.Address, port.PortID, false)
					if err != nil {
						log.Printf("Fail http: %s:%d: %v", host.HostAddress.Address, port.PortID, err)
						// Attempt https then
						resp, err = sendRequest(host.HostAddress.Address, port.PortID, true)
						if err != nil {
							// Still fail, no point in continuing
							log.Printf("Fail https: %s:%d: %v", host.HostAddress.Address, port.PortID, err)
							continue
						}
					}
					defer resp.Body.Close()

					log.Printf("Req: %s:%d --->", host.HostAddress.Address, port.PortID)
					log.Printf("Res: %s:%d: %d <---", host.HostAddress.Address, port.PortID, resp.StatusCode)
				}
			}
		}
	}
}
Clone this wiki locally