Ein „Lead“ auf Fiverr verlangte letzte Woche eine WordPress-Seite mit ERP-Integration. Noch vor jedem echten Austausch schickte er einen Dropbox-Link: ein Zip mit dem kompletten WordPress-Ordner und einem Datenbank-Dump, dazu die Notiz, das Ganze einfach lokal zu starten, damit ich den Scope sehen könne.
Ich möchte genau durchgehen, was passiert ist, denn die ehrliche Version ist nützlicher als die dramatische. Die Datei, die am Ende auftauchte, war nicht einmal das grösste Risiko in diesem Zip. Die eigentliche Lehre betrifft die Anfrage selbst, und die Gewohnheit, die daraus ein Nicht-Ereignis macht, egal was tatsächlich drinsteckt.
Die Anfrage, die nie auf einen Hauptrechner gehört
„Einfach lokal starten, um den Scope zu sehen“ klingt wie eine völlig normale Bitte bei einem WordPress-Migrationsprojekt. Kunden übergeben ständig Exporte, und einen vor dem Angebot zu prüfen ist gängige Praxis. Genau das macht es zur guten Tarnung.
Eine WordPress-Übergabe ist kein Dokument, sondern eine lebendige Codebasis und eine lebendige Datenbank. Sie zu starten bedeutet, jeden PHP-Code in diesem Ordner auszuführen und alles zu importieren, was im Datenbank-Dump steckt. Nichts im Dateibaum, wp-content, wp-admin, wp-includes, eine Config-Datei, muss verdächtig aussehen, um gefährlich zu sein. Es muss nur laufen, und genau das ist der Sinn der Anfrage.
Dieses Zip hat meinen Hauptrechner nie berührt. Es ging direkt in einen DDEV-Container, denselben Ort, an dem hier standardmässig jedes WordPress-Projekt beginnt.
Was tatsächlich drin war
Nachdem die Seite im Container lief, stellte sich heraus: eine einfache Landingpage für eine Shuttle-Buchung mit Kontaktformular. Nichts, das auch nur annähernd nach ERP-Integration aussah, nichts, das das Briefing erklärte, das ich bekommen hatte. Diese Lücke zwischen Scope und Seite war das erste echte Warnsignal, und sie zeigte sich, bevor ich überhaupt gezielt nach etwas Verdächtigem gesucht hatte.
Beim Durchsehen der Dateien lag zudem eine Datei, benannt wie ein Mockup, etwa eine Vorschau der Startseite, mit einer .exe-Endung darunter. Sie versuchte, sich im Moment des Öffnens zur Ausführung zu zwingen.
Ich habe auf die Nachricht nicht geantwortet. Ich habe den Account über Fiverr gemeldet und blockiert. Es gab nichts zu gewinnen, wenn ich weiter reagiert hätte, zu bestätigen, dass ich ein aktives Ziel bin, wäre das Letzte gewesen, was ich hätte preisgeben sollen.
Das eigentliche Risiko waren die Datenbank und die Codebasis
Hier lohnt sich Ehrlichkeit: Eine .exe ist eine Windows-Binärdatei. Meine Entwicklungsumgebung läuft unter Linux, also hatte diese Datei ohnehin keinen Weg zur Ausführung, unabhängig davon, was ich sonst getan hätte. Das ist eine Tatsache über das Dateiformat, keine Schutzmassnahme, die ich bewusst aufgebaut hätte, und es wäre falsch, daraus zu lesen: „Der Container hat einen Virus gestoppt.“
Der Datenbank-Dump und die PHP-Codebasis direkt neben dieser Datei trugen das eigentliche Risiko. Ein bösartiges Plugin oder ein eingeschleustes mu-Plugin läuft in dem Moment, in dem WordPress hochfährt. Ein Datenbank-Dump kann gespeicherte Prozeduren oder Trigger enthalten, die beim Import auslösen, ganz ohne separaten Ausführungsschritt. Beides hätte unter Linux genauso gut funktioniert wie unter Windows. Dass die .exe ihr Ziel verfehlt hat, war Glück. Dass der Container alles andere abgefangen hätte, auf jeder Plattform, war der eigentliche Punkt.
Die Container-First-Regel für jede Übergabe
Jedes WordPress-Projekt läuft hier standardmässig bereits in einem DDEV-Container, das war gängige Praxis, lange bevor dieser Fiverr-Auftrag aufgetaucht ist. Dieser Vorfall ist der Grund, warum ich mich jetzt noch strikter daran halte: Nichts von einem Kunden oder Lead läuft auf meinem Hauptrechner, ohne Ausnahme. Es läuft zuerst in DDEV, jedes Mal, auch bei Übergaben, die völlig routinemässig klingen.
Die Sandbox zur Arbeit passend wählen. DDEV ist der Standard für alles rund um WordPress, WooCommerce oder PHP, das ich tatsächlich weiterbauen werde, und das deckt den grössten Teil dessen ab, was in meinem Posteingang landet. Docker für eine schnelle, generische Prüfung, wenn ich nur nachsehen, nicht darauf aufbauen muss. Eine Wegwerf-VM für alles, dem ich nicht einmal in einem Container traue, unbekannte ausführbare Dateien und Archive besonders, sauber gestartet und nach einmaliger Nutzung gelöscht.
Die Sandbox darf nicht durchlässig sein. Ein Container, der noch an Ihre Zugangsdaten herankommt, hat den grössten Teil seines Werts verloren. Keine freigegebenen Volumes zu SSH-Keys oder einem Passwort-Manager-Tresor. Netzwerkzugriff kappen, wo es geht, eine Payload, die nicht nach Hause telefonieren kann, beschränkt sich auf den lokalen Schaden, den sie bereits versucht hat.
Als Wegwerfware behandeln, denn genau das ist es. Sieht innerhalb der Sandbox etwas verdächtig aus, ist die Antwort, den Container zu löschen und die nächste Prüfung mit einem sauberen Image neu zu starten. Eine Sandbox, die etwas Feindliches berührt hat, sauber zu bekommen, ist eine falsche Ersparnis.
Was vor dem Import zu prüfen ist
Den Dateibaum ansehen, bevor die Seite gestartet wird. Ein Plugin-Ordner, der zu nichts im offiziellen WordPress-Repository passt, oder eine Datei ausserhalb der üblichen wp-content-Struktur, ist einen zweiten Blick wert, bevor die Datenbank überhaupt importiert wird.
Bei jeder verdächtigen Datei die tatsächliche Signatur prüfen, nicht die Endung. Eine doppelte Endung, oder eine Datei, die sich als Windows-Executable meldet, obwohl sie ein Bild sein soll, ist ein sofortiges Stopp-Signal.
Den Scope gegen das abwägen, was tatsächlich ankam. Eine Anfrage für eine ERP-Integration, die als Landingpage mit Kontaktformular ankommt, ist kein Rundungsfehler, sondern eine Lücke, die es wert ist, für sich genommen als Warnsignal behandelt zu werden, noch bevor eine einzige Tabelle importiert wurde.
Und wenn jemand sagt „einfach lokal starten“, das als Anweisung verstehen, nicht als Formsache. Es bittet Sie darum, seinen Code und seine Daten auszuführen. Tun Sie genau das, nur nicht auf etwas, das zählt.
Was ein Container leistet, und was nicht
Ein Container stoppt opportunistische Malware, bevor sie den echten Rechner erreicht, und verhindert versehentliche Ausführung bei einer Routineprüfung. Gegen einen entschlossenen Angreifer ist er nicht immun, und es lohnt sich, ehrlich zu sein, wo diese Grenze verläuft. Die Container-Laufzeitumgebung aktuell halten, denn Escape-Exploits zielen genauso auf die Engine wie auf die Workload darin. Nicht als Root innerhalb der Sandbox laufen lassen. Niemals den Docker-Socket in eine Umgebung mounten, die für nicht vertrauenswürdigen Code gedacht ist, das gibt allem, was darin läuft, faktisch Root auf dem Host.
Nichts davon macht die Praxis sinnlos. Es macht sie zu einer korrekt eingegrenzten Ebene, kombiniert mit der Gewohnheit, „einfach starten“ als die sicherheitsrelevante Anweisung zu behandeln, die es tatsächlich ist.
Das Fazit
Diese eine .exe ist an einem Plattform-Mismatch gescheitert, der nichts mit einer bewussten Entscheidung meinerseits zu tun hatte. Die Lücke zwischen Scope und Lieferung, die Aufforderung, die Codebasis und Datenbank eines Fremden auszuführen, die Gewohnheit, das niemals auf einem echten Rechner zu tun, das sind die Teile, die das eigentliche Risiko so oder so gestoppt hätten, und die Teile, die auch das nächste Mal greifen, wenn die Payload korrekt für mein Setup gebaut ist.
Wenn Sie Seiten-Übergaben von Fremden entgegennehmen, um an Aufträge zu kommen, Fiverr, Upwork, Kaltakquise per E-Mail, egal welche, bauen Sie die Container-First-Gewohnheit auf, bevor Sie sie brauchen. Sie kostet ein paar Minuten bei jedem Projekt. Die Alternative kostet deutlich mehr bei dem einen Projekt, bei dem es tatsächlich zählt.
Wenn Sie als Unternehmer abwägen, ob ein Freelancer Sicherheit ernst nimmt, bevor sie zu Ihrem Problem wird: genau so sieht das in der Praxis aus, keine Richtlinie auf einer Seite, sondern ein Standard, an den mich niemand erinnern muss. Wenn das die Art Gewohnheit ist, die Sie bei Ihrem Projekt wollen, nehmen Sie Kontakt auf oder buchen Sie ein Gespräch.