Network security is an essential aspect of any IT infrastructure. With the increasing number of cyber threats, organizations must regularly scan their networks for vulnerabilities. One effective way to do this is by building a network vulnerability scanner. In this article, we will explore how to build a network vulnerability scanner using Golang.

Introduction to Network Vulnerability Scanning

Network vulnerability scanning is the process of identifying security weaknesses in a network. This includes checking open ports, detecting outdated software versions, and finding misconfigurations that attackers can exploit. A well-designed scanner can help organizations enhance their security posture by detecting and mitigating vulnerabilities before malicious actors exploit them.

Golang (or Go) is an excellent choice for building a network scanner due to its concurrency capabilities, efficiency, and simplicity. With its powerful networking libraries, we can quickly build a robust scanner capable of performing real-time security assessments.

Setting Up the Development Environment

Before we begin coding, ensure that you have Golang installed on your system. You can download and install it from the official Golang website. Verify the installation by running:

$ go version

We also need a text editor or an Integrated Development Environment (IDE) such as Visual Studio Code or Goland.

Creating the Project Structure

Start by creating a new directory for our project:

$ mkdir go-network-scanner
$ cd go-network-scanner
$ go mod init go-network-scanner

This initializes a new Go module.

Building a Basic Port Scanner

A network vulnerability scanner must first identify open ports on a target system. We can achieve this using Go’s net package. Below is a simple port scanner:

package main

import (
	"fmt"
	"net"
	"sync"
	"time"
)

// scanPort attempts to connect to a given port and returns whether it's open
type ScanResult struct {
	Port   int
	Open   bool
}

func scanPort(host string, port int, results chan<- ScanResult, wg *sync.WaitGroup) {
	defer wg.Done()

	address := fmt.Sprintf("%s:%d", host, port)
	conn, err := net.DialTimeout("tcp", address, 1*time.Second)
	if err != nil {
		results <- ScanResult{Port: port, Open: false}
		return
	}
	conn.Close()
	results <- ScanResult{Port: port, Open: true}
}

func main() {
	host := "scanme.nmap.org" // Replace with the target IP or hostname
	ports := []int{21, 22, 23, 25, 53, 80, 443, 3306, 8080} // Common ports

	var wg sync.WaitGroup
	results := make(chan ScanResult, len(ports))

	for _, port := range ports {
		wg.Add(1)
		go scanPort(host, port, results, &wg)
	}

	wg.Wait()
	close(results)

	for result := range results {
		if result.Open {
			fmt.Printf("Port %d is open\n", result.Port)
		} else {
			fmt.Printf("Port %d is closed\n", result.Port)
		}
	}
}

Explanation

  • The scanPort function attempts to establish a TCP connection with a given port.
  • We use Goroutines and WaitGroups to scan multiple ports concurrently.
  • The results are collected in a channel and displayed after all scans are completed.

Detecting Service Versions

Knowing which services are running on open ports is crucial for vulnerability assessment. We can achieve this by sending specific requests and analyzing responses.

Modify scanPort to detect service banners:

func scanPortWithBanner(host string, port int, results chan<- ScanResult, wg *sync.WaitGroup) {
	defer wg.Done()

	address := fmt.Sprintf("%s:%d", host, port)
	conn, err := net.DialTimeout("tcp", address, 1*time.Second)
	if err != nil {
		results <- ScanResult{Port: port, Open: false}
		return
	}
	defer conn.Close()

	conn.SetReadDeadline(time.Now().Add(2 * time.Second))
	buf := make([]byte, 1024)
	n, err := conn.Read(buf)
	if err == nil {
		fmt.Printf("Port %d: %s\n", port, string(buf[:n]))
	}
	results <- ScanResult{Port: port, Open: true}
}

Adding Vulnerability Detection

We can integrate a list of known vulnerabilities by comparing the detected services and versions with publicly available databases like the NVD (National Vulnerability Database).

For example, if we detect an outdated SSH service:

if strings.Contains(string(buf[:n]), "OpenSSH_7.2") {
    fmt.Println("Vulnerability detected: OpenSSH 7.2 has known security issues.")
}

Reporting the Scan Results

To make our scanner useful, we need to generate a structured report. We can export the results to a JSON file:

import (
	"encoding/json"
	"os"
)

type ScanReport struct {
	Host    string       `json:"host"`
	Results []ScanResult `json:"results"`
}

func saveReport(host string, results []ScanResult) {
	report := ScanReport{Host: host, Results: results}
	file, _ := os.Create("scan_report.json")
	defer file.Close()
	json.NewEncoder(file).Encode(report)
}

After scanning, call saveReport(host, results) to store the findings.

Conclusion

Building a network vulnerability scanner with Golang provides a fast and efficient way to assess network security. In this guide, we:

  • Created a simple port scanner
  • Implemented service version detection
  • Added basic vulnerability identification
  • Exported results to a JSON report

This scanner can be further enhanced by integrating with external vulnerability databases, implementing more in-depth service probing, and adding a web-based dashboard for better visualization.

With Golang’s efficiency and concurrency support, you can build highly scalable security tools that help protect networks from potential threats.