Openwall GNU/*/Linux - a small security-enhanced Linux distro for servers
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Date: Mon, 07 Jul 2008 21:05:37 +0200
From: Bram Moolenaar <Bram@...lenaar.net>
To: Jonathan Smith <smithj@...ethemallocs.com>
CC: "Charles E Campbell, Jr" <drchip@...pbellfamily.biz>,
        oss-security@...ts.openwall.com
Subject: Re: More arbitrary code executions in Netrw version 125, Vim 7.2a.10


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@...lenaar.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    ///

Powered by blists - more mailing lists

Your e-mail address:

Please check out the Open Source Software Security Wiki, which is counterpart to this mailing list.

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.