shelltrap.com
en de

Produkt

Shelltrap für CyberPanel

Ein Webshell-Scanner ist nur so gut wie die beiden Dinge, die niemand auf eine Feature-Liste schreibt: was er tut, wenn er sich nicht sicher ist, und was er tut, wenn er kaputt ist. Hier steht beides.

Was er beobachtet

Shelltrap beobachtet die Docroots der Accounts auf Ihrem CyberPanel-Host — standardmäßig /home — und reagiert auf Dateiereignisse, während sie passieren. Die Eventmaske umfasst bewusst mehr als „eine Datei wurde geschrieben":

  • CLOSE_WRITE — ein Schreibvorgang ist abgeschlossen, der übliche Moment zum Scannen
  • MOVED_TO / MOVED_FROM — ein Umbenennen in einen beobachteten Pfad hinein oder heraus
  • CREATE / DELETE — Auftauchen und Verschwinden
  • ATTRIB — Attributänderungen, damit ein späteres chmod, ein setuid-Bit oder ein Eigentümerwechsel ein eigenes Ereignis ist und nicht etwas, das der Scanner am nächsten Sonntag erfährt

Heiße Nicht-Kundenpfade werden absichtlich als ignoriert markiert: ein Datenbank-Datenverzeichnis, Logbäume und Panel-Caches. Ein Filesystem-Mark auf dem Root-Dateisystem liefert sonst jeden Open des Hosts — das ist ein Performance-Problem, kein Sicherheitsgewinn.

Ein Überlauf der Warteschlange wird nicht verschluckt. FAN_Q_OVERFLOW wird gezählt, alarmiert und mit einem zeitlich begrenzten Rekonsiliationsscan beantwortet. Dieselbe Rekonsiliation läuft nach Reboot, Absturz, Upgrade und nach jedem neuen Mount unterhalb eines Kundenroots. „Nicht gescannt" und „Scanner gestört" sind eigene Zustände und werden nie als clean angezeigt.

Vier Schritte zwischen Schreibvorgang und Verdikt

Shelltrap-Architektur: Ereignisquellen, Root-Broker, isolierter Worker, Verdikt und ReaktionVier Ereignisquellen speisen den parserfreien Root-Broker. Der Broker übergibt einen nur lesbaren Dateideskriptor an einen unprivilegierten Worker mit ClamAV, YARA, Hash-Sets und Heuristik. Der Worker liefert eines von fünf Verdikten zurück, aus dem die Reaktion folgt. Rechts hängen Steuerebene, signierte Feeds und Telemetrie am Broker.01 · EREIGNISQUELLENWeb-Uploadlsphp · auto_prepend_filesynchron, 2 sfanotifyTier A–D · CLOSE_WRITEEchtzeitFTPpure-uploadscriptnach dem UploadZeitplanBaseline · inkrementellI/O-Budget02 · ROOT-BROKERshelltrapd — läuft als root, enthält keinen Parseropenat2 · RESOLVE_NO_SYMLINKSJob-Journal in SQLite (WAL)nur opake Objekt-IDskein YARA-, kein ClamAV-CodeSCM_RIGHTS · nur-lesbarer FD03 · SCANNER-WORKEReigener Benutzer · Namespaces · seccomp · Landlock · kein NetzClamAVclamd-Socket · Full-ProfilYARA 4.5je Generation vorkompiliertHash-Setsplus Known-Good-AllowlistHeuristikmehrere Signale nötigGrenzen je Mandant: Dateigröße, Scanzeit, Archivtiefe, expandierte Bytes, Temp-Speicher04 · VERDIKTcleansuspiciousmaliciousunscanneddegraded„nicht gescannt" und „gestört" sind eigene Zustände und werden nie als clean angezeigtSTEUEREBENECyberPanel Plugin · CLI/run/shelltrap/api.sockSO_PEERCRED · Rollenkeine freien PfadeSignatur-FeedsEd25519 · GenerationenProvenienz je RegelKorpus-Gate · CanaryCircuit Breaker · RollbackLizenzEd25519-Token, offline geprüftFingerabdruck je Serverohne Lizenz: keine FeedsReaktionQuarantäne als TransaktionRestore mit MetadatenMail · Webhook · DigestPolicy je DomainHealth · Metriken · AuditPrometheus-Textformatgehashte Audit-Kette
Der Broker hat die Rechte und keinen Parser. Der Worker hat die Parser und keine Rechte. Alles Scharfe passiert rechts von dieser Linie.

