PDFId : quand le python met à nu du pdf…
Je rebondis sur un article que j'ai pu lire de Didier Stevens qui mettait en lumière la capacité pour un fichier pdf d'héberger du code et de lancer, dès l'ouverture du document, un exécutable, parfois sans que l'utilisateur n'en soit conscient.
PDFId
PdfId est un petit script python qui va décortiquer le contenu d'un fichier pdf. Le but étant de pouvoir contrôler qu'aucune action ne sera exécutée à l'ouverture de celui-ci. Bien entendu, sans avoir à le lancer...
Son utilisation est très triviale et binaire : analyse du fichier et désarmement. Petite démonstration...
Pratique
Rapatrions l'outil.$ wget http://www.didierstevens.com/files/software/pdfid_v0_0_11.zip $ unzip pdfid_v0_0_11.zipNous obtenons un script python, pdfid.py. Jouons un peu pour voir. Pour pouvoir le tester, nous avons récupéré un pdf qui lance automatiquement une application calculette. Vous pourrez le télécharger ici.
$ python pdfid.py calc.pdf PDFiD 0.0.11 calc.pdf PDF Header: %PDF-1.1 obj 5 endobj 5 stream 1 endstream 0 xref 1 trailer 1 startxref 1 /Page 1 /Encrypt 0 /ObjStm 0 /JS 0 /JavaScript 0 /AA 0 /OpenAction 1 /AcroForm 0 /JBIG2Decode 0 /RichMedia 0 /Launch 3 /Colors > 2^24 0Le pdf contient 3 instances dans /Launch. Mais encore...
$ strings calc.pdf %PDF-1.1 1 0 obj /OpenAction << /F << /DOS (C:\\\\WINDOWS\\\\system32\\\\calc.exe) /Unix (/usr/bin/xcalc) /Mac (/Applications/Calculator.app) >> /S /Launch /Pages 2 0 R /Type /Catalog endobj 2 0 obj /Kids [ 3 0 R ] /Count 1 /Type /Pages endobj 3 0 obj /Resources << /Font << /F1 5 0 R >> /MediaBox [ 0 0 795 842 ] /Parent 2 0 R /Contents 4 0 R /Type /Page endobj 4 0 obj /Length 1260 >>stream /F1 30 Tf 350 750 Td 20 TL 1 Tr (calc.pdf) Tj /F1 15 Tf 233 690 Td 20 TL 0 Tr (This page is empty but it should start calc :-D) Tj /F1 15 Tf 233 670 Td 20 TL (Dont be afraid of the pop-ups, just click them...) Tj /F1 14 Tf 75 620 Td 20 TL 2 Tr (Comments:) Tj /F1 12 Tf 75 600 Td 20 TL 0 Tr (Windows:) Tj ( - Foxit: runs calc.exe at the document opening without any user confirmation message \(!\) ) ' ( - Acrobat Reader *:) ' ( 1. popup proposing to open "calc.exe" \(warning\)) ' ( 2. starts "calc.exe") ' () ' (Mac:) ' ( - Preview does not support PDF keyword /Launch) ' ( - Acrobat Reader 8.1.2: starts Calculator.app) ' () ' (Linux:) ' ( ! Assumes xcalc is in /usr/bin/xcalc) ' ( - poppler: does not support PDF keyword /Launch) ' ( - Acrobat Reader 7: ) ' ( 1. popup telling it can not open "xcalc" \(dumb reasons\)) ' ( 2. popup proposing to open "xcalc" \(warning\)) ' ( 3. starts "xcalc") ' ( - Acrobat Reader 8.1.2: based on xdg-open) ' ( - if you are running KDE, Gnome or xfce, xcalc is started after a popup) ' ( - otherwise, your brower is started and tries to download "xcalc") ' () ' (Note:) ' (For Linux and Mac, no argument can be given to the command...) ' ETendstream endobj 5 0 obj /Subtype /Type1 /Name /F1 /BaseFont /Helvetica /Type /Font endobj xref 0000000000 65535 f 0000000010 00000 n 0000000234 00000 n 0000000303 00000 n 0000000457 00000 n 0000001774 00000 n trailer /Size 6 /Root 1 0 R /ID [ (bc38735adadf7620b13216ff40de2b26) (bc38735adadf7620b13216ff40de2b26) ] startxref 1866 %%EOFComme je vous l'ai dis en introduction, pdfid.py a une fonction qui permet de désarmer un pdf. Pour cela, il suffit de mentionner la bonne option. Et comme tout bonne outil qui se respecte, il affiche la liste des options via un --help.
$ ./pdfid.py --help Usage: pdfid.py [options] [pdf-file] Tool to test a PDF file Options: --version show program's version number and exit -h, --help show this help message and exit -s, --scan scan the given directory -a, --all display all the names -e, --extra display extra data, like dates -f, --force force the scan of the file, even without proper %PDF header -d, --disarm disable JavaScript and auto launch
Nous allons passer au désarmement du pdf.
Pour cela, il suffit de passer l'option -d sur le fichier à désarmer. On aura alors un joli calc.disarmed.pdf qui sera généré par pdfid.py.$ python pdfid.py -d calc.pdf /OpenAction -> /oPENaCTION /Launch -> /lAUNCH /Launch -> /lAUNCH /Launch -> /lAUNCH PDFiD 0.0.11 calc.pdf PDF Header: %PDF-1.1 obj 5 endobj 5 stream 1 endstream 0 xref 1 trailer 1 startxref 1 /Page 1 /Encrypt 0 /ObjStm 0 /JS 0 /JavaScript 0 /AA 0 /OpenAction 1 /AcroForm 0 /JBIG2Decode 0 /RichMedia 0 /Launch 3 /Colors > 2^24 0Testons maintenant le calc.disarmed.pdf généré par pdfid.py :
$ python pdfid.py calc.disarmed.pdf PDFiD 0.0.11 calc.disarmed.pdf PDF Header: %PDF-1.1 obj 5 endobj 5 stream 1 endstream 0 xref 1 trailer 1 startxref 1 /Page 1 /Encrypt 0 /ObjStm 0 /JS 0 /JavaScript 0 /AA 0 /OpenAction 0 /AcroForm 0 /JBIG2Decode 0 /RichMedia 0 /Launch 0 /Colors > 2^24 0Plus de Launch. Le calc.disarmed.pdf contient maintenant :
$ strings calc.disarmed.pdf %PDF-1.1 1 0 obj /oPENaCTION << /F << /DOS (C:\\\\WINDOWS\\\\system32\\\\calc.exe) /Unix (/usr/bin/xcalc) /Mac (/Applications/Calculator.app) >> /S /lAUNCH /Pages 2 0 R /Type /Catalog endobj 2 0 obj /Kids [ 3 0 R ] /Count 1 /Type /Pages endobj 3 0 obj /Resources << /Font << /F1 5 0 R >> /MediaBox [ 0 0 795 842 ] /Parent 2 0 R /Contents 4 0 R /Type /Page endobj 4 0 obj /Length 1260 >>stream /F1 30 Tf 350 750 Td 20 TL 1 Tr (calc.pdf) Tj /F1 15 Tf 233 690 Td 20 TL 0 Tr (This page is empty but it should start calc :-D) Tj /F1 15 Tf 233 670 Td 20 TL (Dont be afraid of the pop-ups, just click them...) Tj /F1 14 Tf 75 620 Td 20 TL 2 Tr (Comments:) Tj /F1 12 Tf 75 600 Td 20 TL 0 Tr (Windows:) Tj ( - Foxit: runs calc.exe at the document opening without any user confirmation message \(!\) ) ' ( - Acrobat Reader *:) ' ( 1. popup proposing to open "calc.exe" \(warning\)) ' ( 2. starts "calc.exe") ' () ' (Mac:) ' ( - Preview does not support PDF keyword /lAUNCH) ' ( - Acrobat Reader 8.1.2: starts Calculator.app) ' () ' (Linux:) ' ( ! Assumes xcalc is in /usr/bin/xcalc) ' ( - poppler: does not support PDF keyword /lAUNCH) ' ( - Acrobat Reader 7: ) ' ( 1. popup telling it can not open "xcalc" \(dumb reasons\)) ' ( 2. popup proposing to open "xcalc" \(warning\)) ' ( 3. starts "xcalc") ' ( - Acrobat Reader 8.1.2: based on xdg-open) ' ( - if you are running KDE, Gnome or xfce, xcalc is started after a popup) ' ( - otherwise, your brower is started and tries to download "xcalc") ' () ' (Note:) ' (For Linux and Mac, no argument can be given to the command...) ' ETendstream endobj 5 0 obj /Subtype /Type1 /Name /F1 /BaseFont /Helvetica /Type /Font endobj xref 0000000000 65535 f 0000000010 00000 n 0000000234 00000 n 0000000303 00000 n 0000000457 00000 n 0000001774 00000 n trailer /Size 6 /Root 1 0 R /ID [ (bc38735adadf7620b13216ff40de2b26) (bc38735adadf7620b13216ff40de2b26) ] startxref 1866 %%EOF