#!/bin/bash
 
set -uo pipefail
 
# =========================================================
# Server recon script
# "Outside-in" walkthrough of an unknown production box.
# Read-only: nothing on disk gets modified.
# Output goes into the same pre-upgrade folder as the
# snapshot script, with a `recon-` prefix so files don't
# collide if you run both back-to-back.
# =========================================================
 
SNAP="/root/pre-upgrade-$(date +%F-%H%M)"
mkdir -p "$SNAP"
cd "$SNAP"
 
echo "[+] Recon snapshot — saving to: $SNAP"
 
# =========================================================
# README — what each file is for
# =========================================================
cat > recon-README.txt <<EOF
Server recon snapshot
Generated: $(date)
Host:      $(hostname -f 2>/dev/null || hostname)
 
Files:
  recon-exposure.txt    — public-facing: IP, reverse DNS, open ports,
                          firewall rules, certificates on disk
  recon-running.txt     — services, timers, processes, containers, VMs
  recon-packages.txt    — manually installed packages, /opt, /usr/local,
                          custom systemd units
  recon-users.txt       — login history, current sessions, real users,
                          sudoers, /home, recently edited /etc files
  recon-storage.txt     — filesystem usage + biggest top-level dirs +
                          /var/lib breakdown (where stateful data lives)
  recon-scheduled.txt   — system cron, per-user cron, systemd timers
  recon-recent.txt      — warnings in the last 24h, recently written logs
EOF
 
# =========================================================
# EXPOSURE — what the world sees
# =========================================================
{
    echo "=== ip -br -c a ==="
    ip -br -c a
 
    echo
    echo "=== Public IP (best-effort via ifconfig.me) ==="
    PUBLIC_IP=$(curl -s --max-time 5 ifconfig.me 2>/dev/null || true)
    echo "${PUBLIC_IP:-(unavailableno internet or curl missing)}"
 
    echo
    echo "=== Reverse DNS of public IP ==="
    if [ -n "${PUBLIC_IP:-}" ]; then
        host "$PUBLIC_IP" 2>&1 || echo "(no PTR record)"
    else
        echo "(skipped — public IP unknown)"
    fi
 
    echo
    echo "=== iptables -nvL ==="
    iptables -nvL 2>&1 || echo "(iptables not available)"
 
    echo
    echo "=== iptables -t nat -nvL ==="
    iptables -t nat -nvL 2>&1 || true
 
    echo
    echo "=== Certificates found in /etc /opt /usr/local ==="
    find /etc /opt /usr/local -type f \
        \( -name "*.crt" -o -name "*.pem" -o -name "*.cer" -o -name "*.key" \) \
        2>/dev/null || true
 
    echo
    echo "=== ss -tulpn (listening sockets + program) ==="
    ss -tulpn
} > recon-exposure.txt
 
# =========================================================
# RUNNING — what's currently doing work
# =========================================================
{
    echo "=== systemctl list-units --type=service --state=running ==="
    systemctl list-units --type=service --state=running --no-pager
 
    echo
    echo "=== systemctl list-timers --all ==="
    systemctl list-timers --all --no-pager
 
    echo
    echo "=== ps auxf (process tree) ==="
    ps auxf
 
    echo
    echo "=== docker ps -a ==="
    docker ps -a 2>/dev/null || echo "(docker not installed)"
 
    echo
    echo "=== docker images ==="
    docker images 2>/dev/null || true
 
    echo
    echo "=== virsh list --all ==="
    virsh list --all 2>/dev/null || echo "(libvirt not installed)"
 
    echo
    echo "=== lxc list ==="
    lxc list 2>/dev/null || echo "(lxd not installed)"
} > recon-running.txt
 
# =========================================================
# PACKAGES — what was installed on purpose
# =========================================================
{
    echo "=== apt-mark showmanual ==="
    apt-mark showmanual 2>/dev/null || echo "(apt-mark not available — not a Debian/Ubuntu box?)"
 
    echo
    echo "=== ls -la /opt ==="
    ls -la /opt 2>/dev/null || true
 
    echo
    echo "=== ls -la /usr/local/bin /usr/local/sbin ==="
    ls -la /usr/local/bin /usr/local/sbin 2>/dev/null || true
 
    echo
    echo "=== /etc/systemd/system/*.service (custom unit files) ==="
    ls -la /etc/systemd/system/*.service 2>/dev/null || echo "(no custom unit files)"
} > recon-packages.txt
 
# =========================================================
# USERS — who has used / can use this box
# =========================================================
{
    echo "=== last -n 30 (recent logins) ==="
    last -n 30 2>/dev/null || true
 
    echo
    echo "=== who (active sessions) ==="
    who
 
    echo
    echo "=== real users (UID >= 1000) ==="
    getent passwd | awk -F: '$3 >= 1000'
 
    echo
    echo "=== sudo group members ==="
    getent group sudo 2>/dev/null || true
    getent group wheel 2>/dev/null || true
    getent group admin 2>/dev/null || true
 
    echo
    echo "=== ls -la /home ==="
    ls -la /home 2>/dev/null || true
 
    echo
    echo "=== most recently edited files in /etc ==="
    ls -lt /etc | head -20
} > recon-users.txt
 
# =========================================================
# STORAGE — where the data lives
# =========================================================
{
    echo "=== df -hT ==="
    df -hT
 
    echo
    echo "=== top-level dirs by size (du -x -d1 /) ==="
    # -x = stay on one filesystem (skip /proc, /sys, /dev, network mounts)
    du -h -x -d1 / 2>/dev/null | sort -h
 
    echo
    echo "=== /var/lib breakdown (where stateful services keep data) ==="
    du -h -d1 /var/lib 2>/dev/null | sort -h
} > recon-storage.txt
 
# =========================================================
# SCHEDULED — what runs without a human pressing enter
# =========================================================
{
    echo "=== system-level cron drop-in directories ==="
    ls -la /etc/cron.hourly /etc/cron.daily /etc/cron.weekly /etc/cron.monthly /etc/cron.d 2>/dev/null
 
    echo
    echo "=== /etc/crontab ==="
    cat /etc/crontab 2>/dev/null || true
 
    echo
    echo "=== per-user crontabs ==="
    for u in $(cut -f1 -d: /etc/passwd); do
        out=$(crontab -u "$u" -l 2>/dev/null) || continue
        if [ -n "$out" ]; then
            echo "--- $u ---"
            echo "$out"
            echo
        fi
    done
 
    echo
    echo "=== systemctl list-timers --all ==="
    systemctl list-timers --all --no-pager
} > recon-scheduled.txt
 
# =========================================================
# RECENT — what's been going on lately
# =========================================================
{
    echo "=== journalctl --since '24 hours ago' -p warning ==="
    journalctl --since "24 hours ago" -p warning --no-pager 2>/dev/null || true
 
    echo
    echo "=== ls -lt /var/log/ | head -20 (logs most recently written) ==="
    ls -lt /var/log/ | head -20
} > recon-recent.txt
 
# =========================================================
# Done
# =========================================================
echo
echo "[+] Recon snapshot complete:"
ls -lah "$SNAP"/recon-*