Synapse Consulting
Home SynapseRM / TPRM Services Pricing About BlogCareersLabsContact
EN · FR
Test access Book a demo

PDF forensics · Metadata · Decoding · Didier Stevens tools

Anatomy of a booby-trapped PDF: the ORION capstone

A PDF tied to Project ORION was pulled from a suspect's workstation. It looks like an internal report, but three obfuscation techniques are hidden inside. Find them all, recover the hidden message, and tie the whole ORION investigation together.

~60 minEstimated time
exiftool · pdfid.py · pdf-parser.py · CyberChefTools
T1027 · T1059.007 · T1204.002MITRE ATT&CK
★★☆☆ IntermediatePDF forensicsCyberChef

The sample

Fileorion-challenge-03.pdf
SHA-256d7d364d73985683aaf496eec338d5f4a13cb0d0d3ae9eec7a9c6d1e9fde05348
Size11,447 bytes, 2 pages, PDF 1.4
ContextFound on the NORTHSEA-DEV workstation during an internal investigation

1. Scenario

During the investigation into the Project ORION leak, a PDF was recovered from the suspect's workstation. It presents itself as an internal quarterly report, but the DFIR team flagged anomalies in its structure.

Your job is to analyse the file with PDF forensic tools, identify the techniques used to hide information, and extract the IOCs that corroborate the earlier challenges.

🔗 ORION thread: this challenge is part of the same investigation as #01 (VBA maldoc), #02 (disk forensics) and #03 (OSINT attribution). The IOCs extracted here cross-reference the earlier results.

2. Objectives

3. Required tools

bash, Debian / Ubuntu / Kali
# exiftool
sudo apt-get install -y libimage-exiftool-perl

# Didier Stevens tools (pdfid + pdf-parser)
mkdir ~/pdf-tools && cd ~/pdf-tools
wget -q https://didierstevens.com/files/software/pdfid_v0_2_9.zip
wget -q https://didierstevens.com/files/software/pdf-parser_v0_7_9.zip
unzip -q pdfid_v0_2_9.zip
unzip -q pdf-parser_v0_7_9.zip

💡 CyberChef runs online at gchq.github.io/CyberChef. The recipe buttons below open the right recipe directly.

bash, working directory
mkdir -p ~/lab04 && cd ~/lab04
cp /path/to/orion-challenge-03.pdf .
sha256sum orion-challenge-03.pdf
# d7d364d73985683aaf496eec338d5f4a13cb0d0d3ae9eec7a9c6d1e9fde05348

4. Step-by-step analysis

1

Initial triage

pdfinfo · strings

Always start by identifying what you have before going deep.

bash
pdfinfo orion-challenge-03.pdf
output
Title:           Project ORION -- Q3 Assessment Report
Author:          alex.m
Creator:         LibreOffice 24.2 -- AlexM workstation
Producer:        Microsoft Word for Microsoft 365
CreationDate:    Tue Jun 16 07:11:00 2026 UTC
Pages:           2
JavaScript:      no
PDF version:     1.4

🚩 JavaScript: no, but that is wrong. pdfinfo uses a heuristic that looks for a /Names /JavaScript namespace in the catalog. Our JS lives in an /Action object, so pdfinfo misses it. We prove that in step 3.

2

Metadata analysis, the discordance IOC

exiftool

exiftool reads every field of the /Info dictionary and presents it clearly. Look for what does not add up.

bash
exiftool orion-challenge-03.pdf
output
Title       : Project ORION -- Q3 Assessment Report
Author      : alex.m
Subject     : North Sea Digital / Internal research
Keywords    : ORION NSD confidential Q3 2026
Creator     : LibreOffice 24.2 -- AlexM workstation
Producer    : Microsoft Word for Microsoft 365
Create Date : 2026:06:16 09:11:00+02:00

🔴 IOC, Creator / Producer discordance: Creator claims LibreOffice, Producer claims Microsoft Word. These two tools do not coexist in a single legitimate PDF production chain. The Producer field was edited by hand after generation, a common way to muddy the file's origin.

