【实战】 Linux 后门系列 Vim 后门

0x00 简介

Vim(Vi IMproved)是一款强大的文本编辑器。它支持多种编辑模式,具有丰富的编辑功能和高度可定制性。Vim 提供了代码折叠、语法高亮、自动补全等功能,适用于程序员和文本编辑爱好者。通过个性化配置和插件系统,用户可以定制快捷键、颜色方案等。Vim 还可以作为图形化编辑器,在不同操作系统上运行,并与版本控制系统集成。总之,Vim 是一款高效、灵活的编辑器,为用户提供优秀的编辑体验。

  • 0x00 简介

  • 0x01 Vim 配置加载过程

    • 1. vim 配置说明

    • 2. 确定已加载的配置

    • 3. 系统级配置文件解析

    • 4. 用户配置文件解析

    • 5. 用户层ex编辑器配置文件

    • 6. 默认配置文件

    • 7. 自动加载的配置文件

    • 8. vim 配置加载过程初步总结

  • 0x02 Vim 配置加载细节问题

    • 1. 系统配置与用户配置

    • 2. 用户配置与默认配置文件

    • 3. 用户配置与用户配置

    • 4. runtimepath 与 $VIMRUNTIME

    • 5. 哪些目录自动加载

    • 6. 哪些文件自动加载

    • 7. 自动加载好奇的知识点

  • 0x03 vim 后门说明

  • 0x04 vim 自身文件后门

    • 1. 查找 vim 命令程序位置

    • 2. 制作后门文件

  • 0x05 配置文件后门

    • 1. 执行系统命令

    • 2. 屏蔽控制台输出

    • 3. 规避 vim 阻塞

  • 0x06 features

    • 1. +libcall

    • 2. +packages

    • 3. +python3

    • 4. +user_commands

    • 5. +vim9script

  • 0x07 总结

  • 0x08 往期文章

0x01 Vim 配置加载过程

vim 配置加载过程简单描述就是先加载系统级别配置,之后加载个人用户配置,接下来以 Ubuntu 22.04 为例

图片

可以通过 vim --version 来进行查看各种文件的位置以及一些系统包含的插件


  
vim --version
   system vimrc file: "$VIM/vimrc"
     user vimrc file: "$HOME/.vimrc"
 2nd user vimrc file: "~/.vim/vimrc"
      user exrc file: "$HOME/.exrc"
       defaults file: "$VIMRUNTIME/defaults.vim"
  fall-back for $VIM: "/usr/share/vim"

1. vim 配置说明

  • 系统级别配置文件 $VIM/vimrc

  • 用户配置文件 $HOME/.vimrc

  • 次优先级用户配置文件 ~/.vim/vimrc

  • 用户层ex编辑器配置文件 $HOME/.exrc

  • 默认配置文件 $VIMRUNTIME/defaults.vim

  • 次默认配置文件 /usr/share/vim

其中 $VIM 是 vim 内置的变量而不是 Linux 的环境变量,当然 vim 也是可以使用 Linux 环境变量的

图片

图片

图片

图片

通过在vim的底线命令模式中 echo $变量名 来获取 vim 的配置文件地址

图片

图片

图片

图片

图片

图片

因此,在 Ubuntu Server 22.04 vim 默认配置为

  • 系统级别配置文件 $VIM/vimrc  ——> /usr/share/vim/vimrc -> /etc/vim/vimrc

  • 用户配置文件 $HOME/.vimrc  ——> ~/.vimrc

  • 次优先级用户配置文件 ~/.vim/vimrc

  • 用户层ex编辑器配置文件 $HOME/.exrc  ——> ~/.exrc

  • 默认配置文件 $VIMRUNTIME/defaults.vim ——> /usr/share/vim/vim82/defaults.vim

  • $VIM后备配置文件 /usr/share/vim

这些配置文件默认情况下并不是都存在


2. 确定已加载的配置

但是这些配置文件中可能还会引用其他配置文件,因此想要了解本次vim 请求加载了哪些配置文件可以通过在vim的底线命令模式中输入 scriptnames

图片

图片

Ubuntu Server 22.04 默认情况下是没有 ~/.vim 目录的

首先加载的是系统级配置文件 /usr/share/vim/vimrc , 之后根据系统级配置文件的内容加载了一些配置文件内容,默认没有发现用户级配置文件的加载

图片

可以看到默认并没有用户配置

3. 系统级配置文件解析

vim 配置文件有自己的一套 vim 脚本语法,具体可以通过下面的链接进行学习

https://devhints.io/vimscript

https://www.w3cschool.cn/vim/

其中 " 是注释符号, runtime! xxx.vim 表示强制重新加载 xxx.vim

/usr/share/vim/vimrc -> /etc/vim/vimrc

" All system-wide defaults are set in $VIMRUNTIME/debian.vim and sourced by
" the call to :runtime you can find below.  If you wish to change any of those
" settings, you should do it in this file (/etc/vim/vimrc), since debian.vim
" will be overwritten everytime an upgrade of the vim packages is performed.
" It is recommended to make changes after sourcing debian.vim since it alters
" the value of the 'compatible' option.

runtime! debian.vim

" Vim will load $VIMRUNTIME/defaults.vim if the user does not have a vimrc.
" This happens after /etc/vim/vimrc(.local) are loaded, so it will override
" any settings in these files.
" If you don't want that to happen, uncomment the below line to prevent
" defaults.vim from being loaded.
" let g:skip_defaults_vim = 1

" Uncomment the next line to make Vim more Vi-compatible
" NOTE: debian.vim sets 'nocompatible'.  Setting 'compatible' changes numerous
" options, so any other options should be set AFTER setting 'compatible'.
"set compatible

" Vim5 and later versions support syntax highlighting. Uncommenting the next
" line enables syntax highlighting by default.
if has("syntax")
  syntax on
endif

" If using a dark background within the editing area and syntax highlighting
" turn on this option as well
"set background=dark

