Dear Hiring Manger
resume.pdfhack10{flag_here}1. Challenge Overview
The scenario indicates that opening a candidate's resume (resume.pdf) resulted in arbitrary code execution that froze company systems. The objective is to perform digital forensics on the malicious PDF file, identify the trigger mechanism, and extract the hidden payload to recover the flag.
2. Initial Reconnaissance
Initial triage involved verifying the file type and inspecting system metadata, looking for clues indicative of malicious PDF artifacts.
1$ ls -la \&\& file resume.pdf \&\& exiftool resume.pdf2-rw-rw-r-- 1 nopalinto nopalinto 158277 Mar 27 10:09 resume.pdf3resume.pdf: PDF document, version 1.3, 1 page(s)4ExifTool Version Number : 13.505File Name : resume.pdf6Directory : .7File Size : 158 kB8File Type : PDF9MIME Type : application/pdf10PDF Version : 1.311[...]12Producer : Acrobat Distiller 5.0.5 (Windows)13Author : Luann Barnes14Creator : Luann Barnes15Title : Microsoft Word - Document6To determine if the PDF contained active content, we executed pdfid, which quickly flags suspicious embedded actions.
1$ pdfid resume.pdf || echo "pdfid not found, attempting grep" \&\& grep -a -oE "/JS|/JavaScript|/OpenAction|/Launch" resume.pdf2PDFiD 0.2.10 resume.pdf3 PDF Header: %PDF-1.34 obj 385 endobj 386 [...]7 /JS 18 /JavaScript 19 /AA 010 /OpenAction 13. Analysis / Forensics Path
The pdfid scan confirmed the presence of exactly one /OpenAction trigger and one embedded /JavaScript payload. We utilized pdf-parser to locate the specific objects holding this code.
1$ pdf-parser -a resume.pdf2[...]3Search keywords:4 /JS 1: 55 /JavaScript 1: 56 /OpenAction 1: 1Finding that Object 5 held the JavaScript, we dumped its contents.
1$ pdf-parser -o 5 -w resume.pdf | xxd1$ pdf-parser -o 5 resume.pdf2[...]3obj 5 04 Type: /Action5 Referencing: 6 <<7 /JS '(\\\\n var a=["BOPCd","0edrK"," 1i+m"];\\\\n var b=["VBeX","U8:","ddd8$"];\\\\n eval(atob(a.join("")+b.join("")));\\\\n )'9 /S /JavaScript10 /Type /Action11 >>The core logic attempts to assemble two arrays (a and b) into a single string: BOPCd0edrK 1i+mVBeXU8:ddd$.
While the script attempts to decode this using atob (a standard JavaScript function for Base64 decoding), there is an anomaly: the string contains characters like : and $ which are strictly invalid in standard Base64 alphabets. Standard browsers will throw an InvalidCharacterError if evaluated.
In the context of PDF encoding schemes, however, the target string maps perfectly to the ASCII85 (Base85) character set (/ASCII85Decode), which utilizes characters from ! to u. The author deliberately named the function atob or obfuscated the routine to misdirect researchers into assuming Base64 formulation.
4. Exploitation / Recovery
Knowing that the payload is actually encoded in Ascii85 (ignoring whitespaces), we can build an offline decoder in Python. By bypassing the malicious execution framework and extracting the exact arrays directly, we decode the string without triggering the payload bomb.
Solver Script (solve.py):
1import base642# Arrays extracted from PDF Object 5:3js_a = ["BOPCd", "0edrK", " 1i+m"]4js_b = ["VBeX", "U8:", "ddd$"]5# Reconstruct the obfuscated payload6payload = "".join(js_a) + "".join(js_b)7# Decode via ASCII85 (Standard PDF obfuscation encoding format)8flag = base64.a85decode(payload.encode('ascii')).decode('utf-8')9print(f"Recovered Flag: {flag}")Running the solver successfully strips the execution trap and recovers the flag in plaintext:
1$ python3 solve.py23Recovered Flag: hack10{M4l1ci0s_PDF}5. Flag
6. Summary of Approach & Key Takeaways
Initial Recon: Mapped PDF structure using pdfid to confirm the presence of /OpenAction and /JS objects which are notoriously used for malware delivery or system freezing routines.
Payload Extraction: Dissected the document using Didier Stevens' pdf-parser to extract the literal string block held within Object 5.
Deobfuscation/Analysis: Identified that the payload was structured as a split string passed to an eval(atob(...)) wrapper.
Encoding Recognition: Noticed the presence of invalid Base64 delimiters ($, :) within the joined string, correctly pivoting the investigation to Adobe's native ASCII85 (/ASCII85Decode) structure.
Recovery: Reassembled the arrays and ran them through Python's base64.a85decode() library to cleanly extract the flag.
Takeaway: Never blindly trust variables or standard function naming conventions (like atob) in CTF obfuscation scenarios. Threat actors (and challenge developers) often leave red herring wrappers mapping to completely different underlying encoding standards (like ASCII85) explicitly present in the document type specs.