💡 Creation date: 2026-06-16 09:11 CEST. If you did Challenge #02 (disk forensics), that time should ring a bell: it is the exact moment the orion-export.zip archive was created on alex's machine.

3

JavaScript detection, pdfid.py vs pdfinfo

pdfid.py

pdfid.py does no semantic analysis, it counts PDF keyword occurrences in the raw bytes. That is far harder to fool than pdfinfo's heuristics.

bash
python3 ~/pdf-tools/pdfid.py orion-challenge-03.pdf
output
PDFiD 0.2.9 orion-challenge-03.pdf
 PDF Header: %PDF-1.4
 obj                   10
 stream                 3
 /Page                  2
 /JS                    1
 /JavaScript            1
 /OpenAction            1
 /Launch                0
 /EmbeddedFile          0

🚩 /JS 1, /JavaScript 1, /OpenAction 1: the three together are characteristic of a PDF that runs JavaScript on open. pdfinfo said JavaScript: no. Lesson: never trust a single tool.

bash
python3 ~/pdf-tools/pdf-parser.py --search /JavaScript orion-challenge-03.pdf
output
obj 8 0
 Type: /Action

  << /Type /Action
     /S /JavaScript
     /JS (app.alert({cMsg:'ORION verification required. Token: ORION-Q3-NSD',
                     cTitle:'Project ORION',nIcon:3}); )
  >>

💡 Here the JavaScript is benign (an app.alert()). In a real maldoc this action can trigger shellcode, a use-after-free exploit in the reader, or a download. The structure is identical, only the content of /JS changes.

4

Object and stream mapping

pdf-parser.py

Before decoding, map every stream and its encoding methods. This gives you the whole structure at a glance.

bash
python3 ~/pdf-tools/pdf-parser.py --search /Filter orion-challenge-03.pdf
output
obj 5 0
 Contains stream
  << /Length 618 /Filter /FlateDecode >>

obj 7 0
 Contains stream
  << /Length 879 /Filter [/ASCIIHexDecode /FlateDecode] >>

obj 10 0
 Contains stream
  << /Subtype /Image /Filter /FlateDecode >>
obj 1
Catalog
/OpenAction -> obj 8
obj 2
Info (metadata)
Creator != Producer
obj 3
Pages
2 pages: obj 4 + obj 6
obj 4
Page 1
/Contents -> obj 5
obj 5
Page 1 stream
/FlateDecode, 618 B
obj 6
Page 2
/Contents -> obj 7
obj 7
Page 2 stream, hidden
[ASCIIHexDecode + FlateDecode]
obj 8
JavaScript action
/S /JavaScript, /OpenAction
obj 9
Font Helvetica
Type1, shared p1 + p2
obj 10
Image XObject (logo)
/DeviceRGB, /FlateDecode
5

Decode page 1, FlateDecode

pdf-parser.py · CyberChef

Object 5 holds the page-1 stream compressed with zlib (FlateDecode). Two methods: let pdf-parser.py do it, or extract the raw bytes and decode by hand in CyberChef.

bash
python3 ~/pdf-tools/pdf-parser.py --object 5 --filter orion-challenge-03.pdf
output
Stream b'BT\n/F1 20 Tf 50 750 Td (PROJECT ORION) Tj\n/F1 11 Tf 0 -35 Td
(Q3 Assessment Report -- North Sea Digital) Tj\n0 -18 Td
(Classification: INTERNAL -- NOT FOR DISTRIBUTION) Tj ...'
compressed bytes (zlib)Raw InflatePDF operators in clear
🔬 Open the CyberChef recipe, Raw Inflate
6

Decode page 2, ASCIIHexDecode + FlateDecode

pdf-parser.py · CyberChef

Object 7 uses a chain of two filters: the content is ASCII hex first, itself zlib-compressed. To decode, apply the operations in the reverse order of the /Filter list, right to left.

raw ASCIIHexFrom HexRaw InflateORION memo in clear
bash
python3 ~/pdf-tools/pdf-parser.py --object 7 --filter orion-challenge-03.pdf
output
ORION INTERNAL MEMO -- RESTRICTED
Stage 2 transfer confirmed.
Package delivered via USB device. Serial: SN-LAB-042.
Label: TRANSFER
Await signal from N0rthSea before proceeding to stage 3.
Verification token: ORION-{d3c0d3d}-Q3-N0rthS3a
Stream encoding: [/ASCIIHexDecode /FlateDecode]
🔬 Open the CyberChef recipe, From Hex then Raw Inflate

✅ The memo reveals the token ORION-{d3c0d3d}-Q3-N0rthS3a and confirms the transfer over USB device SN-LAB-042 labelled TRANSFER, the two artefacts identified in the disk-forensics Challenge #02.

5. IOC summary

TypeValueSource
MetadataAuthor: alex.mexiftool, /Info obj 2
IOC discordanceCreator: LibreOffice 24.2 / Producer: Microsoft Wordexiftool, contradictory fields
JavaScript/S /JavaScript, /OpenAction obj 8pdfid.py, missed by pdfinfo
TokenORION-{d3c0d3d}-Q3-N0rthS3aobj 7, ASCIIHex+FlateDecode decoded
USB deviceSerial: SN-LAB-042, Label: TRANSFERobj 7, internal memo
PersonaN0rthSea, stage 3 mentionedobj 7, internal memo
Timestamp2026-06-16 09:11 CEST (UTC+2)exiftool, CreationDate

Correlation with the other labs

Challenge #01, VBAalex.m -> AlexM, same author as in the Word maldoc
Challenge #02, diskSN-LAB-042, TRANSFER, same USB identified in activity.log
Challenge #02, disk09:11 CEST, exact creation time of orion-export.zip
Challenge #03, OSINTN0rthSea, Onion persona linked to AlexM via the PGP fingerprint

6. Answer key

Did you find all three techniques and extract every IOC?

Reveal the answer key

The three techniques to find:
1. Creator/Producer discordance in the metadata (obj 2)
2. JavaScript embedded via /OpenAction (obj 8), missed by pdfinfo
3. Double-encoded stream [ASCIIHexDecode + FlateDecode] (obj 7)

Why does pdfinfo miss the JavaScript?

pdfinfo looks for a /Names << /JavaScript ... >> structure in the catalog, the usual pattern for AcroForm forms with JS. Our action uses /OpenAction -> /S /JavaScript directly, without the /Names namespace. It is an implementation difference, not a limitation. pdfid.py counts raw string occurrences and catches both patterns.

Key takeaways

  • Always cross-check at least two tools, a single tool can have blind spots.
  • A Creator/Producer discordance is a reliable IOC because it requires post-generation tampering.
  • The [/ASCIIHexDecode /FlateDecode] chain decodes right to left: From Hex first, then Raw Inflate.
  • The token ORION-{d3c0d3d}-Q3-N0rthS3a ties all four labs together, it is the pivot artefact of the investigation.

7. References

PDF Tools, Didier Stevens

The reference suite for PDF forensics: pdfid, pdf-parser, make-pdf.

ExifTool, Phil Harvey

Metadata extraction for 150+ formats including PDF, DOCX, images.

CyberChef, GCHQ

Raw Inflate, From Hex, From Base64, XOR, every decoding recipe in one tool.

MITRE T1027, Obfuscated Files

Obfuscation techniques in malicious files: encoding, compression, encryption.

MITRE T1059.007, JavaScript

Code execution via JavaScript embedded in PDF or HTML documents.

PDF Reference 1.7, Adobe

The full PDF format specification: object structure, filters, actions.

Entirely fictional environment, for educational use only. The embedded JavaScript is a benign app.alert().

Synapse Consulting

A Belgium-based provider of cybersecurity solutions, and the team behind SynapseRM / TPRM.

PLATFORM
SynapseRM / TPRM Pricing Test accessPresentation (PDF)
SERVICES
Governance Operational Training
COMPANY
About Contact Blog Labs Careers Privacy & cookies
Brussels, Belgium