shelltrap.com
en de

Interaktiv

Webshell Signal Explorer

Erkennung ist keine Magie und keine einzelne clevere Regel. Sie besteht aus mehreren schwachen Signalen, die erst zusammen etwas bedeuten. Hier sind sechs Fälle, einer davon mit der richtigen Antwort: nichts tun.

Webshell Signal Explorer

Sechs Dinge, die ein Scanner auf einem echten Host sieht. Wählen Sie eines und lesen Sie, warum es eine Aktion auslöst — oder bewusst nicht.

Die klassische erste Stufe. Eine kurze Datei, ein kodierter String, ein Aufruf, der Daten zu Code macht.

Verdikt malicious Score 88 public_html/wp-content/uploads/2026/03/thumb-cache.php
<?php
/* thumbnail cache — do not edit */
$k = 'ZXhhbXBsZQ==';
$p = base64_decode($k);
eval($p);

Signale

  • heuristics · php.dynamic_eval +45

    Code wird zur Laufzeit gebaut und ausgeführteval() bekommt eine Variable, kein Literal. Legitimer Anwendungscode braucht das fast nie, ein Lader immer.

  • heuristics +25

    Decoder unmittelbar vor der Senkebase64_decode() speist direkt den ausführenden Aufruf. Der Abstand zwischen Dekodieren und Ausführen ist das Merkmal, nicht die Funktion selbst.

  • heuristics +20

    PHP in einem Upload-Verzeichniswp-content/uploads/ nimmt Dateien aus dem Internet entgegen. Eine .php-Datei dort hat keinen legitimen Grund zu existieren, egal was drinsteht.

  • heuristics +8

    Kommentar imitiert Plattform-Vokabular — „Nicht bearbeiten"-Kommentare sind billige Tarnung gegen menschliche Prüfer. Für sich genommen beweist das nichts; es erhöht die Punktzahl erst, wenn andere Signale feuern.

Drei Transformationen in einem Ausdruck. Sinn der Verschachtelung ist, ein grep nach einem einzelnen Funktionsnamen ins Leere laufen zu lassen.

Verdikt malicious Score 79 public_html/wp-includes/class-wp-image-cache.php
<?php
$s = 'nSjXpH5NmH2Wn2E=';
$x = gzinflate(base64_decode(str_rot13($s)));
$h = "\x73\x79\x73\x74\x65\x6d";
echo strlen($x);

Signale

  • heuristics +35

    Drei Decoder in einem Ausdruckstr_rot13base64_decodegzinflate ist eine Transformationskette, keine Datenverarbeitung. Jede Funktion für sich ist harmlos, die Komposition ist das Signal.

  • heuristics +24

    Hex-kodiertes String-Literal — Eine lange \x..-Folge versteckt einen einfachen Bezeichner vor allem, was nach Wörtern sucht. PHP löst sie beim Parsen auf, ein Mensch nicht.

  • heuristics · php.escape_density +12

    Ungewöhnliche Dichte an Escape-Sequenzen — Gemessen am Rest der Datei. Für sich genommen trifft das auch legitimen Bibliothekscode — genau deshalb entscheidet es nie allein.

  • heuristics +15

    Dateiname imitiert den Core, der Pfad passt nicht — Der Name imitiert den WordPress-Core, doch die Distribution enthält keine solche Datei, und ihr Hash steht nicht in der Known-Good-Allowlist.

Ein einzelnes stark wirkendes Signal, das für sich genommen keine Aktion auslösen darf. Genau dafür gibt es den Report-only-Modus.

Verdikt suspicious Score 38 public_html/app/Support/Dispatcher.php
<?php
$a = 'php';
$b = 'info';
$f = $a . $b;
$f();

Signale

  • heuristics · php.variable_call +28

    Aufrufziel wird zur Laufzeit zusammengesetzt — Das Aufrufziel taucht nie als Literal auf, keine statische Regel kann es benennen. Dispatcher, Plugin-Loader und DI-Container tun das täglich völlig legitim.

  • heuristics +10

    Bezeichner über Konkatenation zerlegt — Einen Namen in Fragmente zu zerlegen ist ein Muster zur Suchvermeidung. In Framework-Code ist es oft schlicht Lesbarkeit.

Zwei Signale, kein Decoder, kein Upload-Pfad, Hash unbekannt, aber die Datei liegt im Quelltextbaum der Anwendung. Der Score bleibt unter der Schwelle: Shelltrap protokolliert ein Finding, benachrichtigt und fasst nichts an. Eine Quarantäne würde hier die Website zerstören.

Die Magic Bytes sagen GIF, der Inhalt sagt PHP. Upload-Prüfungen, die nur den Header ansehen, sind zufrieden; der Webserver wird nicht gefragt.

Verdikt malicious Score 84 public_html/wp-content/uploads/2026/03/logo.png
GIF89a;
<?php echo 1; ?>

Signale

  • heuristics +40

    PHP-Open-Tag mit Code in einer Mediendatei — Ein <?-Bytepaar allein genügt nicht — das erzeugte Fehlalarme auf normalen JPEGs und wurde behoben. Ein explizites Tag mit ausführbarem Code dahinter genügt.

  • heuristics +26

    Deklarierter Typ und Inhalt widersprechen sich — Die Typerkennung über Magic Bytes steuert nur die Priorität. Eine Datei, deren Endung, Magic Bytes und Inhalt drei verschiedene Geschichten erzählen, wird geprüft und nie als „nur ein Bild" übersprungen.

  • heuristics +18

    Beschreibbarer Upload-Pfad — Die Datei ist dort gelandet, wo anonyme Besucher schreiben dürfen. Zusammen mit dem Tag beantwortet das die Frage „wie kam sie hierher", bevor jemand sie stellen muss.

Überhaupt kein Code. Zwei Konfigurationszeilen, die den Server Bilder ausführen und vor jedem Request eine fremde Datei laden lassen.

Verdikt malicious Score 91 public_html/wp-content/uploads/.htaccess + .user.ini
# .htaccess
AddType application/x-httpd-php .png
AddHandler application/x-httpd-php .ico

; .user.ini
auto_prepend_file = /home/example/public_html/wp-content/uploads/.cache.php

Signale

  • heuristics +42

    Endung auf den PHP-Handler umgebogenAddType/AddHandler unterhalb eines Docroots macht aus harmlosen Uploads ausführbaren Code. Fast keine legitime Site braucht das unterhalb von uploads/.

  • heuristics +38

    `auto_prepend_file` aus einer Site heraus gesetzt — Es ist derselbe Mechanismus, den das Upload-Gate von Shelltrap selbst benutzt — genau deshalb behandelt das Produkt eine Überschreibung auf Site-Ebene als Fund und vertraut ihr nicht.

  • heuristics +11

    Punktdatei in einem öffentlichen Verzeichnis — Die vorgeschaltete Datei versteckt sich vor einem beiläufigen ls. Persistenz wohnt in den Dateien, die niemand auflistet.

Der Echtzeit-Watcher sieht Schreibvorgänge auf .htaccess und .user.ini genauso wie Inhaltsänderungen, weil die Eventmaske Attributänderungen einschließt. Deshalb fängt dieselbe Pipeline einen reinen Konfigurationsangriff wie einen Code-Drop.

Echter WordPress-Core-Code, der eine Heuristik auslöst. Wenn ein Scanner das in Quarantäne schiebt, nimmt er die Website mit. Die ehrliche Antwort ist eine Known-Good-Allowlist, kein lauterer Alarm.

Verdikt clean Score 12 public_html/wp-includes/kses.php
<?php
// wp-includes/kses.php — unmodified WordPress core
$string = str_replace( array( '&amp;', '&lt;', '&gt;' ), array( '&', '<', '>' ), $string );
$string = wp_kses_normalize_entities( $string, $context );
$string = preg_replace( '/&([^&\s;]+)(?![0-9a-z;])/', '&amp;$1', $string );

Signale

  • heuristics · php.escape_density +12

    Hohe Dichte maskierter Zeichen — Ein HTML-Sanitizer besteht aus nichts als Escape-Sequenzen. PHPMailer, SimplePie und die Tabellen benannter Zeichenreferenzen lösen dasselbe Signal aus.

  • hash +0

    SHA-256 steht in der Known-Good-Allowlist — Die Prüfsumme stammt aus der veröffentlichten WordPress-Distribution. Die Allowlist beantwortet die Heuristik — aber sie überstimmt nie einen Pfad-Kontexttreffer wie PHP unterhalb von uploads/.

Verdikt clean. Ein Signal, ein passender Known-Good-Hash, kein Upload-Pfad. Es wird nichts gemeldet, nichts verschoben und niemand um 03:00 Uhr geweckt.

Illustration, keine Schadsoftware: Jedes Schnipsel hier ist wirkungslos. Scores und Bezeichner hängen von der aktiven Regelgeneration ab; sie erklären die Begründung und spezifizieren nicht das Produkt.

Warum ein Score und keine Regel

Ein einzelnes Signal genügt fast nie. base64_decode steht in der Hälfte der Plugins auf einem belebten WordPress-Host. Ein variabler Funktionsaufruf ist das, wovon jeder Dispatcher und jeder Dependency-Injection-Container der PHP-Welt lebt. Hohe Escape-Dichte ist ein HTML-Sanitizer.

Jedes dieser Merkmale, allein als Regel verwendet, ergibt einen Scanner, der entweder offensichtliche Lader übersieht oder den WordPress-Core in Quarantäne schiebt. Beide Fehlerarten enden mit demselben Telefonat.

Deshalb bewertet die Heuristik in Shelltrap. Jedes Signal steuert ein Gewicht bei, die Gewichte summieren sich, und das Verdikt vergleicht die Summe mit einer Schwelle, die Sie je Domain verschieben können. Jedes beteiligte Signal wird mit dem Fund gespeichert und im Panel angezeigt — ein Verdikt ist also eine Begründung, die Sie lesen können, und kein Etikett, dem Sie glauben müssen.

Die Signale, die kein Code sind

Zwei der sechs Fälle oben enthalten überhaupt kein PHP. Ein umgebogener Handler in .htaccess und eine auto_prepend_file-Zeile in .user.ini sind Konfiguration — und sie gehören zu den wirksamsten Persistenzmechanismen im Shared Hosting: Sie brauchen keine eigene Shell und überleben das Aufräumen der Datei, nach der alle gesucht haben.

Genau deshalb umfasst die Eventmaske des Watchers Attributänderungen, und genau deshalb laufen .user.ini und .htaccess immer durch die volle Pipeline, wie klein sie auch sind. Ein Scanner, der nur .php-Dateien ansieht, sieht sich die falsche Hälfte des Problems an.

Der eine, der still bleiben muss

Der letzte Fall ist der wichtige. wp-includes/kses.php ist WordPress-Core, unverändert, und löst jedes Mal eine Heuristik aus, weil Sanitizer aus Escape-Sequenzen bestehen. PHPMailer, SimplePie und die Tabellen benannter Zeichenreferenzen ebenso.

Die ehrliche Antwort darauf ist eine Known-Good-Allowlist aus veröffentlichten Distributionsprüfsummen — kein lauterer Alarm und keine leisere Heuristik. Und die Allowlist hat ihrerseits eine Grenze: Sie darf einen Pfad-Kontexttreffer nicht überstimmen. Eine Datei, deren Hash im WordPress-Core steht, die nun aber in einem Upload-Verzeichnis liegt, bleibt ein Fund — denn die Frage ist, wie sie dorthin gekommen ist.

Gegen das eigene Denken prüfen