Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <4871D3AE.4070004@freethemallocs.com>
Date: Mon, 07 Jul 2008 00:28:30 -0800
From: Jonathan Smith <smithj@...ethemallocs.com>
To: vim_dev@...glegroups.com, 
 "Steven M. Christey" <coley@...us.mitre.org>
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

-----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''
> 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.
> 
> --~--~---------~--~----~------------~-------~--~----~
> 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-----

Powered by blists - more mailing lists

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.