Categories
Programming

Writing a simple port scanner in Go

Go is a fabulous programming language for writing all types of modern software, in particular network aware tools and infrastructure of the Cloud. Go is also great for writing penetration testing tools. I wanted to demonstrate a simple port scanner in Go to show the language’s power and simplicity for ethical hackers.

Why Go and why write a port scanner?

I really like Go. It’s a simple, fast and efficient language and I think it gets the right balance between the power of C and Java, with the ease of use and simplicity of Python. I started learning Go a while back and it’s definitely one of my favourite programming languages.

Go really shines writing network tools. Without going into the reasons why Go exists, in my opinion if you’re going to write modern applications that are network aware then you will not go wrong considering Go. I’m writing a port scanner because I think it’s a really good example of what Go is good at. Can you find better examples of Go code elsewhere? Probably. Can you find better, more efficient port scanners? Most definitely. But considering the penetration testers job requirements and sometimes having to create quick tools in the middle of an engagement, I’d say learning how to write even a basic port scanner is a worthy exercise.

You’ll need to have Go set up on your local machine to run the code in this post. Go is very easy to get set up and runs on most platforms out of the box. I’ve tested this code on both Windows 10 and Linux systems. I wont run through installing Go but if you head over to the Go website you should find instructions for your platform.

Assuming everything is setup correctly, you should be able to run Go and see the following output.

Now that’s ready, let’s write some code. I’m going to start with the basic shell of a program, the simplest likely to be worth doing in Go.

package main

import (
    "fmt"
)

func main() {
    fmt.Println("Yay ports")
}

Enter this code into your text editor (I’m using vim) and then run it with go run:

If everything went to plan you should see “Yay ports” printed to the console. If you didn’t see it, I’d suggest going back through your code to find what went wrong.

Go is pretty easy to read. At the very top of the file you see “package main”. This tells Go that your file is the main package and not a module or library. Next you have the import block. Imports are other code libraries that you can import into your code for use. If you’ve used C it’s similar to the #include statements but a little better. In our import block we’re importing the fmt package which gives us functions for outputting text.

Next we have the actual code that does something. Like C, Go needs to have a main function. I’m assuming you have basic programming knowledge, but if you don’t a function is a self-contained block of code that does something, and main is a special function that the Go runtime uses to execute your code.

Inside the main function we’re using the fmt.Println() function to output some text (remember we imported fmt earlier).

Cool, but that’s not a port scanner. If anything that’s a Hello world program that forgot to say Hello…

Let’s change that. Let’s make it connect to a remote server.

package main

import (
    "fmt"
    "net"
)

func main() {
    _, err := net.Dial("tcp", "google.com:80")
    if err == nil {
        fmt.Println("You connected to Google")
    }
}

In this code, we’re adding the net package to be imported first and then in the main code block we first call the net.Dial() function to connect over TCP to google.com. The _, err at the start of the line is Go’s way of saying we don’t want to store the result in a variable (_) but if there’s an error you can store that in the err variable. The underscore is a way of telling the Go compiler you know there’s a result but you can discard it.

Ok, we can communicate over the Internet and if you’ve ever tried network programming in C you should be able to see how much easier this is in Go. Anyway, still not a port scanner yet.

package main

import (
    "fmt"
    "net"
)

func main() {
    for i := 1; i <= 1024; i++ {
        address := fmt.Sprintf("scanme.nmap.org:%d", i)
        conn, err := net.Dial("tcp", address)
        if err != nil {
            continue
        }
        conn.Close()
        fmt.Println("Port %d is open.\n", i)
    }
}

You’ll notice a new changes to the main codeblock. First we’re wrapping everything in a for loop. There are 65,535 possible ports on a computer system but for the sake of demonstration we’ll just scan the first 1024 which are the commonly used ports.

The loop sets up a variable i to run from 1 to 1024 times. Inside the for loop we’re assigning the value “scanme.nmap.org” into the address variable with the value inside the i variable as the port (so eventually it will contain all 1024 numbers). I’m scanning the nmap server rather than Google this time, nmap is the industry standard port scanner tool and has services set up for testing port scanning tools, Google might get upset though if we port scan them.

Then as before, we call the Dial function passing it the address variable (and the port). If the err variable is given a value that means the port was closed and the loop will skip to the next value. If err is empty (nil) that means the port returned a response and can be considered open. If it’s open we print a message indicating such and move on.

We can see by running the code that some ports are open. If you leave it running longer you’ll likely find more open ports.

This is by no means the most efficient port scanner. It can be done much better. For example, using GoRoutines to run each port scan in parallel and giving the user some flexibility by not hardcoding the host you want to scan in the code. But for the sake of a blog post, it’s good enough.

Once you’re happy with your code you can run go build to create the final binary executable.

You can grab the code from my Github Gist.

I hope that was informative and showed you how easy Go is and how quick you can build useful utilities. As an ethical hacker, the ability to craft tools is an essential skill.

Leave a Reply

Your email address will not be published.