đŸ„· ninja.sh — Handbuch

Last-Triage fĂŒr die RZ-Bereitschaft. Wenn der Load brennt und die SLA-Uhr
lÀuft: ninja.sh macht in Sekunden eine read-only Momentaufnahme, damit du
entscheiden kannst statt zu raten — Bot-Angriff oder WordPress-AnfĂ€nger
mit 500 Plugins
?

Leitsatz: Downtime setzen → Momentaufnahme → entscheiden → bestenfalls lösen.
ninja.sh fĂŒhrt nie selbst etwas aus. Es zeigt nur an. Handeln tust du in
einer zweiten bash. Damit Meister schlafen kann. 🩉


1. Was es ist (und was nicht)

Ist Ist nicht
Read-only Momentaufnahme unter Last Kein Dauer-Monitoring (dafĂŒr: Icinga/Zabbix)
Entscheidungshilfe Angriff vs. Eigenverschulden Kein Auto-Blocker (kein fail2ban-Ersatz)
Ein einzelnes File zum Reinpasten per vim/ssh Kein BSD (Fokus Debian/Ubuntu; BSD → andere wecken)

Wichtigste Eigenschaft: schmal & portabel. Eine Datei, keine AbhÀngigkeiten
außer Standard-Tools. Auf jede Linux-Box kopierbar.


2. Installation

Reinpasten (vim) oder per scp, dann ausfĂŒhrbar machen:

chmod +x ninja.sh

Optionale Tools (fĂŒr GeoIP-LĂ€nder & whois-CIDR — Debian/Ubuntu):

apt install -y whois geoip-bin geoip-database

Fehlt eins, degradiert ninja.sh sauber: ohne GeoIP keine [CC]-Marker, ohne
whois nur ein Hinweis. Der Rest lÀuft trotzdem.


3. Bedienung

Interaktiv (Default)

./ninja.sh

Öffnet das MenĂŒ mit Live-Status-Header.

Direkt (ohne MenĂŒ — gut zum Pipen)

./ninja.sh snap            # einmalige Momentaufnahme nach stdout
./ninja.sh watch           # Live-Aufnahme, Refresh alle 30s
./ninja.sh rec             # nur die Handlungs-VorschlÀge
./ninja.sh whois <IP>      # eine IP nachschlagen (Land + Org + CIDR)

Snapshot wegspeichern oder verschicken (Farben fallen automatisch weg, wenn
die Ausgabe kein Terminal ist):

./ninja.sh snap > /tmp/triage_$(hostname)_$(date +%H%M).txt

MenĂŒpunkte

Taste Aktion
1 Momentaufnahme (ein Screen, alle Sektionen)
2 Live-Watch — Aufnahme alle 30s, Ctrl+C zurĂŒck
3 Web error-log tail -f
4 Auth-log tail -f
5 System-log tail -f
w IP nachschlagen — GeoIP-Land + whois (echte CIDR zum Blocken)
r Handlungs-VorschlÀge (copy-paste-fertig)
q Quit

In allen tail -f- und Watch-Ansichten bringt dich Ctrl+C zurĂŒck ins
MenĂŒ
— es killt nicht das Script.


4. Die Momentaufnahme lesen

Reihenfolge ist Absicht: erst wo bin ich, dann brennt CPU oder Netz, dann
wer.

Kopfzeile

distro=debian  init=systemd  pkg=apt  web=nginx  db=mysql
deine SSH-IP: 1.2.3.4  (NICHT droppen)

Was die Umgebungs-Erkennung gefunden hat. Die SSH-IP-Warnung ist deine
Versicherung gegen Selbst-Aussperrung.

LAST & WER FRISST CPU/RAM — der wichtigste Split

  • Load 1/5/15 + die Top-Prozesse.
  • CPU bei mysqld/php-fpm + normales Web-Volumen → Eigenverschulden
    (Plugin/Cron-Loop). Nicht blocken — Query/Plugin finden.
  • Load hoch, aber CPU idle und stattdessen viele Verbindungen → Richtung Netz/Angriff.

💡 Merke: viele Requests ≠ viel Last. Ein Scanner, den nginx mit 444
wegwirft, macht 400 Requests und 0.02 Load. Erst die Kombination
entscheidet.

