oss-sec mailing list archives

Re: More arbitrary code executions in Netrw version 125, Vim 7.2a.10


From: Jonathan Smith <smithj () freethemallocs com>
Date: Mon, 07 Jul 2008 00:28:30 -0800

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Jan Minář wrote:
Following my recent advisory on Vim vulnerabilities, here goes a followup: many
more vulnerabile statements in Netrw.  Although Netrw has been updated with
the new fnameescape() and shellescape() functions, it doesn't use them
consistently.  It is difficult *not* to find vulnerable code in Netrw.

This writeup can be found at:
      ``http://www.rdancer.org/vulnerablevim-netrw.html'&apos;
The archive with code that we're using can be found at:
      ``http://www.rdancer.org/vulnerablevim-netrw.tar.bz2'&apos;.

Best results are achieved by running ``make test'' in the root
directory of the abovementioned archive:

      $ make test
      [...]
        -------------------------------------------
        -------- Test results below ---------------
        -------------------------------------------
        filetype.vim
        tarplugin.updated: VULNERABLE
        zipplugin : VULNERABLE
    --> netrw.v2  : VULNERABLE
    --> netrw.v3  : VULNERABLE
    --> netrw.v4  : VULNERABLE


1. Compression and Decompression (The ``mz'' Command)

Invoking the ``mz'' command upon a file with a crafted file name can lead to
arbitrary code execution.


1.1 Vulnerability

In many places, Netrw ($VIMRUNTIME/autoload/netrw.vim) fails to sanitize file
names used as shell arguments.

In function s:NetrwMarkFileExe() (The ``mx'' command): ``apply command to marked
files.  Substitute: filename -> % If no %, then append a space and the filename
to the command'':

        4036    for fname in s:netrwmarkfilelist_{curbufnr}
        4037     if a:islocal
        4038      if g:netrw_keepdir
        4039       let fname= s:ComposePath(curdir,fname)
        4040      endif
        4041     else
        4042      let fname= b:netrw_curdir.fname
        4043     endif
        4044     if cmd =~ '%'
        4045      let xcmd= substitute(cmd,'%',fname,'g')
        4046     else
        4047      let xcmd= cmd.' '.fname
        4048     endif
        4049     if a:islocal
        4050 "     call Decho("local: xcmd<".xcmd.">")
    --> 4051      let ret= system(xcmd)
        4052     else
        4053 "     call Decho("remote: xcmd<".xcmd.">")
    --> 4054      let ret= s:RemoteSystem(xcmd)

Following code in function s:NetrwMarkFileCompress() is run when the ``mz''
(compress/decompress) command is invoked.  The variable
``s:netrwmarkfilelist_{curbufnr}'' holds the marked files list.:

       159 if !exists("g:netrw_decompress")
       160  let g:netrw_decompress= { ".gz" : "gunzip" , ".bz2" : "bunzip2"
, ".zip" : "unzip" , ".tar" : "tar -xf"}
       161 endif
      [...]
        3816    for fname in s:netrwmarkfilelist_{curbufnr}
        3817     " for every filename in the marked list
        3818     for sfx in sort(keys(g:netrw_decompress))
        3819      if fname =~ '\'.sfx.'$'
        3820       " fname has a suffix indicating that its
compressed; apply associated decompression routine
        3821       let exe= g:netrw_decompress[sfx]
        3822 "      call Decho("fname<".fname."> is compressed so
decompress with <".exe.">")
        3823       if a:islocal
        3824        if g:netrw_keepdir
        3825         let fname= s:ComposePath(curdir,fname)
        3826        endif
        3827       else
        3828        let fname= b:netrw_curdir.fname
        3829       endif
        3830       if executable(exe)
        3831        if a:islocal
    --> 3832         call system(exe." ".fname)


1.2. Exploit

We exploit the statement on line 3832.

Run ``make demo'' or ``make test'' in the netrw.v2 directory.  Note: ``make
test'' may hang when run from within vim.


2. Copying Files (The ``mc'' Command)

Invoking the ``mc'' command inside a directory with a crafted directory name
can lead to arbitrary code execution.


2.1. Vulnerability

Netrw inappropriately uses shellescape() in many places to sanitize
arguments of the
``execute'' command.

        708   exe s:netrw_silentxfer."!".g:netrw_rcp_cmd."