Die Trennung in diesem Bild ist das gesamte Sicherheitsargument. Ein Scanner ist ein Programm, das vom Angreifer gewählte Dateien öffnet und durch Archiv-, Bild-, Dokument- und Executable-Parser schickt. Das ist der gefährlichste Code im System, also läuft er nicht als root:

Der Root-Broker (shelltrapd) ist ein statisch gelinktes Go-Binary ohne cgo. Er hält die fanotify-Gruppen, normalisiert Ereignisse, öffnet Dateien sicher (openat2 mit RESOLVE_NO_SYMLINKS, auf älteren Kerneln ein komponentenweiser openat-Walk mit O_NOFOLLOW), erfasst minimale Metadaten, übergibt Scan-Jobs an Worker, führt Quarantäne-Transaktionen aus und bedient die lokale API. Er enthält kein YARA, keinen ClamAV-Code und kein Archiv-, Office- oder ELF-Parsing. Er akzeptiert keinen freien Pfad aus Panel oder UI, nur opake Objekt-IDs. Einzige Ausnahme ist der Root-CLI-Aufruf scan <pfad>, über SO_PEERCRED als uid 0 verifiziert.

Der Scanner-Worker ist ein eigener Prozess unter einem eigenen Systembenutzer, in eigenem Mount- und PID-Namespace, mit seccomp, rlimits und cgroup-Grenzen, definiertem Timeout, Crash-Retry — und ohne Netz. Er bekommt vom Broker einen nur lesbaren Deskriptor über SCM_RIGHTS; er löst selbst nie einen Pfad auf.

Die Engines

Im Worker, in dieser Reihenfolge:

  1. Typerkennung über Magic Bytes. Sie steuert nur die Priorität. Größenfilter, Medien, Backups und Caches werden nie stillschweigend als sauber gewertet — sie werden als unscanned gemeldet und in einen begrenzten Tiefenscan oder einen geplanten Spezialscan gegeben. Bild-Header vor PHP, .phar, .phtml, .user.ini und verschachtelte Archive laufen immer durch die volle Pipeline.
  2. ClamAV über den clamd-Socket, nur im Full-Profil.
  3. YARA 4.5, mit Regeln, die je Feed-Generation gegen genau diese Engine-Version vorkompiliert sind.
  4. Hash-Sets — SHA-256-Mengen plus eine Known-Good-Allowlist für WordPress-Core und verbreitete Plugins und Themes, Laravel und Joomla. Die Allowlist darf einen Pfad-Kontexttreffer nicht blind überstimmen: Ein Known-Good-Hash in einem Upload-Verzeichnis bleibt ein Fund.
  5. Heuristik, mit erklärbarem Scoring je Signal: PHP-Obfuskationsmerkmale (eval, base64_decode, gzinflate, str_rot13, chr-Ketten, lange Hexstrings, variable Funktionsaufrufe, Entropie), PHP in Upload-Verzeichnissen, .htaccess- und .user.ini-Tricks (AddHandler, AddType, auto_prepend_file), Symlinks aus dem Home-Verzeichnis hinaus, world-writable und setuid-Dateien. Ein Treffer braucht mehrere unabhängige Signale. Entropie oder eine einzelne lange Zeile ergeben für sich genommen nie ein suspicious — diese Lehre hat uns eine Handvoll Fehlalarme auf normalen JPEGs und auf Wordfences eigenem Transient-Cache gekostet, und sie ist behoben.