" Uncomment the following to have Vim jump to the last position when
" reopening a file
"au BufReadPost * if line("'\"") > 1 && line("'\"") <= line("$") | exe "normal! g'\"" | endif

" Uncomment the following to have Vim load indentation rules and plugins
" according to the detected filetype.
"filetype plugin indent on

" The following are commented out as they cause vim to behave a lot
" differently from regular Vi. They are highly recommended though.
"set showcmd  " Show (partial) command in status line.
"set showmatch  " Show matching brackets.
"set ignorecase  " Do case insensitive matching
"set smartcase  " Do smart case matching
"set incsearch  " Incremental search
"set autowrite  " Automatically save before commands like :next and :make
"set hidden  " Hide buffers when they are abandoned
"set mouse=a  " Enable mouse usage (all modes)

" Source a global configuration file if available
if filereadable("/etc/vim/vimrc.local")
  source /etc/vim/vimrc.local
endif


去掉注释后

runtime! debian.vim

if has("syntax")
  syntax on
endif

if filereadable("/etc/vim/vimrc.local")
  source /etc/vim/vimrc.local
endif

分为三部分

runtime! debian.vim  强制重新加载 debian.vim

经过测试,这里 debian.vim 所在路径为 $VIMRUNTIME 的值(/usr/share/vim/vim82)的目录下

图片

经过测试,这里直接写绝对路径是不行的,必须是这个目录的相对路径

if has("syntax")
  syntax on
endif

这段代码检查当前 vim 是否支持语法高亮,如果支持则打开语法高亮

if filereadable("/etc/vim/vimrc.local")
  source /etc/vim/vimrc.local
endif

这段配置代码的意思是,如果文件/etc/vim/vimrc.local存在并且可读,则加载该文件

通过对系统级配置文件 /etc/vim/vimrc 进行分析,可以知道这个文件默认内容不多,主要就是开启语法高亮、重新加载配置文件 debian.vim 、引入 /etc/vim/vimrc.local

因此接下来分析 debian.vim 和 /etc/vim/vimrc.local

/usr/share/vim/vim82/debian.vim

这一看就是 debian 系操作系统特有的文件, Centos 以及 Rocky Linux 等没有这个文件,甚至系统级配置文件位置都不同

根据 /etc/vim/vimrc 中注释描述,将所有系统侧配置文件都放置在 /usr/share/vim/vim82/debian.vim 文件中,每次程序升级时,都有可能覆盖更新 /usr/share/vim/vim82/debian.vim 文件,因此一些个性化配置尽量在个人用户配置处进行

" Normally we use vim-extensions. If you want true vi-compatibility
" remove change the following statements
set nocompatible " Use Vim defaults instead of 100% vi compatibility
set backspace=indent,eol,start " more powerful backspacing

" Now we set some defaults for the editor
set history=50  " keep 50 lines of command line history
set ruler  " show the cursor position all the time

" modelines have historically been a source of security/resource
" vulnerabilities -- disable by default, even when 'nocompatible' is set
set nomodeline

" Suffixes that get lower priority when doing tab completion for filenames.
" These are files we are not likely to want to edit or read.
set suffixes=.bak,~,.swp,.o,.info,.aux,.log,.dvi,.bbl,.blg,.brf,.cb,.ind,.idx,.ilg,.inx,.out,.toc