WEB — Angriffs-Erkennung

  • Rate (req/s): viel los oder normal?
  • Top-Talker IPs mit [Land]: eine IP mit Riesen-Count = simpler Bot.
    Eigene IPs sind als <= SELF (nicht droppen) markiert.
  • Top /24-Netze: Bots verteilen sich ĂŒber Ranges — hier werden sie sichtbar,
    auch wenn einzelne IPs niedrig aussehen.
  • HTTP-Status-Mix: viele 4xx/444 = Scanner/Block · viele 5xx = App kippt.
  • VerdĂ€chtige Pfade: /.env, wp-login, xmlrpc, /.git = Credential-/WP-Probing.
  • Top User-Agents: ein einzelner UA mit hohem Count = Bot-Signatur.

AUTH / SSH

Top-Quell-IPs fehlgeschlagener Logins + Gesamtzahl. Hohe Zahl → SSH-Brute →
sshguard/fail2ban (siehe Empfehlungen).

DATENBANK

Live SHOW FULL PROCESSLIST (Sleep-Verbindungen ausgeblendet) — im Akutfall
aussagekrÀftiger als das Slow-Log, weil es zeigt, was jetzt lÀuft. Ohne
passwortlosen Zugang gibt's den fertigen -u root -p-Befehl.


5. Entscheiden & handeln (r)

r druckt copy-paste-fertige Befehle — du setzt sie in der zweiten bash ab:

  1. Downtime setzen — Monitoring auf Wartung, damit nicht mitten in der
    Analyse Pager hochgehen.
  2. IP/Netz sperren — gestaffelt: einzeln → /24 → echte CIDR (via w).
    Inklusive Block prĂŒfen und Block wieder lösen.
  3. Dienste reload/restart — Befehle automatisch im richtigen Init-Format.
  4. Entscheidungshilfe Angriff vs. Eigenverschulden in Worten.
  5. nginx-Snippet gegen WP-Bot-Flut (xmlrpc deny + wp-login ratelimit).

IP-Lookup (w) fĂŒr den prĂ€zisen Block

./ninja.sh whois 185.12.59.118

Zeigt Land + Org + echte CIDR (route/inetnum, oft /20). Damit blockst
du den realen Netzbereich des Angreifers statt blind /24 zu raten:

iptables -I INPUT -s <CIDR aus whois> -j DROP

6. Sicherheits-Eigenschaften (warum man dem Tool trauen kann)

  • Read-only. Keine Sektion verĂ€ndert irgendetwas am System.
  • Nie Auto-AusfĂŒhrung. Alle Aktionen sind Text, den du bewusst absetzt.
  • Self-Lockout-Schutz. Eigene Server-IPs (v4/v6/Loopback) und die
    SSH-Client-IP werden erkannt und in den Talkern markiert — sie landen nicht
    versehentlich in einem DROP.
  • ANSI-Injection entschĂ€rft. User-Agents/Pfade/Logzeilen sind
    angreiferkontrolliert; alle untrusted Felder werden vor der Ausgabe von
    Steuerzeichen befreit (clean()), damit ein prÀparierter Log-Eintrag nicht
    dein Terminal kapert.
  • set -u. Tippfehler in Variablen brechen frĂŒh ab statt still ins Leere zu laufen.

7. Troubleshooting

Symptom Ursache / Fix
Rate:-Zeile fehlt Logformat ohne [dd/Mon/yyyy:HH:MM:SS] → _logepoch()-Regex anpassen
Keine [CC]-LĂ€nder apt install geoip-bin geoip-database (oder GeoLite2-.mmdb fehlt)
web=none Kein Standard-Logpfad gefunden → Pfad in probe() (for f in 
) ergĂ€nzen
DB-Sektion: „kein passwortloser Zugang" normal ohne unix_socket-Auth → gezeigten -u root -p-Befehl nutzen
init=unknown / Service-Befehle stimmen nicht exotisches Init → svc_cmd() erweitern
Farben als \033[
] in einer Datei passiert nicht — Farben werden ohne TTY automatisch leer (sonst Bug melden)

8. Anpassen

Alle Stellschrauben stehen oben im Script:

  • WATCH_INTERVAL=30 — Refresh-Takt im Watch-Modus.
  • TAIL_N=500 — wie viele Log-Zeilen analysiert werden.
  • probe() — neue Logpfade/Distros hier eintragen.
  • snap_web() → „VerdĂ€chtige Pfade" — eigene Probe-Muster ins grep -aoiE aufnehmen.

Der Code ist durchgehend kommentiert (was/wo/wie/warum) — fang bei probe()
an, dann liest sich der Rest von selbst.