Full Report
The authors of this post competed in the Paradigm CTF in 2023. One of the challenges was a Solana Jump Oriented Programming (JOP) challenge. The idea was to adapt a traditional binary exploitation technique for Solana. Solana programs can have memory corruption issues. So, having a mechanism to achieve an arbitrary CPI is a great challenge idea. The vulnerable program has three instructions: a write-what-where primitive, a CPI to a non-existent program and a jump to an arbitrary address. The test environment is a standard Solana node. The competition criteria is that the program contains a PDA with the seed "flag" with a length of 0x1337 and the first bytes being equal to 0x4337. Although you're limited to only a single instruction in the state of the VM (because most things are temporary), we can actually use the primitives above to execute arbitrary instructions. The goal is to find a way to CPI into the system program with controlled parameters. When looking at the assembly in Binary Ninja, they found a gadget that allows for calling sol_invoke_signed_rust as long as the proper data is in place on the Stack. To store the fake parameters, they can be stored directly in the instruction's input data. Using the write primitive, pointers to this information can be added to the stack. A pretty neat post on binary exploitation within Solana!
Analysis Summary
# Research: Solana: Jumping Around in the VM
## Metadata
- **Authors:** Nicola Vella, Robert Chen
- **Institution:** OtterSec (osec.io)
- **Publication:** OtterSec Blog / Paradigm CTF 2023 Analysis
- **Date:** December 11, 2023
## Abstract
This research explores the adaptation of Jump-Oriented Programming (JOP) from traditional binary exploitation to the Solana BPF (Berkeley Packet Filter) Virtual Machine. By analyzing a specific CTF challenge, the authors demonstrate how a series of memory corruption primitives—specifically arbitrary write and arbitrary jump—can be chained to bypass VM constraints and execute unauthorized Cross-Program Invocations (CPI).
## Research Objective
The research aims to answer: How can a high-level memory corruption vulnerability in a Solana program be escalated to full program control, specifically achieving an arbitrary CPI to the System Program?
## Methodology
### Approach
The researchers utilized a "JOP chain" strategy. They identified a gadget within the Solana BPF VM's compiled code that allows for calling `sol_invoke_signed_rust`. By using a "write-what-where" primitive to populate the stack with fake parameters and an "arbitrary jump" primitive to divert execution flow, they bypassed the high-level Rust safety checks.
### Dataset/Environment
- **Environment:** A standard Solana node test environment.
- **Target:** A custom eBPF program with three intentionally vulnerable instructions:
1. A volatile memory write (write-what-where).
2. A CPI to a null program.
3. An arbitrary function pointer call (jump-to-address).
### Tools & Technologies
- **Binary Ninja:** Used for reverse engineering the BPF bytecode and identifying functional gadgets.
- **Solana BPF VM:** The execution environment and target of the exploit.
- **Rust/eBPF:** The language and instruction set architecture of the vulnerable program.
## Key Findings
### Primary Results
1. **VM Escape via Gadgets:** Even within a sandboxed VM, traditional binary exploitation techniques like JOP are viable if program instructions allow for arbitrary jumps.
2. **Stack Manipulation:** By calculating the specific memory addresses of VM call frames (e.g., `0x200000000 + 0x2000 * depth`), an attacker can precisely place "fake" `AccountInfo` and `Instruction` structures.
3. **Instruction Chaining:** The researchers successfully bypassed the "single instruction" limit of the test environment by recursively calling the `process` function, effectively creating a multi-stage exploit within one transaction.
### Novel Contributions
- **First Public Demonstration of JOP on Solana:** While Solana vulnerabilities are often logic-based, this research highlights the danger of low-level memory unsafety in the VM.
- **Deterministic Stack Mapping:** Providing a formulaic approach to locate call frames within the Solana VM's memory space.
## Technical Details
The exploit follows a sophisticated sequence:
1. **Parameter Placement:** The attacker stores the "Create Account" instruction data directly in the transaction's input data.
2. **Stack Preparation:** Using the write primitive, they write pointers to this input data onto the BPF stack at offset locations where `sol_invoke_signed_rust` expects to find its arguments (Account Infos, Seeds, etc.).
3. **The Jump:** They trigger the arbitrary jump primitive to land on a "CPI Gadget"—a segment of existing code that prepares the registers for a system call.
4. **Execution:** The VM executes a `sol_invoke_signed_rust` call with the attacker-controlled parameters, resulting in the creation of a PDA containing the "flag" data required by the challenge.
## Practical Implications
### For Security Practitioners
- **Memory Safety is Paramount:** In Solana, using `unsafe` Rust or `mem::transmute` can bypass all on-chain security guarantees, leading to full VM compromise.
- **Complexity of CPI:** CPIs are the primary vector for state change; securing the parameters passed to these calls is the most critical part of Solana security.
### For Defenders
- **Audit for Unsafe Blocks:** Rigorous auditing must focus on any use of `unsafe` pointers or direct memory manipulation.
- **Static Analysis:** Tools should flag arbitrary jumps or dynamic function pointer calls that do not have a defined allow-list of targets.
## Limitations
- **The Primitives:** The exploit relies on extremely powerful memory corruption primitives (arbitrary write and jump) which are rarely found together in production code unless via a significant compiler or VM bug.
- **Instruction Limits:** The exploit is limited by the maximum stack depth (64 frames) and the maximum transaction data size.
## Comparison to Prior Work
Traditional Solana research focuses on "Anchor" framework vulnerabilities (e.g., missing account checks). This research shifts the focus back to "Web2-style" binary exploitation, proving that low-level hardware-like vulnerabilities still exist in high-level blockchain environments.
## Real-world Applications
- **Exploit Development:** Provides a framework for developing exploits for zero-day vulnerabilities in the Solana VM or core programs.
- **Security Tooling:** Informs the development of fuzzers designed to find memory corruption in eBPF loaders.
## Future Work
- Exploring if similar JOP techniques can be applied to the Agave/Solana validator's native code execution.
- Investigating the impact of SIMD instructions in the BPF VM on memory isolation.
## References
- Vella, N., & Chen, R. (2023). *Solana: Jumping Around in the VM.* [osec[.]io/blog/2023-12-11-jumping-around-in-the-vm]
- *Reverse Engineering Solana with Binary Ninja.* [osec[.]io/blog/2022-08-27-reverse-engineering-solana]
- *Solana: An Auditor’s Introduction.* [osec[.]io/blog/2022-03-14-solana-security-intro]