Stack-based buffer overflow in R 3.4.4. Full exploitation on x86, but only RIP control with gadget analysis on x64 due to program constraints. The same vulnerability across two architectures, leading to different exploitation paths.
Stack-based buffer overflow in R 3.4.4. Full exploitation on x86, but only RIP control with gadget analysis on x64 due to program constraints. The same vulnerability across two architectures, leading to different exploitation paths.
This repository is part of the material I use when teaching memory corruption exploitation (in addition to my regular work, I also teach in different cybersecurity courses where I help train the next generation of reverse engineers).
CVE-2019-25485 is the case I use when I want students to work through the same vulnerability on two different architectures and see firsthand what changes between them. R 3.4.4 ships in both x86 and x64 versions, and the exact same overflow exists in both, the same GUI field, the same input handler, the same crash. Both are documented and exploited here as separate exercises:
R 3.4.4 is a statistical computing application, not a network service or a browser. The overflow is triggered through a desktop GUI field, which means the attack surface is completely different from every other case I teach. What makes this case useful for teaching:
R is a statistical computing and graphics environment available for Windows, macOS, and Linux. The vulnerability is in the GUI Preferences dialog, specifically the Language for menus and messages field, which copies user input into a fixed-size stack buffer without validating its length.
Key technical details:
R 3.4.4 processes the Language for menus and messages field by copying the supplied string into a fixed-size stack buffer without checking its length. A simplified version of the vulnerable logic looks like this:
char language_buffer[256];
strcpy(language_buffer, user_input);
Sending a sufficiently long string causes the copy to write past the end of the buffer, corrupting the stack until the saved return address is overwritten. When the function returns, the CPU loads the attacker-controlled value from the stack into RIP and attempts to jump to it.
On x64, Windows enforces canonical address validation before any jump takes place. A non-canonical value like 0x4141414141414141 triggers an immediate access violation before RIP is loaded, which means the crash looks different from x86, no clean RIP = 4141414141414141. The offset must be found by reading the cyclic pattern from the stack after the crash rather than from RIP directly.
The crash can be reproduced by pasting a long string into the language field. No authentication is required. Example using Python to generate the payload:
import struct
payload = b'A' * 400
with open('payload.txt', 'wb') as f:
f.write(payload)
Open R 3.4.4 x64
Edit -> GUI Preferences
Paste contents of payload.txt into Language for menus and messages
Click OK
The goal of this repository is not only to demonstrate the crash, but to walk through the complete exploitation process on both architectures, documenting what works on x86, what breaks on x64, and more importantly, why.
To keep the main README clean, the detailed exploitation notes, scripts, and debugger steps are placed inside the Vulnerability 📂 folder of this repository, organized into separate x86 and x64 subfolders.
There you will find the complete workflow for both architectures:
x86 - Full exploitation:
x64 - RIP control and exploitation analysis: