5 Commits

Author SHA1 Message Date
Dominic Breuker
9c63e5d6c5 prepare README.md for version 1.2.0 release 2019-08-22 20:32:18 +02:00
Dominic Breuker
c136be2f46 Merge pull request #8 from DominicBreuker/version-tag
Version logging
2019-08-22 20:27:41 +02:00
Dominic Breuker
831cac3196 add version logging to startup log messages for better troubleshooting 2019-08-22 17:56:12 +02:00
Dominic Breuker
3bd4885e22 change banner 2019-08-21 23:43:00 +02:00
Dominic Breuker
6f434e1d5b add kill switch for errno 22 error to shut down if the error does not go away 2019-08-21 23:42:39 +02:00
5 changed files with 56 additions and 28 deletions

View File

@@ -9,6 +9,9 @@ DEV_DOCKERFILE = $(PROJECT_DIR)/docker/Dockerfile.development
TEST_IMAGE = local/pspy-testing:latest
TEST_DOCKERFILE = $(PROJECT_DIR)/docker/Dockerfile.testing
VERSION = `git describe --tags --always || echo "unknown"`
BUILD_SHA = `git rev-parse HEAD || echo "unknown"`
# Run unit test and integration test inside container
test:
docker build -f $(TEST_DOCKERFILE) -t $(TEST_IMAGE) .
@@ -38,7 +41,7 @@ example:
# builds one set of static binaries that should work on any system without dependencies, but are huge
# builds another set of binaries that are as small as possible, but may not work
build:
sh -c "if ! docker image ls | grep '$(BUILD_IMAGE)' | cut -d ':' -f1; then echo 'building build image'; docker build -f $(BUILD_DOCKERFILE) -t $(BUILD_IMAGE) .; fi"
# sh -c "if ! docker image ls | grep '$(BUILD_IMAGE)' | cut -d ':' -f1; then echo 'building build image'; docker build -f $(BUILD_DOCKERFILE) -t $(BUILD_IMAGE) .; fi"
mkdir -p $(PROJECT_DIR)/bin
docker run -it \
@@ -47,8 +50,8 @@ build:
-w "/go/src/github.com/dominicbreuker" \
--env CGO_ENABLED=0 \
--env GOOS=linux \
--env GOARCH=386 \
$(BUILD_IMAGE) /bin/sh -c "go build -a -ldflags '-extldflags \"-static\"' -o pspy/bin/pspy32 pspy/main.go"
--env GOARCH=386 \
$(BUILD_IMAGE) /bin/sh -c "go build -a -ldflags '-s -w -X main.version=${VERSION} -X main.commit=${BUILD_SHA} -extldflags \"-static\"' -o pspy/bin/pspy32 pspy/main.go"
docker run -it \
--rm \
-v $(PROJECT_DIR):/go/src/github.com/dominicbreuker/pspy \
@@ -56,18 +59,18 @@ build:
--env CGO_ENABLED=0 \
--env GOOS=linux \
--env GOARCH=amd64 \
$(BUILD_IMAGE) /bin/sh -c "go build -a -ldflags '-extldflags \"-static\"' -o pspy/bin/pspy64 pspy/main.go"
$(BUILD_IMAGE) /bin/sh -c "go build -a -ldflags '-s -w -X main.version=${VERSION} -X main.commit=${BUILD_SHA} -extldflags \"-static\"' -o pspy/bin/pspy64 pspy/main.go"
docker run -it \
--rm \
-v $(PROJECT_DIR):/go/src/github.com/dominicbreuker/pspy \
-w "/go/src/github.com/dominicbreuker" \
--env GOOS=linux \
--env GOARCH=386 \
$(BUILD_IMAGE) /bin/sh -c "go build -ldflags '-w -s' -o pspy/bin/pspy32s pspy/main.go && upx pspy/bin/pspy32s"
$(BUILD_IMAGE) /bin/sh -c "go build -ldflags '-w -s -X main.version=${VERSION} -X main.commit=${BUILD_SHA}' -o pspy/bin/pspy32s pspy/main.go && upx pspy/bin/pspy32s"
docker run -it \
--rm \
-v $(PROJECT_DIR):/go/src/github.com/dominicbreuker/pspy \
-w "/go/src/github.com/dominicbreuker" \
--env GOOS=linux \
--env GOARCH=amd64 \
$(BUILD_IMAGE) /bin/sh -c "go build -ldflags '-w -s' -o pspy/bin/pspy64s pspy/main.go && upx pspy/bin/pspy64s"
$(BUILD_IMAGE) /bin/sh -c "go build -ldflags '-w -s -X main.version=${VERSION} -X main.commit=${BUILD_SHA}' -o pspy/bin/pspy64s pspy/main.go && upx pspy/bin/pspy64s"

View File