".s:netrw_rcpmode."
".shellescape(uid_machine.":".escape(b:netrw_fname,' ?&;')."
".tmpfile)
        810    exe s:netrw_silentxfer."!".g:netrw_scp_cmd.useport."
".shellescape(g:netrw_machine.":".escape(b:netrw_fname,g:netrw_fname_escape))."
".tmpfile
        831     exe s:netrw_silentxfer."!".g:netrw_http_cmd."
".shellescape(tmpfile)."
".shellescape("http://".g:netrw_machine.netrw_fname)
        842     exe s:netrw_silentxfer."!".g:netrw_http_cmd."
".shellescape(tmpfile)."
".shellescape("http://".g:netrw_machine.netrw_html)
        882    exe s:netrw_silentxfer."!".g:netrw_rsync_cmd."
".shellescape(g:netrw_machine.":".netrw_fname)." ".tmpfile
        907     exe s:netrw_silentxfer."!".g:netrw_fetch_cmd."
".tmpfile." ".shellescape(netrw_option."://".g:netrw_uid.':'.s:netrw_passwd.'@'.g:netrw_machine."/".netrw_fname)
        910     exe s:netrw_silentxfer."!".g:netrw_fetch_cmd."
".tmpfile." ".shellescape(netrw_option."://".g:netrw_machine."/".netrw_fname)
        923    exe s:netrw_silentxfer."!".g:netrw_sftp_cmd."
".shellescape(g:netrw_machine.":".netrw_fname)." ".tmpfile
        1084    exe s:netrw_silentxfer."!".g:netrw_rcp_cmd."
".s:netrw_rcpmode." ".shellescape(tmpfile)."
".shellescape(uid_machine.":".netrw_fname)
        1177    exe s:netrw_silentxfer."!".g:netrw_scp_cmd.useport."
".shellescape(tmpfile)."
".shellescape(g:netrw_machine.":".netrw_fname)
        2976   exe "silent !".viewer." ".viewopt.shellescape(fname).redir
        2981   exe 'silent !start rundll32 url.dll,FileProtocolHandler
'.shellescape(fname)
        2987   exe "silent !gnome-open ".shellescape(fname).redir
        2992   exe "silent !kfmclient exec ".shellescape(fname)." ".redir
        2997   exe "silent !open ".shellescape(fname)." ".redir
        3656    exe "silent! !".g:netrw_local_mkdir.' '.shellescape(newdirname)
        3680   exe "silent! !".mkdircmd." ".shellescape(newdirname)
        3911    exe "silent! !".g:netrw_local_mkdir.' '.shellescape(tmpdir)
        4775    exe s:netrw_silentxfer."!".g:netrw_scp_cmd.useport."
".filelist." ".shellescape(tgtdir)
        5058    exe s:netrw_silentxfer."!".g:netrw_scp_cmd.useport."
".args." ".shellescape(machine.":".escape(tgt,g:netrw_fname_escape))
        6001    exe "silent r! ".listcmd.shellescape(s:path)
        6015     exe "silent r! ".listcmd.' "'.shellescape(s:path).'"'


        3888    let args=
