Identifying Syscall-Guard Variables for Data-Only Attacks
This talk introduces VIPER, a framework designed to automatically identify security-critical non-control data, specifically 'syscall-guard variables,' which are used to protect sensitive system calls. By leveraging branch forcing and backward data-flow analysis, the researchers demonstrate how flipping these variables can bypass security checks to achieve data-only attacks. The presentation showcases the effectiveness of this technique by discovering 34 previously unknown syscall-guard variables and executing four new data-only exploits against SQLite and the V8 JavaScript engine. The tool is released as an open-source resource for security researchers.
Beyond Control-Flow: Exploiting Syscall-Guard Variables for Data-Only Attacks
TLDR: Researchers have introduced VIPER, a framework that automates the discovery of security-critical non-control data known as syscall-guard variables. By identifying and flipping these specific variables, attackers can bypass security checks and execute unauthorized system calls without ever needing to hijack control flow. This technique effectively renders traditional control-flow integrity protections useless, as the exploit relies entirely on manipulating application state.
Control-flow hijacking has been the bread and butter of exploit development for decades. We spend our time hunting for buffer overflows or use-after-free vulnerabilities to overwrite return addresses or function pointers. We have built entire defensive ecosystems around this, from stack canaries to Control-Flow Integrity (CFI) implementations. But while we were busy hardening the execution path, we left the data layer wide open. Data-only attacks do not care about your ROP chains or your shadow stacks. They care about the variables that dictate what your application is allowed to do.
The Mechanics of Syscall-Guard Variables
Most applications rely on specific variables to gate access to sensitive system calls. Think of a flag like authenticated in a login routine or a configuration string that defines which binaries a web server is permitted to execute. These are not control-flow targets; they are state variables. If an attacker can flip a single bit in memory, they can bypass the logic that checks these variables, effectively tricking the application into performing actions it was never intended to allow.
The research team behind VIPER identified a specific subset of this data: syscall-guard variables. These are the variables directly involved in the conditional branches that precede a system call. If you can identify these variables and find a way to corrupt them, you gain the ability to force the application to execute a system call with parameters of your choosing.
How VIPER Automates the Hunt
Finding these variables manually is a nightmare. It requires deep knowledge of the codebase and tedious manual inspection. VIPER changes the game by automating this process through two primary components: Branch Forcing and backward data-flow analysis.
The framework first performs a dry run of the target application to record all triggered branches and system calls. It then systematically flips every branch encountered during execution. If flipping a branch results in a new, security-sensitive system call being triggered, VIPER flags that branch as a "syscall-guard branch." The variables governing that branch are then identified as syscall-guard variables.
Once identified, the framework performs a backward data-flow analysis to determine if these variables are actually corruptible. It evaluates two metrics: the memory location (global variables are generally easier to target than stack variables) and the number of memory-write instructions that influence the variable's value.
Real-World Impact: SQLite and V8
The researchers demonstrated the power of this approach by targeting SQLite and the V8 JavaScript engine. In SQLite, they identified seven syscall-guard variables and successfully built three new data-only exploits. One of these exploits targeted the p->doxdgOpen variable. By corrupting this variable, an attacker can force SQLite to execute arbitrary commands.
Here is the logic flow for that specific vulnerability:
void output_reset(ShellState *p) {
if (p->doxdgOpen) {
char *zCmd = mprintf("xdg-open %s", p->zTempFile);
system(zCmd); // Arbitrary command execution
}
}
If you have an arbitrary write primitive, you do not need to worry about bypassing ASLR to redirect execution flow. You simply write a non-zero value to the memory address of p->doxdgOpen. The next time the application calls output_reset, the if condition evaluates to true, and your command executes. This is a clean, reliable exploit that bypasses most modern exploit mitigations.
In the V8 engine, the team leveraged CVE-2021-30632, a type confusion vulnerability, to target the options.enable_os_system variable. By flipping this single global variable, they enabled the os.system function in a context where it should have been restricted, leading to shell execution.
Why This Matters for Your Next Engagement
For those of us performing penetration tests or bug bounty research, this research shifts the focus. When you find a memory corruption bug, do not just look for ways to gain code execution via ROP. Look for the state variables that control the application's security policy. If you can find a way to influence a variable that guards a sensitive system call, you have a much more stable and stealthy exploit path.
Defenders need to recognize that memory safety is not just about preventing control-flow hijacking. Protecting sensitive state variables is equally critical. While there is no silver bullet, developers should focus on minimizing the exposure of these variables, particularly those stored in global memory, and implementing stricter access controls on the data structures that hold them.
The release of VIPER and the accompanying exploit examples provides a blueprint for how to approach these vulnerabilities. Stop looking only at the instruction pointer. Start looking at the data that tells the application what to do. The next time you are staring at a heap dump, ask yourself which variables are actually running the show.
Vulnerability Classes
Tools Used
OWASP Categories
All Tags
Up Next From This Conference

How to Read and Write a High-Level Bytecode Decompiler

Opening Keynote: Black Hat Asia 2024

AI Governance and Security: A Conversation with Singapore's Chief AI Officer
Similar Talks

The Dark Side of Bug Bounty

On Your Ocean's 11 Team, I'm the AI Guy