@@ -1,6 +1,6 @@
<img src="images/logo.svg" align="left" />
# pspy - unprivileged linux process snooping
# pspy - unprivileged Linux process snooping
[![Go Report Card](https://goreportcard.com/badge/github.com/DominicBreuker/pspy)](https://goreportcard.com/report/github.com/DominicBreuker/pspy)
[![Maintainability](https://api.codeclimate.com/v1/badges/23328b2549a76aa11dd5/maintainability)](https://codeclimate.com/github/DominicBreuker/pspy/maintainability)
@@ -12,7 +12,7 @@ It allows you to see commands run by other users, cron jobs, etc. as they execut
Great for enumeration of Linux systems in CTFs.
Also great to demonstrate your colleagues why passing secrets as arguments on the command line is a bad idea.
The tool gathers it's info from procfs scans.
The tool gathers the info from procfs scans.
Inotify watchers placed on selected parts of the file system trigger these scans to catch short-lived processes.
## Getting started
@@ -21,13 +21,13 @@ Inotify watchers placed on selected parts of the file system trigger these scans
Get the tool onto the Linux machine you want to inspect.
First get the binaries. Download the released binaries here:
- 32 bit big, static version: `pspy32` [download](https://github.com/DominicBreuker/pspy/releases/download/v1.0.0/pspy32)
- 64 bit big, static version: `pspy64` [download](https://github.com/DominicBreuker/pspy/releases/download/v1.0.0/pspy64)
- 32 bit small version: `pspy32s` [download](https://github.com/DominicBreuker/pspy/releases/download/v1.0.0/pspy32s)
- 64 bit small version: `pspy64s` [download](https://github.com/DominicBreuker/pspy/releases/download/v1.0.0/pspy64s)
- 32 bit big, static version: `pspy32` [download](https://github.com/DominicBreuker/pspy/releases/download/v1.2.0/pspy32)
- 64 bit big, static version: `pspy64` [download](https://github.com/DominicBreuker/pspy/releases/download/v1.2.0/pspy64)
- 32 bit small version: `pspy32s` [download](https://github.com/DominicBreuker/pspy/releases/download/v1.2.0/pspy32s)
- 64 bit small version: `pspy64s` [download](https://github.com/DominicBreuker/pspy/releases/download/v1.2.0/pspy64s)
The statically compiled files should work on any Linux system but are quite huge (~4MB).
If size is an issue, try the smaller versions which depend on libc and are compressed with UPX (<1MB).
If size is an issue, try the smaller versions which depend on libc and are compressed with UPX (~1MB).
### Build
@@ -41,7 +41,8 @@ The summary is as follows:
- -r: list of directories to watch with Inotify. pspy will watch all subdirectories recursively (by default, watches /usr, /tmp, /etc, /home, /var, and /opt).
- -d: list of directories to watch with Inotify. pspy will watch these directories only, not the subdirectories (empty by default).
- -i: interval in milliseconds between procfs scans. pspy scans regularly for new processes regardless of Inotify events, just in case some events are not received.
- -c: print events in different colors. Red for new processes, green for new Inotify events.
- -c: print commands in different colors. File system events are not colored anymore, commands have different colors based on process UID.
- --debug: prints verbose error messages which are otherwise hidden.
The default settings should be fine for most applications.
Watching files inside `/usr` is most important since many tools will access libraries inside it.

View File

@@ -5,7 +5,6 @@ import (
"log"
"os"
"os/signal"
"strings"
"syscall"
"time"
@@ -17,15 +16,20 @@ import (
"github.com/spf13/cobra"
)
var bannerLines = []string{
" _____ _____ _______ __",
" | __ \\ / ____| __ \\ \\ / /",
" | |__) | (___ | |__) \\ \\_/ / ",
" | ___/ \\___ \\| ___/ \\ / ",
" | | ____) | | | | ",
" |_| |_____/|_| |_| ",
helpText,
}
var banner = `
██▓███ ██████ ██▓███ ▓██ ██▓
▓██░ ██▒▒██ ▒ ▓██░ ██▒▒██ ██▒
▓██░ ██▓▒░ ▓██▄ ▓██░ ██▓▒ ▒██ ██░
▒██▄█▓▒ ▒ ▒ ██▒▒██▄█▓▒ ▒ ░ ▐██▓░
▒██▒ ░ ░▒██████▒▒▒██▒ ░ ░ ░ ██▒▓░
▒▓▒░ ░ ░▒ ▒▓▒ ▒ ░▒▓▒░ ░ ░ ██▒▒▒
░▒ ░ ░ ░▒ ░ ░░▒ ░ ▓██ ░▒░
░░ ░ ░ ░ ░░ ▒ ▒ ░░
░ ░ ░
░ ░
`
var helpText = `
pspy monitors the system for file system events and new processes.
@@ -33,11 +37,9 @@ It prints these envents to the console.
File system events are monitored with inotify.
Processes are monitored by scanning /proc, using file system events as triggers.
pspy does not require root permissions do operate.
Check our https://github.com/dominicbreuker/pspy for more information.
Check out https://github.com/dominicbreuker/pspy for more information.
`
var banner = strings.Join(bannerLines, "\n")
var rootCmd = &cobra.Command{
Use: "pspy",
Short: "pspy can watch your system for new processes and file system events",
@@ -75,6 +77,8 @@ func init() {
func root(cmd *cobra.Command, args []string) {
logger := logging.NewLogger(debug)
logger.Infof("%s", banner)
cfg := &config.Config{
RDirs: rDirs,
Dirs: dirs,

View File

@@ -4,6 +4,7 @@ import (
"bytes"
"fmt"
"io/ioutil"
"os"
"strconv"
"strings"
"unsafe"
@@ -70,9 +71,20 @@ func (i *Inotify) Watch(dir string) error {
return nil
}
var errno22Counter = 0
func (i *Inotify) Read(buf []byte) (int, error) {
n, errno := unix.Read(i.FD, buf)
if n < 1 {
if errno.Error() == "invalid argument" {
errno22Counter += 1
if errno22Counter > 20 {
fmt.Printf("Unrecoverable inotify error (%s, errno %d). Exiting program...\n", errno, errno)
os.Exit(22)
}
} else {
errno22Counter = 0
}
return n, fmt.Errorf("reading from inotify fd %d: errno: %d", i.FD, errno)
}
return n, nil

10
main.go
View File

@@ -1,7 +1,15 @@
package main
import "github.com/dominicbreuker/pspy/cmd"
import (
"fmt"
"github.com/dominicbreuker/pspy/cmd"
)
var version string
var commit string
func main() {
fmt.Printf("pspy - version: %s - Commit SHA: %s\n", version, commit)
cmd.Execute()
}