join(map(copy(s:netrwmarkfilelist_{bufnr('%')}),"b:netrw_curdir.\"/\".shellescape(v:val)"))
        3889 "   call Decho("system(".g:netrw_localcopycmd." ".args."
".shellescape(s:netrwmftgt).")")
    --> 3890    call system(g:netrw_localcopycmd." ".args."
".shellescape(s:netrwmftgt))

2.2. Exploit

Run ``make demo'' or ``make test'' in the netrw.v3 directory.  Note: ``make
test'' may hang when run from within vim.


2.3. Patch

--- /usr/local/share/vim/vim72a/autoload/netrw.vim      2008-07-01
18:38:09.000000000 +0100
+++ -   2008-07-03 19:01:50.676582822 +0100
@@ -3885,7 +3885,7 @@
   if      a:islocal &&  s:netrwmftgt_islocal
       " Copy marked files, local directory to local directory
        "   call Decho("copy from local to local")
        -   let args=
join(map(copy(s:netrwmarkfilelist_{bufnr('%')}),"b:netrw_curdir.\"/\".shellescape(v:val)"))
        +   let args=
join(map(copy(s:netrwmarkfilelist_{bufnr('%')}),"shellescape(b:netrw_curdir).\"/\".shellescape(v:val)"))
         "   call Decho("system(".g:netrw_localcopycmd." ".args."
".shellescape(s:netrwmftgt).")")
             call system(g:netrw_localcopycmd." ".args."
".shellescape(s:netrwmftgt))



3. Deleting Files (The ``D'' Command)

Applying the ``D'' to a file with a crafted file name, or inside a directory
with a crafted directory name, can lead to arbitrary code execution.


3.1 Vulnerability

Netrw fails to properly sanitize arguments passed to the s:System() function,
which is a wrapper for the ``execute'' command:

        7596    fun! s:System(cmd,path)
        [...]
        7599      let path = a:path
        [...]
        7615        exe "let result= ".a:cmd."('".path."')"

In  function s:NetrwLocalRmFile():

        6724  fun! s:NetrwLocalRmFile(path,fname,all)
        [...]
        6730    let rmfile= s:ComposePath(a:path,a:fname)
        [...]
    --> 6754      let ret= s:System("delete",rmfile)
        [...]
    --> 6777      call s:System("system",g:netrw_local_rmdir.'
'.shellescape(rmfile))
        [...]
    --> 6782       let errcode= s:System("delete",rmfile)
        [...]
    --> 6788         call s:System("system","rm ".shellescape(rmfile))

In function s:NetrwLocalRmFile():
        6730   let rmfile= s:ComposePath(a:path,a:fname)
        [...]
    --> 6754     let ret= s:System("delete",rmfile)
        [...]
    --> 6777     call s:System("system",g:netrw_local_rmdir.'
'.shellescape(rmfile))
        6778 "    call Decho("v:shell_error=".v:shell_error)
        6779
        6780     if v:shell_error != 0
        6781 "     call Decho("2nd attempt to remove directory<".rmfile.">")
    --> 6782      let errcode= s:System("delete",rmfile)
        6783 "     call Decho("errcode=".errcode)
        6784
        6785      if errcode != 0
        6786       if has("unix")
        6787 "       call Decho("3rd attempt to remove directory<".rmfile.">")
    --> 6788        call s:System("system","rm ".shellescape(rmfile))


3.2 Exploit

We exploit the statement on the line 6754.  Run ``make demo'' or ``make test''
in the netrw.v4 directory.  Note: ``make test'' may hang when run from within
vim.  We use the TIOCSTY ioctl to simulate keyboard input in ``make test'' --
avoid touching the keyboard while ``make test'' is running.

--~--~---------~--~----~------------~-------~--~----~
You received this message from the "vim_dev" maillist.
For more information, visit http://www.vim.org/maillist.php
-~----------~----~----~----~------~----~------~--~---


Steve, could we get CVEs assigned, please? I'd imagine we'd need three;
one for the tarplugin issue, one for the zipplugin, and one for the
netrw issues (which are similar enough to probably justify lumping them
together).

Bram, have you had a chance to look at this yet? The advisory included a
patch for one of the issues, but not others.

Thanks in advance to you both.

Also potentially of interest: on rPath Linux 2 and Foresight Linux 2, I
get the following with vim 7.1 (it could be due either to version skew
between me and the reporter or due to how we build vim):

tarplugin.updated: VULNERABLE
zipplugin : VULNERABLE
netrw.v2  : EXPLOIT FAILED
netrw.v3  : EXPLOIT FAILED
netrw.v4  : EXPLOIT FAILED

On rPath Linux 1, with vim 6.3, I get the following:

tarplugin.updated: EXPLOIT FAILED
zipplugin : EXPLOIT FAILED
netrw.v2  : EXPLOIT FAILED
netrw.v3  : EXPLOIT FAILED
netrw.v4  : EXPLOIT FAILED

        smithj

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.9 (GNU/Linux)

iEYEAREIAAYFAkhx054ACgkQCG91qXPaRektJwCgpWWPsqaiH1fkgqAlqsKm+VIF
JSQAoILE62WZnh2raUk0yHWwx2lVhk57
=jzec
-----END PGP SIGNATURE-----


Current thread: