SACK: Systematic Generation of Function Substitution Attacks Against Control-Flow Integrity

Zhechang Zhang

Network and Distributed System Security (NDSS) Symposium 2026 · Day 2 · Systems Security

Overview

This talk presents SACK, the first systematic framework for automatically constructing function substitution attacks against programs protected by fully precise static Control-Flow Integrity (CFI). While CFI has been the principal defense against control-flow hijacking for over a decade, SACK demonstrates that even the strongest possible static CFI -- where every allowed target must be triggered by some benign input -- can be systematically bypassed by substituting one legitimate target for another within the allowed set.

Watch on YouTube · Slides

Visual summary for SACK: Systematic Generation of Function Substitution Attacks Against Control-Flow Integrity by Zhechang Zhang
Visual summary for SACK: Systematic Generation of Function Substitution Attacks Against Control-Flow Integrity by Zhechang Zhang

Key moments

  1. 0:00 Control-flow hijacking and CFI fundamentals
  2. 2:00 Function substitution attacks: bypassing even fully precise CFI
  3. 3:00 SQLite safe mode bypass: the motivating example
  4. 6:00 LLM-assisted security oracle generation from documentation
  5. 8:00 Attack engine: automated substitution and violation checking
  6. 10:00 Results: 22 oracles, 52 function pointers, hundreds of attacks
  7. 11:00 V8 exploit demo: swapping removedirectory to system()
  8. 12:30 Q&A: V8 sandbox escape implications and comparison to data-oriented attacks

SACK: Systematic Generation of Function Substitution Attacks Against Control-Flow Integrity

Speakers: Zhechang Zhang

Conference: NDSS Symposium

YouTube: https://www.youtube.com/watch?v=QCrHvmpbYUA

Overview

This talk presents SACK, the first systematic framework for automatically constructing function substitution attacks against programs protected by fully precise static Control-Flow Integrity (CFI). While CFI has been the principal defense against control-flow hijacking for over a decade, SACK demonstrates that even the strongest possible static CFI -- where every allowed target must be triggered by some benign input -- can be systematically bypassed by substituting one legitimate target for another within the allowed set.

The framework combines dynamic target collection, LLM-assisted security oracle construction, and automated substitution testing to find hundreds of attacks across seven applications. Key results include breaking 18 out of 22 security oracles, leveraging 52 function pointers, and building five end-to-end exploits using historical CVEs, including a V8 JavaScript engine exploit that achieves arbitrary command execution by swapping a directory removal function pointer to system().

Background

▶ Watch: Control-flow hijacking and CFI fundamentals (0:00)

Control-flow hijacking attacks have been exploited for over 30 years. The basic chain starts with a memory safety bug (like buffer overflow), which is used to corrupt control data (function pointers, return addresses), diverting execution to attacker-controlled logic. Control-Flow Integrity (CFI) defends against this by checking whether each indirect control-flow transfer destination is in an allowed set, blocking invalid targets.

Years of research have refined CFI's allowed target sets, progressing toward fully precise static CFI -- the strongest protection achievable by static analysis, where every allowed target must be triggered by some benign input. Prior work on control-flow bending demonstrated that even under fully precise static CFI, attackers can still substitute one legitimate target for another to achieve meaningful attacks. However, the previous paper manually constructed only two attacks (one arbitrary code execution in Apache, one file manipulation in Wireshark), with no systematic or automated approach.

SACK fills this gap by automating the discovery of function substitution attacks, demonstrating that this class of vulnerability is far more prevalent than the handful of manually-constructed examples suggested.

Key Findings

▶ Watch: SQLite safe mode bypass: the motivating example (3:00)

Sub-attacks are practical and prevalent: Across seven tested applications, SACK found hundreds of attacks leveraging 52 function pointers, breaking 18 out of 22 security oracles. This demonstrates that function substitution attacks are not rare corner cases but a systematic weakness in CFI-protected software.

22 security oracles across seven programs: The framework identified 22 security features that can serve as attack targets, including 9 related to dangerous operations, 6 related to authentication, 3 related to logging, and 2 related to connection limiting.

Five end-to-end exploits: Using historical CVEs, the researchers built five complete exploits demonstrating real-world exploitation paths, including a V8 exploit that escalates a memory corruption vulnerability to arbitrary command execution.

LLMs effectively generate security oracles: Using GPT-4.1 at approximately $0.60 per oracle, the framework automatically generates structured security oracles from program documentation, making the oracle construction process both cheap and scalable.

Dynamic target collection avoids false positives: By collecting targets from benign executions rather than static analysis, the framework ensures all substitution candidates are genuinely allowed by fully precise static CFI, avoiding overestimation issues in static approaches like TypeDive, TFA, and core graph.

Technical Deep Dive

▶ Watch: Attack engine: automated substitution and violation checking (8:00)

SACK operates through three main components:

Dynamic Target Collection: Rather than using static analysis (which overestimates allowed targets), the framework runs programs with test suites and synthesized inputs, collecting the actual function pointer targets triggered during benign execution. This guarantees that all collected targets comply with fully precise static CFI -- any substitution using these targets would pass CFI checks.

