Intro


So over the weekend I picked up a copy of Black Hat Go by Tom Steele and have been following along. I have a little experience with Python and Bash, so Go wasn’t terribly hard to jump into but definitely different as I have zero experience with C or other similar languages.

So why choose Go to learn?

  • It’s minimalist as hell (the language spec is only 50 pages)
  • Concurrency is a big part of Go (unfortunately I won’t be utilizing that feature in this project)
  • Go can cross-compile static binaries!

The Naive Approach

Whenever learning a new programming language or concept, I find the “naive” approach works well. Instead of trying to implement the “best” approach to a problem, simply implement the first one that comes to mind and build off of that. I like taking a project-oriented approach to learning so I decided to build a “naive” TCP port-scanner utilizing what I’ve learned so far with Go.

The Code

The repo can be found here

package main

import (
	"bufio"
	"fmt"
	"net"
	"os"
)

func main() {
	// open our file for reading
	file, _ := os.Open("ports.conf")

	// create a scanner object that reads the file we opened before
	// by default, NewScanner splits on newlines
	scanner := bufio.NewScanner(file)

	// we need to initialize an empty slice here for text in order
	// for the append function on line 25 to work
	var text []string

	// read in the file line by line, save it to "text" and close the file
	for scanner.Scan() {
		text = append(text, scanner.Text())
	}
	file.Close()
	// os.Args[1] parses argv
	TARGET := os.Args[1]
	fmt.Printf("The target is %s", TARGET)
	var openPorts []string
	for _, port := range text {
		fmt.Printf("\r\nCurrently scanning: %s:%s", TARGET, port)
		address := TARGET + ":" + port
		conn, err := net.Dial("tcp", address)
		if err != nil {
			//port is either filtered or closed
			continue
		}
		conn.Close()
		openPorts = append(openPorts, port)
		fmt.Printf("\r\n[*]Port %s is open!\n", port)
	}
	fmt.Printf("\nThe ports open for %s are %s", TARGET, openPorts)
}


Breaking Down The Code

    file, _ := os.Open("ports.conf")
  • ports.conf will be our config file, simply fill it up with newline separated ports we want to TCP scan
scanner := bufio.NewScanner(file)
var text []string
 for scanner.Scan() {
	text = append(text, scanner.Text())
}
file.Close()
  • this bit reads our ports file and stores the result as an array in a variable called text
TARGET := os.Args[1]
fmt.Printf("The target is %s", TARGET)
var openPorts []string
  • initialize our target as a constant that is read as a command line argument
  • e.g ./scan scanme.nmap.org
  • also declare a string array we’ll use to store open ports we find
for _, port := range text {
	address := TARGET + ":" + port
	conn, err := net.Dial("tcp", address)
	if err != nil {
		//port is either filtered or closed
		continue
	}
	conn.Close()
	openPorts = append(openPorts, port)
  • finally, we get to the meaty part of the scanner, the actual scanning routine that utilizes the built-in net package that golang provides
  • “err” lets us know if the port is filtered or closed
  • each open port we find gets appended to openPorts, the array we declared earlier

Conclusion


This is a really bad and slow TCP port scanner, there’s many things I would improve upon like:

  • making use of concurrency
  • scan top 100 ports by default
  • read multiple hosts
  • different type of scans (half-open, UDP, Xmas, etc..)
  • improving user UI

These features will come in the next iteration!