[prev in list] [next in list] [prev in thread] [next in thread] 

List:       oss-security
Subject:    [oss-security] Re: More arbitrary code executions in Netrw version 125, Vim 7.2a.10
From:       Bram Moolenaar <Bram () moolenaar ! net>
Date:       2008-07-07 19:05:37
Message-ID: 200807071905.m67J5blB065410 () moolenaar ! net
[Download RAW message or body]


Jonathan -

> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA256
> 
> Forgive the double-post; my first message was blocked by the vim_dev
> mailing list due to not being subscribed (which is very odd, given that
> I am subscribed). This one is being sent directly to Bram instead.
> 
> 	smithj
> 
> 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''
> > The archive with code that we're using can be found at:
> > 	``http://www.rdancer.org/vulnerablevim-netrw.tar.bz2''.
> > 
> > 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.
> 
> 
> 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.

The problem in the zip plugin has already been fixed, but the file
wasn't distributed yet.  It's now on
ftp://ftp.vim.org/pub/vim/runtime/autoload/zip.vim

Charles is working on further problems with the netrw plugin.  I'm
waiting for this to make the Vim 7.2b BETA release.

- Bram

-- 
        Very funny, Scotty.  Now beam down my clothes.

 /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net   \\\
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\        download, build and distribute -- http://www.A-A-P.org        ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic