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