Security Oracle Construction: Security features of target applications are converted into security oracles that define: the claim (what the feature protects), how to enable it, inputs to trigger it, and the expected outcome. The process uses LLMs to parse official documentation and generate structured oracles. For example, SQLite's safe mode prevents dangerous SQL operations -- the oracle captures that enabling safe mode with -dsafe should block read_file operations.

Attack Engine: A two-component system performing automated substitution and verification:

  1. Function Substitution: For each function pointer, iterates through all dynamically-collected targets, substituting the original target with each candidate
  2. Violation Check: Compares the output after substitution against the oracle's expected outcome; any deviation indicates a potential attack

The SQLite safe mode bypass illustrates the complete flow: the function pointer xAuth normally points to safe_mode_auth() (which performs security checks) but can also legitimately point to idx_auth_callback() (which only checks remaining memory). Substituting the latter bypasses the safe mode entirely, allowing execution of previously blocked dangerous operations like read_file.

The V8 exploit demonstrates escalation from a historical CVE: a function pointer in the OS operations dispatcher is substituted from remove_directory to system(). Since both are legitimate targets in the allowed set, CFI permits the substitution, and the attacker gains arbitrary command execution.

Demo / Proof of Concept

▶ Watch: Results: 22 oracles, 52 function pointers, hundreds of attacks (10:00)

The talk included a live demo of the V8 exploit. Starting with an old version of V8 containing the historical CVE:

  1. First, a normal remove_directory call is shown executing but crashing due to incorrect argument types (expecting a path and boolean)
  2. The exploit corrupts the function pointer, substituting remove_directory with system()
  3. When remove_directory is called again, system() is executed instead, spawning a shell

The demo effectively shows that CFI-protected software can be exploited without violating any CFI policy, because the substituted target is in the allowed set.

Defensive Implications

▶ Watch: Q&A: V8 sandbox escape implications and comparison to data-oriented attacks (12:30)

SACK delivers a clear message: fully precise static CFI is not sufficient to prevent meaningful exploitation. The allowed target sets in real-world software are large enough to contain security-relevant substitutions across authentication bypasses, dangerous operation execution, logging evasion, and connection limit circumvention.

Several defensive directions emerge:

Context-sensitive CFI: Incorporating execution context (call stack, program state) into CFI checks could distinguish between legitimate uses of a function pointer and attacker-induced substitutions, but at significant performance cost.

Runtime security feature verification: Rather than relying solely on CFI to prevent misuse, security-critical features should include redundant verification mechanisms that cannot be bypassed by a single function pointer substitution.

Reducing allowed target set sizes: Programs should be designed to minimize the number of legitimate targets for each function pointer, reducing substitution opportunities. This is an argument for more fine-grained function pointer typing and compartmentalization.

Complementary defenses: The assumption model includes DEP and shadow stacks alongside CFI. Data-oriented attacks (mentioned in Q&A) represent a related bypass class. Defense-in-depth remains essential, with CFI as one layer rather than a complete solution.

The open-source release of SACK enables security teams to audit their own CFI-protected applications for substitution vulnerabilities.

Key Takeaways

  • Even fully precise static CFI -- the strongest possible static defense -- can be systematically bypassed through function substitution attacks
  • SACK automatically found hundreds of attacks across seven applications, leveraging 52 function pointers and breaking 18 of 22 security features
  • LLM-assisted security oracle construction at ~$0.60 per oracle makes this framework scalable and cheap to deploy
  • Five end-to-end exploits including a V8 command execution demonstrate real-world exploitability
  • Dynamic target collection from benign executions ensures all substitutions comply with CFI policy, avoiding false positives from static over-approximation
  • Security features like SQLite safe mode, authentication checks, and logging can all be bypassed through legitimate function pointer target substitution

About the Speaker(s)

Zhechang Zhang (presenting as "Joan") presented this work at NDSS. The research represents a significant advance in understanding the fundamental limitations of CFI as a defense mechanism. The SACK framework is available as open source for the security community to evaluate CFI-protected applications.

Reviews

Dr. Zero (Offensive Security Researcher) — MUST SEE

A genuinely important contribution to offensive security research. SACK systematically demonstrates that fully precise static CFI -- the gold standard defense against control-flow hijacking -- is fundamentally insufficient against function substitution attacks. Hundreds of attacks across seven applications, five end-to-end exploits including a V8 command execution, and a framework that uses LLMs to automate security oracle construction for $0.60 each. This is real exploitation research with deep implications for memory safety defenses.

Heather Calloway (CISO) — USEFUL

A technically impressive demonstration that CFI -- a widely deployed defense mechanism -- has fundamental limitations that allow systematic bypass through function substitution. While the immediate audience is memory safety researchers and exploit developers, security leaders should understand that CFI-protected software is not immune to control-flow attacks, and defense-in-depth strategies remain essential.

→ Top-rated talks at Network and Distributed System Security (NDSS) Symposium 2026

All talks from Network and Distributed System Security (NDSS) Symposium 2026