Grenzen je Mandant und global gelten für Dateigröße, Scanzeit, Archiv-Rekursion, Dateizahl, Kompressionsverhältnis, expandierte Bytes und Temp-Speicher. Eine Überschreitung tötet den Worker-Prozess und vermerkt das Objekt als unscanned mit Grund — ein begrenztes Scheitern statt eines unbegrenzten.

Lieber die Begründung sehen als darüber lesen? Der Webshell Signal Explorer geht sechs reale Formen durch, einschließlich des Fehlalarms, der nicht passieren darf.

Fünf Verdikte

VerdiktBedeutungStandardaktion
cleanvon jeder Engine des Profils gescannt, nichts gefundenkeine
suspiciousmehrere unabhängige Signale, unterhalb der Aktionsschwellemelden
maliciousSignatur- oder Hashtreffer oder Heuristik-Score über der SchwelleQuarantäne bei Signatur- und Hashtreffern
unscannedeine Grenze wurde erreicht, der Grund ist protokolliertmelden, planmäßig erneut versuchen
degradedder Scanner selbst war beeinträchtigtmelden, alarmieren

Der Cache-Schlüssel enthält Mount-ID, Inode, hochauflösende mtime und ctime, Größe, Content-Hash sowie Regelmengen-, Engine- und Policy-Generation. Ein Signaturupdate invalidiert alte clean-Verdikte automatisch. Pfadabhängige Policy-Verdikte (etwa „PHP in uploads") liegen in einem getrennten Cache, weil derselbe Inode über einen Hardlink oder ein Rename den Kontext wechseln kann.

Reaktion, und warum Quarantäne eine Transaktion ist

Quarantäne als crash-sichere TransaktionDer Broker kopiert die Datei deskriptorbasiert, vergleicht den Hash, synchronisiert Datei und Verzeichnis, veröffentlicht atomar, schreibt Manifest und Datenbank und entfernt das Original erst danach über den Verzeichnis-Deskriptor mit erneutem Inode- und Hashvergleich. Weicht etwas ab, endet der Vorgang in einem sichtbaren Recovery-Zustand statt als Erfolg.REIHENFOLGE IST DIE SICHERHEIT01Kopie über Deskriptorin eine temporäre, nur für root lesbare Datei02Hashvergleichdie Kopie muss byteweise dem gescannten Deskriptor entsprechen03fsyncDatei und Verzeichnis, damit ein Stromausfall nichts halbiert04atomar veröffentlichenrename in den Quarantänebestand05Manifest und DBEigentümer, Modus, Zeiten, ACLs, xattrs, SELinux-Kontext06Original entfernenüber den Verzeichnis-FD, mit erneutem Inode- und HashvergleichAbweichungInode geändertHash abweichendZiel existiertSchreiben fehlgeschlagenRecovery-Zustandsichtbar, auditiertnie als Erfolg gemeldetEXDEV ist der NormalfallRestoreüberschreibt nie ein Zielchmod 000 gibt es nicht · Quarantäne ist Beweismaterial und wird auch beim Purge nur nach ausdrücklicher Freigabe gelöscht
Jeder Schritt ist so angeordnet, dass ein Absturz zwischen zwei Schritten einen wiederherstellbaren Zustand hinterlässt und keine gelöschte Kundendatei.

Restore überschreibt nie ein vorhandenes Ziel und stellt Eigentümer, Modus, Zeiten, ACLs, erweiterte Attribute und den SELinux-Kontext wieder her. Eine chmod 000-Aktion gibt es nicht: eine Datei an Ort und Stelle kaputtzumachen ist keine Eindämmung, sondern ein Support-Ticket. EXDEV — Quarantäne und Original auf verschiedenen Dateisystemen — ist der Normalfall und kein Fehler.

Benachrichtigung heißt: Admin-Mail sofort bei malicious, Digest bei suspicious, optional Kundenmail über den CyberPanel-Kontakt und Webhooks, die auf eine Ziel-Allowlist beschränkt sind. Ignore-Regeln umfassen Pfad-Globs je Site, Signatur-IDs, Hash-Allowlists und Benutzer. Eine Ignore-Regel unterdrückt die Aktion, nie den Scan und nie die Aufzeichnung des Fundes.

Das Upload-Gate

Ablauf des synchronen Upload-GatesEin Besucher lädt eine Datei hoch. Der PHP-Adapter läuft vor dem Anwendungscode, reicht die Temp-Deskriptoren an den Broker weiter und wartet höchstens zwei Sekunden. Der Worker scannt, der Broker antwortet mit allow oder deny. Bei deny endet der Request mit 403 und die Temp-Datei wird gelöscht; bei einem Gate-Fehler entscheidet die Policy on_error.BesucherHTTP-Requestlsphpshelltrap-prepend.phpBroker/run/shelltrap/upload.sockWorkerisoliert, ohne NetzPOST multipart/form-data$_FILES nicht leersonst tut der Adapter nichts{v:1, docroot, server_name, files[]}höchstens 128 Dateien · 1 MiB je Zeilenur-lesbarer FD je Temp-DateiO_RDONLY|O_NOFOLLOW · reguläre Datei, passender EigentümerVerdikt je Datei{"decision":"allow|deny","reason","millis"}deny → HTTP 403, Temp-Datei gelöschtallow → Anwendung läuft normal weiterZEITBUDGETupload.timeout_ms — Standard 2000 ms, Maximum 60000 msGATE-FEHLERupload.on_error = open (Standard: Request läuft weiter) · closed (HTTP 503)
Der synchrone Weg. Alles andere — SFTP, Panel-Dateimanager, WebDAV, CLI — fängt stattdessen der Watcher asynchron ab.

Eine einzige PHP-Datei, über auto_prepend_file in einer globalen lsphp-ini je PHP-Version geladen, tut gar nichts, solange $_FILES leer ist. Ist es das nicht, reicht sie die Temp-Deskriptoren über einen lokalen Socket an den Broker und wartet höchstens upload.timeout_ms (Standard 2000 ms, gedeckelt bei 60000 ms). Eine malicious-Antwort bedeutet HTTP 403 und eine gelöschte Temp-Datei. Fail-open ist bei einem Gate-Fehler der Standard, fail-closed ist je Domain verfügbar.

Das ist der Mechanismus, der auf OpenLiteSpeed und LiteSpeed Enterprise ohne ModSecurity identisch funktioniert, und das ist der ehrliche Grund für diese Wahl. Wir nennen auch seine Grenze: auto_prepend_file lässt sich per .user.ini innerhalb der Site überschreiben. Genau dieses Muster ist selbst ein Heuristiktreffer, und der Echtzeit-Watcher bleibt als Catch-all hinter dem Gate.

FTP-Uploads werden über pure-uploadscript eingereiht und direkt nach dem Upload gescannt; dieser Post-Upload-Charakter wird ausgewiesen statt weggeredet.

Mehr dazu: wie das Upload-Gate funktioniert .

Plattformstufen

Vier Beobachtungsstufen, nach Laufzeitfähigkeit statt Kernelversion gewähltDer Installer probiert die Fähigkeiten des Hosts. Stufe A nutzt fanotify mit Filehandles und liefert vollständige Echtzeit. Stufe B verzichtet auf Filehandles, Umbenennungen kommen verzögert. Stufe C arbeitet ohne CAP_SYS_ADMIN mit budgetiertem inotify und einem Crawler. Stufe D installiert nicht und liefert nur Diagnose.LAUFZEITPROBE, KEINE VERSIONSANNAHMEAvollständigfanotify mit FAN_REPORT_DFID_NAME, Marks je MountUbuntu 22.04/24.04 · Alma/Rocky/RHEL 9 und 10Echtzeit, alle FunktionenBfd-modefanotify ohne Filehandles, Renames über ctime-AbgleichAlma/Rocky/RHEL/CloudLinux 8 · Ubuntu 20.04 GA-KernelEchtzeit beim Schreiben, Umbenennen verzögertCcontainerbudgetiertes inotify plus checkpointbarer Crawlerunprivilegiertes LXC/OpenVZ ohne CAP_SYS_ADMINErkennung mit Verzögerung, im Produkt ausgewiesenDnicht unterstütztkein verwendbares Backend oder unbekanntes DateisystemRestkeine Installation, nur Diagnose
Der Installer probiert Fähigkeiten zur Laufzeit. Eine Kernel-Versionsnummer ist ein Hinweis, nie eine Zusage.

shelltrapd --check liefert JSON mit tier, diagnostic.tier und je Mount einem reason und error. Ist ein Backend ausdrücklich konfiguriert, spiegelt das oberste tier diese Wahl wider — für eine echte Fähigkeitsaussage lesen Sie deshalb immer auch diagnostic.tier.

Debian hat bei CyberPanel selbst nur Third-Party-Support, also sagen wir es nicht zu. Globale inotify-Sysctls werden nie hinter Ihrem Rücken angehoben: Der Installer zählt Watches und fragt.

Full- und Lite-Profil

Das Profil wird nach einer Messung gewählt, nicht aus einer Versionstabelle. Full verlangt einen laufenden oder installierbaren clamd, einen Socket, der vom Benutzer shelltrap-scan tatsächlich erreichbar ist, und mindestens 1,5 GiB MemAvailable, die nach der gemessenen Reload-Spitze übrig bleiben. Sonst wählt die Installation Lite, setzt scanner.enable_clamd = false und sagt das. Lite hat sichtbar geringere Abdeckung: Die Support-Zusage für die Software ist dieselbe, die Erkennungszusage nicht.

Ein später gestarteter clamd stuft Sie nicht stillschweigend auf Full hoch. Das ist Absicht: Ein Profilwechsel ist eine Sicherheitsentscheidung und bekommt eine Messung, keine Vermutung.

Signatur-Feeds

Weg einer Signaturgeneration von der Quelle bis zur AktivierungQuellen werden nach Lizenz gefiltert, mit Provenienz versehen und zu einer Ed25519-signierten Generation gebaut. Der Client prüft Digest und Signatur, das Korpus-Gate prüft gegen Known-Good und Known-Bad, erst danach wird atomar umgeschaltet. Ein Quarantäne-Sturm über mehrere Accounts löst automatisch einen Rollback aus.BUILD BEI PANOMITYAUF IHREM SERVER01Quelleneigene Regeln · kuratierte Fremdregeln02Lizenzfilternur DRL-1.1, BSD-3, Apache-2.0, MIT03ProvenienzQuelle, Autor, Commit, Lizenz je Regel04SignaturEd25519 · manifest.json + manifest.sig05PrüfungDigest vor Signatur, Ablauf, Denylist06Korpus-GateKnown-Good hart, Known-Bad als Quote07Aktivierungatomarer Symlink-Wechsel, Cache invalidiertCircuit Breakerletzte Stunde gegen 24-Stunden-Mittel: mindestens 50 Quarantänen und mehr als das Zehnfacheund mindestens drei Accounts und mindestens 20 % der aktiven Accounts — ein einzelner Account löst nie einen serverweiten Rollback ausautomatischer Rollback
Regeln werden kuratiert, nach Lizenz gefiltert, signiert, verifiziert, gegen ein Korpus geprüft und erst dann aktiviert — mit automatischem Rollback, wenn das Ergebnis wie ein Fehlalarm-Sturm aussieht.

Fremdregeln werden nie direkt von einem fremden Mirror aktiviert. Jede Regel trägt ihre Provenienz — Quelle, Commit, Lizenz, Autor, ob sie verändert wurde — und der Build lässt nur Regeln unter DRL-1.1, BSD-3-Clause, Apache-2.0 und MIT zu (plus GPL-2.0-only für ClamAV-Datenbanken). Wo eine Upstream-Lizenz uns verpflichtet, Autor, URI und Lizenzhinweis sichtbar zu halten, wandert diese Attribution bis in die Fundanzeige und die Benachrichtigungsmail.

Die ClamAV-Datenbanken daily, main und bytecode holt freshclam je Server; gebündelt werden sie nicht.

Das CyberPanel-Plugin

Das Plugin ist eine Bedienoberfläche, kein zweiter Scanner. Broker und Worker laufen weiter, wenn das Panel steht, aktualisiert wird oder kaputt ist.

  • Seiten: Dashboard und Health, Funde mit Filtern, Paging, Detail und Signalen, Quarantäne mit Restore (Purge nur Admin), Policies je Domain mit sichtbarer Vererbung global → Account → Domain, Ignore-Listen, Feed-Generationen, Audit (nur Admin), Jobs sowie eine Hilfe- und Statusseite.
  • Rollen: Administratoren sehen alles; Reseller und Kunden sehen ihre eigenen Sites, können in ihrem Bereich ein Restore anfordern und dürfen nur die Policy-Schlüssel ändern, die ein Administrator freigegeben hat. upload.on_error und heuristics.action bleiben für beide Rollen gesperrt, und der Broker setzt diese Grenze unabhängig von der UI durch.
  • Integrität: Der CyberPanel-Installer patcht Core-Dateien zeilenweise, deshalb legt das Plugin atomare Snapshots an, bevor es etwas anfasst, prüft sie per Prüfsumme und rollt zurück, wenn Installation oder Reparatur scheitern. Nach einem Panel-Upgrade ist der Reparaturpfad idempotent und läuft erneut.

Einzelheiten: die Plugin-Dokumentation .

Lizenzierung

Eine Lizenz je Server. Die Aktivierung bindet die Lizenz an einen Server-Fingerabdruck aus /etc/machine-id; deactivate gibt den Platz wieder frei. Der Daemon prüft einen Ed25519-signierten Token offline — der Lizenzdienst muss nicht erreichbar sein, damit der Scanner arbeitet — und ein systemd-Timer erneuert ihn täglich mit einer Stunde Jitter.

Ohne gültige Lizenz stürzt der Daemon nicht ab und läuft nicht in eine Schleife: Der Watcher zählt weiter Ereignisse, der Scheduler plant nichts, das Upload-Gate antwortet allow mit dem Grund unlicensed, und Health meldet unlicensed mit präziser Ursache. Feeds antworten 401. Das ist die kommerzielle Grenze, und sie ist so gebaut, dass sie sichtbar scheitert statt gefährlich.

Mehr: Lizenzierung und Aktivierung .

Was Shelltrap nicht ist

Ehrlichkeit ist billiger als eine Rückerstattung:

  • Er ist keine WAF und keine Firewall. Er sieht Dateien an, keine Requests.
  • Er verhindert keine Ausführung auf Kernel-Ebene. Ein Open vorab zu blockieren ist ein 1.x-Prototyp und wird heute bewusst nicht zugesagt. Was es heute gibt, ist ein synchrones Gate auf dem Web-Upload-Weg und schnelle asynchrone Erkennung überall sonst.
  • Er behauptet nicht, alles zu finden. Kein Scanner tut das. Er behauptet, ehrlich zu sagen, was er gescannt hat, was er nicht scannen konnte und warum er so entschieden hat.
  • Er kann sich nicht gegen einen Angreifer wehren, der schon root auf der Maschine hat. Nichts, was auf dieser Maschine läuft, kann das.

Kommen Sie von CXS?

Die Migrationsseite ordnet Begriffe, Quarantäne und Konfiguration zu, und der Rechner ermittelt, wie viele Lizenzen eine Flotte braucht.

CXS → Shelltrap: Migration