" We know xterm-debian is a color terminal
if &term =~ "xterm-debian" || &term =~ "xterm-xfree86"
  set t_Co=16
  set t_Sf=[3%dm
  set t_Sb=[4%dm
endif

" Some Debian-specific things
if has('gui')
  " Must define this within the :if so it does not cause problems with
  " vim-tiny (which does not have +eval)
  function! <SID>MapExists(name, modes)
    for mode in split(a:modes, '\zs')
      if !empty(maparg(a:name, mode))
        return 1
      endif
    endfor
    return 0
  endfunction

  " Make shift-insert work like in Xterm
  autocmd GUIEnter * if !<SID>MapExists("<S-Insert>", "nvso") | execute "map <S-Insert> <MiddleMouse>" | endif
  autocmd GUIEnter * if !<SID>MapExists("<S-Insert>", "ic") | execute "map! <S-Insert> <MiddleMouse>" | endif
endif

" Set paper size from /etc/papersize if available (Debian-specific)
if filereadable("/etc/papersize")
  let s:papersize = matchstr(readfile('/etc/papersize', '', 1), '\p*')
  if strlen(s:papersize)
    exe "set printoptions+=paper:" . s:papersize
  endif
endif

这个配置文件中未包含对其他配置文件的引用

/etc/vim/vimrc.local

Ubuntu Server 22.04 中默认不存在这个文件

4. 用户配置文件解析

  • ~/.vimrc

  • ~/.vim/vimrc

图片

Ubuntu 默认不存在vim个人用户配置文件

5. 用户层ex编辑器配置文件

~/.exrc

图片

Ubuntu Server 22.04 默认不存在该配置文件

6. 默认配置文件

默认配置文件在没有个人用户的配置文件时使用,Ubuntu Server 22.04 默认无个人默认配置文件,因此默认情况下会启用默认配置文件

$VIMRUNTIME/defaults.vim ——> /usr/share/vim/vim82/defaults.vim

" The default vimrc file.
"
" Maintainer: Bram Moolenaar <Bram@vim.org>
" Last change: 2021 Nov 17
"
" This is loaded if no vimrc file was found.
" Except when Vim is run with "-u NONE" or "-C".
" Individual settings can be reverted with ":set option&".
" Other commands can be reverted as mentioned below.

" When started as "evim", evim.vim will already have done these settings.
if v:progname =~? "evim"
  finish
endif

" Bail out if something that ran earlier, e.g. a system wide vimrc, does not
" want Vim to use these default values.
if exists('skip_defaults_vim')
  finish
endif

" Use Vim settings, rather than Vi settings (much better!).
" This must be first, because it changes other options as a side effect.
" Avoid side effects when it was already reset.
if &compatible
  set nocompatible
endif

" When the +eval feature is missing, the set command above will be skipped.
" Use a trick to reset compatible only when the +eval feature is missing.
silent! while 0
  set nocompatible
silent! endwhile

" Allow backspacing over everything in insert mode.
set backspace=indent,eol,start

set history=200  " keep 200 lines of command line history
set ruler  " show the cursor position all the time
set showcmd  " display incomplete commands
set wildmenu  " display completion matches in a status line

set ttimeout  " time out for key codes
set ttimeoutlen=100 " wait up to 100ms after Esc for special key

" Show @@@ in the last line if it is truncated.
set display=truncate

" Show a few lines of context around the cursor.  Note that this makes the
" text scroll if you mouse-click near the start or end of the window.
set scrolloff=5

" Do incremental searching when it's possible to timeout.
if has('reltime')
  set incsearch
endif

" Do not recognize octal numbers for Ctrl-A and Ctrl-X, most users find it
" confusing.
set nrformats-=octal

" For Win32 GUI: remove 't' flag from 'guioptions': no tearoff menu entries.
if has('win32')
  set guioptions-=t
endif

" Don't use Ex mode, use Q for formatting.
" Revert with ":unmap Q".
map Q gq

" CTRL-U in insert mode deletes a lot.  Use CTRL-G u to first break undo,
" so that you can undo CTRL-U after inserting a line break.
" Revert with ":iunmap <C-U>".
inoremap <C-U> <C-G>u<C-U>

" Only do this part when Vim was compiled with the +eval feature.
if 1

  " Enable file type detection.
  " Use the default filetype settings, so that mail gets 'tw' set to 72,
  " 'cindent' is on in C files, etc.
  " Also load indent files, to automatically do language-dependent indenting.
  " Revert with ":filetype off".
  filetype plugin indent on

  " Put these in an autocmd group, so that you can revert them with:
  " ":augroup vimStartup | exe 'au!' | augroup END"
  augroup vimStartup
    au!

    " When editing a file, always jump to the last known cursor position.
    " Don't do it when the position is invalid, when inside an event handler
    " (happens when dropping a file on gvim) and for a commit message (it's
    " likely a different one than last time).
    autocmd BufReadPost *
      \ if line("'\"") >= 1 && line("'\"") <= line("$") && &ft !~# 'commit'
      \ |   exe "normal! g`\""
      \ | endif

  augroup END

  " Quite a few people accidentally type "q:" instead of ":q" and get confused
  " by the command line window.  Give a hint about how to get out.
  " If you don't like this you can put this in your vimrc:
  " ":augroup vimHints | exe 'au!' | augroup END"
  augroup vimHints
    au!
    autocmd CmdwinEnter *
   \ echohl Todo | 
   \ echo 'You discovered the command-line window! You can close it with ":q".' |
   \ echohl None
  augroup END

endif

" Switch syntax highlighting on when the terminal has colors or when using the
" GUI (which always has colors).
if &t_Co > 2 || has("gui_running")
  " Revert with ":syntax off".
  syntax on

  " I like highlighting strings inside C comments.
  " Revert with ":unlet c_comment_strings".
  let c_comment_strings=1
endif

" Convenient command to see the difference between the current buffer and the
" file it was loaded from, thus the changes you made.
" Only define it when not defined already.
" Revert with: ":delcommand DiffOrig".
if !exists(":DiffOrig")
  command DiffOrig vert new | set bt=nofile | r ++edit # | 0d_ | diffthis
    \ | wincmd p | diffthis
endif

if has('langmap') && exists('+langremap')
  " Prevent that the langmap option applies to characters that result from a
  " mapping.  If set (default), this may break plugins (but it's backward
  " compatible).
  set nolangremap
endif

在该配置文件中,也没有发现引入其他配置文件

7. 自动加载的配置文件

图片

通过我们对各种 vim 官方的各种配置文件进行分析,但是并没有发现图中的 /usr/share/vim/vim82/syntax/syntax.vim 以及下面一系列的配置文件的加载部分,也就是说除了配置文件以外,还有其他部分决定着加载一些配置文件

通过一些学习,我发现 vim 会自动加载 runtimepath 这个项(options) 值指向的目录中的部分目录下的配置文件,这段话有点绕,下面举例子

  • 查看 runtimepath 的值

    底线命令模式下 set runtimepath?

    图片

    图片

    可以看到,Ubuntu 默认的 vim runtimepath 的值为

    runtimepath=~/.vim,/var/lib/vim/addons,/etc/vim,/usr/share/vim/vimfiles,/usr/share/vim/vim82,/usr/share/vim/vimfi
    les/after,/etc/vim/after,/var/lib/vim/addons/after,~/.vim/after
    
  • 测试其中一个目录中新建 plugin 目录并放置 1.vim 配置文件

    以 /var/lib/vim/addons 目录为例

    图片

    图片

    默认情况是不启用行号的,接下来尝试在  /var/lib/vim/addons 目录新建 plugin 目录,并在其中创建 1.vim 配置文件,配置文件中写入 set number 来让 vim 显示行号

    图片

    图片

    图片

    图片

    配置成功生效

8. vim 配置加载过程初步总结

通过一些探索,默认情况下 vim 会加载如下配置文件

  • 系统级别配置文件 $VIM/vimrc

  • 用户配置文件 $HOME/.vimrc

  • 次优先级用户配置文件 ~/.vim/vimrc

  • 用户层ex编辑器配置文件 $HOME/.exrc

  • 默认配置文件 $VIMRUNTIME/defaults.vim

  • runtimepath 项的值所指向的路径内部分内容

0x02 Vim 配置加载细节问题

1. 系统配置与用户配置

1) 相同的配置项以谁为准

一般软件来说,遇到相同配置项,最终都是以用户配置为准,我们通过一个实验来测试 vim 是如何做的

实验思路:

  • 通过在系统配置 /etc/vim/vimrc 中配置 set background=dark ,

  • 用户配置 ~/.vimrc  中配置 set background=light

  • 测试最终vim背景颜色来判断最终结果

默认背景颜色为 dark

系统配置背景颜色为 dark

系统配置背景颜色为 dark

图片

用户配置背景颜色为白色

现在打开 1.txt 查看背景颜色

图片

图片

配置最终以用户配置为准,但是似乎背景颜色没有改成白色,难道是 ssh 连接的原因吗?通过图形化界面测试也是一样,推测可能是 Ubuntu 的终端或vim不支持设置背景颜色

通过 background  项的值可知,系统配置与用户配置遇到相同值的情况下,以用户配置为主

现在我们加了用户配置,我们看一下详细的配置加载情况

图片

可以看到, ~/.vimrc 是在 /usr/share/vim/vimrc 后加载的,也就是说可能是遇到相同配置项以后加载的配置文件为准,我们尝试在 /var/lib/vim/addons/plugin/1.vim 中添加 set background=dark

图片

图片

图片

图片

因此得出结论:vim 的配置文件在配置项相同的时候,以后加载的配置文件的结果为准

与常规软件的配置文件规则一样

其实在 vim 中可以在底线命令模式下输入 verbose set background? 来查看 background 这个项的值是来自哪个配置文件

图片

图片

2) 被覆盖的配置项会执行吗

上一个实验中被覆盖的 background 配置项,在未被覆盖前,系统配置文件中是否生效了呢?

肯定是生效过对吧,但是最为一个相对严谨的安全研究员,我们还是通过实验来验证一下

先科普 vim 配置文件中设置变量和打印变量的方法

设置变量
let g:my_variable = 'Hello, World!'

打印变量
echo g:my_variable

实验思路:

  • 在系统配置文件中设置变量 flag 变量值为 system

  • 在用户配置文件中打印 flag 变量

  • 在用户配置文件中设置 flag 变量值为 user

  • 在  /var/lib/vim/addons/plugin/1.vim  中打印 flag 变量

图片

图片

图片

现在尝试通过 vim 编辑 1.txt

图片

可以看出,虽然最终 flag 变量的值被修改了,但是系统配置中设置 flag 变量这个操作是成功了的,相信看到这里,部分小伙伴已经对后门有想法了,但请不要着急,这部分主要是探索 vim 配置详细加载情况

2. 用户配置与默认配置文件

1)  用户配置文件存在且不为空

在 /etc/vim/vimrc 中曾有介绍,如果不存在用户配置文件,将启用默认配置文件 $VIMRUNTIME/defaults.vim ,如果存在用户配置文件,则不启动,实际情况是这样的吗?我们需要进行一个实验

实验思路

  • 创建用户配置文件 ~/.vimrc

  • 删除/var/lib/vim/addons/plugin/1.vim 以及 plugin 文件夹

  • 在默认配置文件中写入 set number

  • 编辑 1.txt 查看结果

图片

图片

图片

图片

图片

图片

可以看到,存在用户配置文件的情况下,确实默认配置文件不会执行

如果用户配置文件是 ~/.vim/vimrc 也这样吗

图片

图片

用户配置文件 ~/.vim/vimrc 也是生效的

2) 用户配置文件存在且为空

如果用户配置文件存在,但是内容是空的,这种情况下默认配置文件会生效吗

图片

图片

图片

图片

可以看出,默认配置文件判断的是文件存不存在,而不是有没有内容

3) 用户配置文件不存在

如果用户配置文件不存在,默认文件就会执行吗

图片

图片

果然,在用户配置文件不存在的情况下,默认配置会生效

4) .vim  文件夹存在,用户配置文件不存在

图片

图片

看来默认配置文件检查的是具体的文件而不是目录

5)  .vim/plugin/1.vim 存在,用户配置文件不存在

图片

图片

图片

两个配置文件都执行了

3. 用户配置与用户配置

用户主配置文件也有两个文件 ~/.vimrc 和 ~/.vim/vimrc ,用户配置文件其他内容都在 ~/.vim/ 目录下

Ubuntu 22.04 默认情况没有用户配置文件 ~/.vim/* 和 ~/.vimrc

图片

1) 两个用户配置同时存在

如果 ~/.vimrc 或  ~/.vim/vimrc 只存在一个,则会自动执行,当两个文件同时存在会怎么样呢?

实验思路:

  • ~/.vimrc  设置变量 flag 的值为 0

  • ~/.vim/vimrc  设置变量 flag 的值为 1

  • echo 变量 flag

图片

图片

图片

当两个用户配置文件同时存在时,默认会启用  ~/.vimrc

2)  ~/.vimrc 存在, .vim/plugin 目录下配置文件是否执行

图片

图片

.vim/plugin目录下的文件加载不受用户配置文件影响

4. runtimepath 与 $VIMRUNTIME

runtimepath 是一个配置项,而 $VIMRUNTIME 是一个vim自有的环境变量,每次启动 vim 时会将 $VIMRUNTIME 的值更新到 runtimepath 配置项中

1) 在 vim 中临时修改 $VIMRUNTIME 的值,会直接修改 runtimepath 吗

图片

图片

图片

图片

图片

图片

图片

图片

图片

可以得出结论,在运行的 vim 中临时修改 $VIMRUNTIME 环境变量的值并不会影响 runtimepath 项的值

2) 永久修改 $VIMRUNTIME 的值,会修改 runtimepath

图片

图片

图片

图片

图片

看来似乎通过用户配置永久修改 $VIMRUNTIME 不会对 runtimepath 造成影响,尝试通过系统配置文件永久修改 $VIMRUNTIME

图片

图片

可以看到,启动vim会报错,找不到 /tmp/syntax/syntax.vim ,这说明设置生效了,我们回车继续

图片

图片

图片

图片

可以看到, runtimepath 的值并未受到影响,因此似乎 runtimepath 的值并不来自于 $VIMRUNTIME

但是看很多文章中都写的是 runtimepath 的值由多部分组成,其中一部分是  $VIMRUNTIME ,为什么我们修改了会失败呢?

此时我突然想起了修改后启动 vim 的报错,难道是修改后由于 /tmp 目录下缺少相关文件导致的?

实验证明一下

图片

首先是执行 vim 不再报错了

图片

图片

图片

图片

结果还是一样的

图片

有趣的是,在加载配置文件列表中,确实有几个配置文件是从 /tmp/vim_runtime 目录加载的,而 debian.vim 竟然没有从 /tmp/vim_runtime

之前我们讲过, debian.vim 的路径是从 $VIMRUNTIME 获取的,而强制重新加载 debian.vim 的配置文件的指令就在系统配置文件/etc/vim/vimrc之中,如果这种脚前脚后的关系都无济于事的话,那后面的配置文件不使用我们修改过后的地址的配置文件也是可以理解的了

继续实验,在 /etc/vim/vimrc 中设置一下打印的选项,分别打印 $VIMRUNTIME 和 runtimepath 的值

图片

图片

从这个结果可以看出,在加载第一个配置文件/etc/vim/vimrc之前, runtimepath 就已经存在了,因此我们在 /etc/vim/vimrc 中修改 $VIMRUNTIME 的值后也不会重新生成 runtimepath

但是重新加载 debian.vim 是在设置  $VIMRUNTIME  之后,为何 debian.vim 不使用我们修改后的$VIMRUNTIME 的值就很难让人理解了

既然我们修改了  $VIMRUNTIME  之后,有几个配置文件还是跟着改了目录的,因此我们尝试在 /etc/vim/vimrc 中使用 runtime! xxx.vim 来加载它们,看看这回是什么路径

图片

图片

图片

这就说明 runtime! 命令加载的地址根本就不是当前$VIMRUNTIME

既然从加载第一个配置文件前,runtimepath 和 $VIMRUNTIME 就已经设置好了,要么是 vim 还有其他的配置文件,要么是 vim 直接从系统获取的配置

删除掉刚刚配置 $VIMRUNTIME 的内容,采用 Linux 环境变量的方式进行配置

图片

图片

图片

图片

图片

果然,$VIMRUNTIME 是从 Linux 操作系统的环境变量来的

因此永久修改 $VIMRUNTIME 不一定会修改 runtimepath ,只有通过Linux 操作系统环境变量来永久修改 $VIMRUNTIME 时才会修改 runtimepath 的值,通过vim系统配置文件的方式永久修改 $VIMRUNTIME 不会修改 runtimepath 的值

3) runtimepath 是否可以通过环境变量设置

图片

图片

图片

图片

可以看到并没有什么影响,因此 runtimepath 的值并不是来自于 Linux 操作系统环境变量

4) runtimepath 是否可以通过配置文件修改

图片

图片

图片

从结果可以看出,实际上 runtime! xxx.vim 引用的配置文件地址并不是由 $VINRUNTIME 来决定的,而是由 runtimepath 来决定的,这里官方应该是写错了,只不过由于 runtimepath 默认是由 $VIMRUNTIME 组成的,所以错得不是很明显

而 defaults.vim 是实打实的 $VIMRUNTIME

5. 哪些目录自动加载

$VIMRUNTIME 和 ~/.vim 目录下的部分目录中的脚本会在vim启动或运行过程中加载,具体目录如下

  • autoload 目录:包含自动加载的脚本文件

  • colors 目录:包含颜色主题文件

  • compiler 目录:包含编译器配置文件

  • doc 目录:包含文档文件

  • ftplugin 目录:包含文件类型相关的插件脚本

  • indent 目录:包含文件类型相关的缩进脚本

  • keymap 目录:包含键盘映射脚本

  • lang 目录:包含语言相关的文件

  • plugin 目录:包含插件脚本文件

  • syntax 目录:包含语法高亮脚本文件

  • ftdetect 目录:包含文件类型检测脚本

  • after目录:包含 Vim 启动后加载的配置文件

1) autoload

如果大家看过《程序员的自我修养》、看过我写的《学完ELF后人间清醒的总结v1.0》或者了解过ELF文件结构与加载过程,大家肯定会了解一个概念 —— 延迟绑定

其实 autoload 的思想也是一样,对于需要程序启动时加载的插件就启动时加载,刚启动时用不到后期用到的插件就什么时候用,什么时候加载

这些启动 vim 过程中用不到的插件就放在 autoload 目录下,以自动函数的形式存放

自动函数也是一种函数,不过有一个固定的规范,autoload 下的文件名与函数名部分内容必须一致,举个例子

自动函数文件:/usr/share/vim/vim82/autoload/demo.vim

自动函数的定义

function! demo#MyFunction()
    set number
endfunction

这个函数名字由 demo  #  MyFunction  组成,其中 deno 必须与文件名 demo 相同,# 是固定格式,具体函数名自定义就好

自动函数的加载

可以在 vim 的底线命令模式下直接输入 :call demo#MyFunction() 进行加载

图片

图片

图片

图片

当然,也可以通过写入到配置文件的方式加载

图片

图片

2) colors

colors 文件夹是 vim 的配色方案存储的文件夹,除非使用插件管理器(例如 vim-plug) ,不然不会自动加载,可以通过 colorscheme mycolorscheme 来加载 colors/mycolorscheme.vim 这个颜色配置文件,举例如下:

Vim颜色配置文件: /usr/share/vim/vim82/colors/color_demo.vim

图片

在 /etc/vim/vimrc 中添加 colorscheme color_demo

图片

测试效果

图片

成功加载配置文件

3) compiler

compiler 是与编译器相关的配置文件夹,当用户在底线命令模式中使用:compiler xxx 的时候,会自动加载compiler 目录下同名的配置文件

在 compiler 目录下已有的 gcc.vim 中添加 set number

图片

打开 vim 测试效果

图片

图片

成功加载我们加入的配置

如果希望在vim打开某个类型的文件时,就加载相关类型对应的编译器配置文件,可以通过在 /etc/vim/vimrc 进行相关配置

以打开 go 类型文件时,自动切换 go 编译器,之后加载 /usr/share/vim/vim82/compiler/go.vim 为例

先通过 vim 打开 1.go 文件,查看未进行相关设置前效果

图片

在 /usr/share/vim/vim82/compiler/go.vim 中添加 set number

图片

接下来一步很重要

在 /etc/vim/vimrc 中添加 autocmd FileType go compiler go

图片

打开 1.go 进行测试

图片

如果你还不满足,希望在 vim 启动的时候就自动加载 compiler 目录下的某个配置文件,除了直接引用的方式以外,可以利用 VimEnter 事件通过在 /etc/vim/vimrc 中添加 autocmd VimEnter * compiler gcc,实现打开任意类型文件时都加载 gcc 编译器,进而加载 gcc.vim 配置文件

在  /usr/share/vim/vim82/compiler/gcc.vim 中添加 set number

图片

在 /etc/vim/vimrc 中添加 autocmd VimEnter * compiler gcc

图片

打开 1.go 测试效果

图片

打开 1.txt 测试效果

图片

直接启动vim测试效果

图片

成功加载我们的配置文件

4) doc

这个目录下的文件都是帮助文档,并不会自动加载,通常用户在底线命令模式下输入 :help xxx 就会显示出来了

5) ftplugin

ftplugin 目录用于存放与文件类型相关的配置文件。这些文件可以根据文件类型自动加载,并为特定类型的文件提供相关的设置和命令。

这回以 python 类型文件为例

在 /usr/share/vim/vim82/ftplugin/python.vim 中添加 set number

图片

打开 1.txt 进行测试

图片

打开 1.py 进行测试

图片

如果我们想为后缀名为 .pwd 的文件进行相关配置,直接在 ftplugin 目录下放置一个 pwd.vim 就可以吗?

图片

打开 1.pwd 查看效果

图片

看来没有那么简单,需要额外进行配置

需要在 /etc/vim/vimrc 中添加如下配置

autocmd BufNewFile,BufRead *.pwd setfiletype pwd

图片

打开 1.txt 进行测试

图片

打开 1.pwd 进行测试

图片

成功实现在打开自定义类型文件时执行自定义的配置文件

6) indent

indent 目录用于存放与缩进相关的配置文件。这些文件可以根据文件类型自动加载,并为特定类型的文件提供自定义的缩进设置

这回以 rust 文件为例

在 /usr/share/vim/vim82/indent/rust.vim 中添加 set number

图片

打开 1.txt 测试效果

图片

打开 1.rs  测试效果

图片

图片

成功加载相关配置文件

和上面相同,如果想要自定义一个 .pwd 类型文件的缩进配置,如何操作呢?

其实文件类型配置这些东西主要都是记录在一个文件中 /usr/share/vim/vim82/filetype.vim ,但是我们在这里不着急讨论,放在后面部分,我们参考其中的书写方法,在 /etc/vim/vimrc 文件中进行配置

图片

au BufNewFile,BufRead *.rs			setf rust

在 /etc/vim/vimrc 中添加下面的内容

au BufNewFile,BufRead *.pwd			setf pwd

图片

在 indent  文件夹内添加 pwd.vim

图片

打开  1.txt 和 1.go 测试效果

图片

图片

打开 1.pwd 文件测试效果

图片

成功加载自定义的配置文件

7) keymap

keymap 目录用于存放与键位映射相关的配置文件。这些文件可以根据文件类型自动加载,并为特定类型的文件提供自定义的键位映射

vim 默认的键位映射文件并不多,常见的 Python、Go 等都没有,正好我们为 .pwd 新建一个键位映射文件

图片

图片

看来还是需要在 /etc/vim/vimrc 中添加对 .pwd 后缀文件的解析结果配置

au BufNewFile,BufRead *.pwd			setf pwd

图片

打开 1.txt 测试效果

图片

打开 1.pwd 测试效果

图片

成功加载自定义的配置文件

8) lang

lang 目录用于存放与语言相关的配置文件。这些文件默认不会自动加载,一般在使用vim 部分多语言支持的插件时才会加载,当然,我们可以使用上面的 vim 事件来让其加载,这种加载方式适合于任何目录的配置文件

在 lang 目录中新建 zh_CN_18030.vim 文件

图片

在 /etc/vim/vimrc 中。写入如下内容

autocmd VimEnter * source $VIMRUNTIME/lang/zh_CN_18030.vim

图片

现在打开任意文件,测试效果

图片

成功加载自定义的配置文件

这种加载方式适用于任何目录的文件,因此并非lang目录独有,经过测试, source 加载的语法文件后缀并不一定需要是 .vim ,其他后缀也是可以的

9) plugin

plugin 目录用于存放插件文件,这些插件文件可以添加新的功能、命令、映射键位等

这个目录太清爽了,不用配置,直接将配置文件放在里面就会在vim启动时自动加载,加载顺利是按照字母顺序来进行的

图片

这个目录默认存在的文件不多,我们新建一个,在新建之前,我们先看一下打开 1.txt 的效果

图片

在 plugin 文件夹新建 toxml.vim

图片

打开 1.txt 测试效果

图片

成功加载自定义配置文件

10) syntax

syntax 目录中的语法文件用于提供代码高亮和语法解析的功能。这些语法文件通常会在打开相应类型的文件时自动加载。

默认打开 1.pwd

图片

图片

vim打开未匹配到文件类型的文件时,会自动加载 /usr/share/vim/vim82/syntax/nosyntax.vim

在 /usr/share/vim/vim82/syntax/nosyntax.vim  中添加 set number

图片

再次打开 1.pwd

图片

删除 /usr/share/vim/vim82/syntax/nosyntax.vim  中的 set number

接下来我们通过新增文件类型来实现自动加载

在 /etc/vim/vimrc 中新增以下内容

au BufNewFile,BufRead *.pwd			setf pwd

图片

打开 1.pwd

图片

图片

成功加载自定义配置

11) ftdetect

ftdetect 目录用于自动检测文件类型,这个目录和plugin目录一样,目录下的配置文件可以自动加载

Ubuntu 22.04 中默认已经没有这个目录了,但是新建这个目录并在其中放置配置文件仍然有效

图片

打开 1.txt

图片

新建 ftdetect 目录并在其中创建 ttt.vim

图片

图片

图片

成功加载自定义配置文件

12) macros

macros 目录用于存放宏文件,它们包含一系列 Vim 命令和操作的序列,macros 目录没有自动加载的特殊机制

13) pack

pack 目录用于管理插件和脚本包。当你将插件或脚本包放置在 pack 目录中时,Vim 会自动加载这些包

关于 pack 目录,网络上文件较少,先存的部分文章绝大多数也都是错误的,通过 :help packages 获取到了正确的使用方法

图片

package 和 plugin 略有不同,package 可以包含多个插件,因此 pack 目录也有自己固定的格式

  1. 在 pack 目录创建包文件夹 —— mypackage

  2. 在 mypackage 中创建固定名称的文件夹 start

  3. 在 start 文件夹中创建任意名称文件夹,以 pack1 为例

  4. 在 pack1 文件夹中创建固定名称文件夹 plugin 或 syntax 等

  5. 在 plugin 或 syntax 中创建任意名称的 vim 配置文件  pack_test.vim

  6. 在 pack_test.vim 中写入 set number

未设置前打开 1.txt

图片

创建 package 并写入内容

图片

打开 1.txt

图片

图片

成功加载了自定义配置文件

14) print

print 目录是 Vim 默认的打印支持脚本所在的位置,并不是用于自动加载脚本的目录

15) spell

spell 目录下的拼写检查文件可以通过自动加载来启用拼写检查功能,暂未发现可以自动启动的方法

16) tutor

tutor 目录下的教程文件是通过自动加载来启用 Vim 自带的教程功能的,暂未发现可以自动启动的方法

17) after

after 目录是 Vim 中一个特殊的目录,用于存放在 Vim 启动后加载的配置文件。after 目录中的配置文件可以用于覆盖默认的 Vim 配置,以及在 Vim 启动后进行进一步的个性化设置

Ubuntu 22.04 默认情况下没有 after 文件夹,我们可以新建该文件夹

图片

after 目录既然是用来覆盖默认的 vim 配置,就有和默认配置文件夹相同的目录结构,也就是说 after 目录下的 plugin 目录中的配置文件也会自动执行

图片

打开 1.txt

图片

发现并没有执行

删除 after 目录,在用户配置文件中创建 after 目录,按照上面的方式进行测试

图片

再次打开 1.txt

图片

也就是说 在Ubuntu 22.04上after目录只在用户配置中有效,在系统级配置中无效

18) 自动加载的目录小结
目录名 自动加载 修改配置文件的方式加载 打开特定格式文件自动加载 未发现自动加载
autoload 1
colors 1
compiler 1
doc 1
ftplugin 1
indent 1
keymap 1
lang 1
plugin 1
syntax 1
ftdetect 1
macros 1
pack 1
print 1
spell 1
tutor 1
after 1

图片

6. 哪些文件自动加载

$VIMRUNTIME 和 ~/.vim 目录下的部分脚本会在vim启动或运行过程中加载

经过上个小节的洗礼,大家应该已经轻车熟路了,想要确定具体加载了哪些脚本,只需要分别打开有文件类型的文件、未知文件类型的文件、直接执行 vim,之后分别在底线命令模式下执行 :scriptnames 就可以看到默认加载的脚本了

使用 vim 打开 1.go 文件脚本的加载情况

图片

使用 vim 打开 a 文件的脚本加载情况

图片

直接执行 vim

图片

通过对比,可以得出,自动加载的脚本如下(第8条和第12条根据打开文件类型而定)

  • vimrc

  • debian.vim

    在 vimrc 中默认引用

  • syntax/syntax.vim

  • syntax/synload.vim

  • syntax/syncolor.vim

  • colors/lists/default.vim

  • filetype.vim

  • scripts.vim

  • `defaults.vim

  • ftplugin.vim

  • indent.vim

  • syntax/nosyntax.vim

    在目标文件未识别到文件类型或文件类型不需要语法高亮时自动加载

  • plugin/*

自动加载的文件小结
文件名 文件作用 是否自动加载
vimrc Vim 的全局配置文件,用于设置全局的  Vim 选项和自定义命令。它在 Vim 启动时自动加载,并为所有用户生效
debian.vim 为 Debian 系统定制的 Vim  配置文件,包含了一些特定于 Debian 的配置选项和设置 Debian等系统自动加载
syntax/syntax.vim Vim  用于语法高亮显示的核心文件,定义了语法高亮的规则和逻辑
syntax/synload.vim Vim  用于语法高亮显示的辅助文件,用于加载和管理语法文件
syntax/syncolor.vim Vim  用于语法高亮显示的辅助文件,用于加载和管理语法文件
colors/lists/default.vim Vim  颜色方案的默认配置文件,定义了默认的颜色方案
filetype.vim 这个文件定义了文件类型的检测规则和相关设置,用于根据文件类型自动加载相应的配置和插件
scripts.vim 这个文件包含一些 Vim  脚本的帮助函数和设置,用于支持 Vim 脚本的运行和调试 打开部分文件自动加载
defaults.vim 默认的 Vim 配置选项,用于设置 Vim  的默认行为和外观
ftplugin.vim 这个文件包含了一些文件类型相关的插件设置,用于为特定文件类型自动加载相应的插件和配置 打开部分文件自动加载
indent.vim 这个文件包含了一些自动缩进的设置,用于根据文件类型自动设置正确的缩进规则
syntax/nosyntax.vim Vim  用于禁用语法高亮显示的设置文件,用于取消对当前文件的语法高亮显示 未匹配到文件格式     或不需要语法高亮时自动加载
plugin/* 各种插件

图片

7. 自动加载好奇的知识点

runtime 和runtime!加载规则一致,对于之前已经被加载过的配置文件效果有些差异,因此在以下文章中讨论加载规则时不必纠结 runtime 还是runtime!,涉及到差异时,我会详细标注

1) $VIMRUNTIME 和 ~/.vim 效果是否一致

除了加载顺序以及after 目录差异外,未发现其他区别

2) runtime! 加载目录取决于什么

默认情况 /etc/vim/vimrc 中存在通过 runtime! debian.vim 的配置,在前面的部分中,我标注了 debian.vim 文件来自 $VIMRUNTIME 环境变量中,从结果看是没有错的

不过如果从原理来说,runtime! 加载配置文件的地址选择是来自于 runtimepath 项的,只不过前面也讲过 $VIMRUNTIME 的值是 runtimepath 的一部分

3) runtime! 存在多文件时如何选择

按照常规思路去想,一般来说是按照 runtimepath 的顺序,选择第一个找到相关文件的地址去重新加载,但是 vim 的思路似乎是 "小孩子才做选择,我全都要"

没错,runtime! xxx.vim  会将 runtimepath 指定的目录中所有找到的 xxx.vim 重新加载一遍

在 /etc/vim/vimrc 为例,添加 runtime! demo.vim

图片

获取 runtimepath 的值

图片

图片

runtimepath=~/.vim,/var/lib/vim/addons,/etc/vim,/usr/share/vim/vimfiles,/usr/share/vim/vim82,/usr/share/vim/vimfiles/after,/etc/vim/after,/var/lib/vim/addons/after,~/.vim/after

按照先后顺序整理如下

  • ~/.vim

  • /var/lib/vim/addons

  • /etc/vim

  • /usr/share/vim/vimfiles

  • /usr/share/vim/vim82

  • /usr/share/vim/vimfiles/after

  • /etc/vim/after

  • /var/lib/vim/addons/after

  • ~/.vim/after

现在分别在 ~/.vim 、/var/lib/vim/addons/etc/vim/after  中放置 demo.vim ,内容均为打印当前文件所在位置

图片

此时打开 vim

图片

图片

可以看到,我只在 /etc/vim/vimrc 中设置了一次 runtime! demo.vimruntimepath制定的目录下所有的demo.vim 都重新加载了一遍,具体顺序是按照 runtimepath 中的顺序来的

4)  runtime! 低权限可以引用高权限文件吗

我们直接将 3) 中  /etc/vim/vimrc 中的 runtime! demo.vim 移到 ~/.vimrc 或 ~/.vim/vimrc 中

图片

图片

可以看到,低权限配置 runtimepath 是可以加载高权限文件夹下的配置文件的

图片

图片

此时,如果用 sudo 来执行 vim ,就不会加载 demo.vim 了,毕竟sudo后执行vim的变成了 root,默认情况下 root 的 ~/.vimrc 和 ~/.vim/vimrc ,即使存在也不存在 runtime! demo.vim 指令

5) runtime! 可以加载非 *.vim 的文件吗

之前我们演示的都是加载 *.vim 文件,现在尝试加载非 .vim 后缀的文件

首先获取 runtimepath

runtimepath=~/.vim,/var/lib/vim/addons,/etc/vim,/usr/share/vim/vimfiles,/usr/share/vim/vim82,/usr/share/vim/vimfiles/after,/etc/vim/a
fter,/var/lib/vim/addons/after,~/.vim/after

在 /usr/share/vim/vim82 目录下新建 demo.vim ,内容为 set number

![](../../../../Library/Application Support/typora-user-images/.png)

图片

在 /etc/vim/vimrc 中使用 runtime! demo.vim 进行加载

图片

打开 1.txt

图片

配置生效,现在将 demo.vim 修改为 demo ,并将 /etc/vim/vimrc 中的内容一并修改

图片

总结

本篇文章只是利用了 vim 部分功能来制作后门,案例也处于是概念性的,以系统命令执行为主。当然,如果你已经通篇读了本篇文章,相信你一定了解细节支持,有了很多思路,有时间可以在本地实现一下。

本篇文章较长,公众号阅读可能不是很方便,因此我们给大家准备了 PDF 版本

公众号:吉吉说安全,对我发消息【后门】获取PDF版本」

 「如果你也想学习更多这类安全技术,【详情下方图片了解,【扫下方二维码加入:只做高质量优质精品内容」

图片

「会持续给大家更新更好东西,期待得到你免费的」

图片

免责声明

由于传播、利用本公众号所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,本公众号及作者不为此承担任何责任,一旦造成后果请自行承担!如有侵权烦请告知,我们会立即删除并致歉。谢谢!

相关推荐

  1. Linux系列」聊聊vi/vim的3种命令模式

    2024-04-03 16:04:04       21 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-04-03 16:04:04       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-03 16:04:04       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-03 16:04:04       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-03 16:04:04       18 阅读

热门阅读

  1. linux之自主shell编写

    2024-04-03 16:04:04       12 阅读
  2. CODEFORCES --- 1399A.Remove Smallest

    2024-04-03 16:04:04       14 阅读
  3. 5G时代来了,一键登录的颠覆式体验时代也来了

    2024-04-03 16:04:04       14 阅读
  4. ES 7.12官网阅读-ILM(index lifecycle management)

    2024-04-03 16:04:04       13 阅读
  5. LEETCODE-DAY41

    2024-04-03 16:04:04       13 阅读
  6. c++ 实现线程池、实现异步接口

    2024-04-03 16:04:04       13 阅读
  7. LeetCode 746. 使用最小花费爬楼梯

    2024-04-03 16:04:04       13 阅读
  8. 模拟退火算法

    2024-04-03 16:04:04       11 阅读
  9. 每日OJ题_回文串dp①_力扣647. 回文子串

    2024-04-03 16:04:04       10 阅读
  10. 【WPF应用24】C#中的Image控件详解与应用示例

    2024-04-03 16:04:04       14 阅读
  11. rust实现希尔排序算法

    2024-04-03 16:04:04       14 阅读