2nd Oct 2002 [SBWID-5721]
COMMAND
GV Execution of Arbitrary Shell Commands
SYSTEMS AFFECTED
gv-3.5.8 and probably older versions
PROBLEM
In Marc Bevand [bevand_m (at) epita.fr] advisory :
http://www.epita.fr/~bevand_m/asa/asa-0000
--oOo-- 1. Introduction
GV [0] is a PostScript and PDF previewer available on many unix systems
and even on some non-unix systems. Technically, it is a user interface
for Ghostscript [1], which is a PostScript and PDF language
interpreter. GV is also able to automatically decompress GZip'ed [2]
files on-the-fly before reading them.
When GV detects that the document is either a PDF file or a GZip
compressed file, it executes some commands with the help of the
system() function. Unfortunately, these commands contain the filename,
which can be considered as untrusted user input. It is then possible to
distribute a file (with a meticulously choosed filename, that can even
seems innocent) that causes execution of arbitrary shell commands when
it is read with GV.
--oOo-- 2. Problem
GV detects PDF files or GZip compressed files by reading the first
bytes of datas:
o when "%PDF-" is read, GV assumes it is a PDF file and call system()
with the following argument (default value of the GV.gsCmdScanPDF X11
ressource):
"gs -dNODISPLAY -dQUIET -sPDFname=%s -sDSCname=%s pdf2dsc.ps -c quit"
The 1st "%s" corresponds to the PDF filename, and the 2nd to a
temporary filename.
o when "\037\235" or "\037\213" is read, GV assumes it is a GZip
compressed file and call system() with the following argument (default
value of the GV.uncompressCommand X11 ressource):
"gzip -d -c %s > %s"
The 1st "%s" corresponds to the GZip compressed filename, and the 2nd
to a temporary filename.
In these conditions, trying to open, for example, a PDF file named
"xxx & echo hello & xxx"
leads to execution of
"gs -dNODISPLAY -dQUIET -sPDFname=xxx & echo hello & xxx ...".
Thus,
"echo hello"
(a part of the filename) is executed:
$ file "xxx & echo hello & xxx"
xxx & echo hello & xxx: PDF document, version 1.2
$ gv "xxx & echo hello & xxx"
--> hello
sh: xxx: command not found
GS>hello
sh: xxx..tmp: command not found
The error messages ("sh: xxx: command not found", etc) are just results
of the garbage introduced in the system() argument by the unusual "xxx
& echo hello & xxx" filename. Moreover, GV displays a dialog
box explaining that execution of Ghostscript failed.
But all these "inconvenients" (from the malicious user point-of-view)
can be easily avoided. Imagine a site where each host access a file
server through the mount point "/sgoinfre", and suppose that someone
(Charly) creates 2 files in this directory:
o a PDF file named 'Huhu_"`source evil`".pdf'
(doublequotes and
backquotes are part of the filename)
o a shell script named 'evil' that contains:
#!/bin/sh
echo '"`source evil`"'
touch _it_works_
Now, here is what happens if someone else (Alice) wants to read the PDF
file:
$ cd /sgoinfre
$ gv 'Huhu_"`source evil`".pdf'
All works fine for Alice (no error messages, no dialog box), except
that she hasn't realized that 'evil' has been executed under her
identity:
$ ls -l _it_works_
-rw------- 1 alice users 0 Jul 30 05:56 _it_works_
Note: this example works only if the /bin/sh shell executed by system()
supports the 'source' builtin; that's the case when /bin/sh is a link
to bash.
SOLUTION
--oOo-- 3. Solution
The GV maintainer, Johannes Plass <plass (at)
thep.physik.uni-mainz.de>, has been e-mailed twice about this problem.
Unfortunately, no response has been received, it seems that he has
stopped his work on GV since 1997.
However, I propose a temporary fix: the attached patch
("asa-0000.gv-3.5.8.patch"), done against GV 3.5.8, checks if the
filename contains only allowed characters (alphanumeric and
``+,-./:=@\^_''). If this is not the case, an error message is
displayed and system() is not called.
--oOo-- 4. Conclusion
GV contains a security hole allowing execution of arbitrary shell
commands. Since the author seems to have stopped his work on GV, a
temporary fix has been developped: see the attached patch done against
GV 3.5.8.
--oOo-- 5. References
[0] GV
http://wwwthep.physik.uni-mainz.de/~plass/gv/
[1] Ghostscript
http://www.cs.wisc.edu/~ghost/index.html
[2] GNU Zip
http://www.gzip.org
--oOo-- 6. Attached files
The following file is also available at:
http://www.epita.fr/~bevand_m/asa/asa-0000.gv-3.5.8.patch
---8<------------------ asa-0000.gv-3.5.8.patch-------------------------
diff -ur gv-3.5.8.orig/source/file.c gv-3.5.8/source/file.c
--- gv-3.5.8.orig/source/file.c 1997-06-07
00:00:00.000000000 +0200
+++ gv-3.5.8/source/file.c 2002-09-26
23:56:00.000000000 +0200
@@ -285,6 +285,22 @@
}
/*############################################################*/
+/* file_nameIsDangerous */
+/*############################################################*/
+
+char *file_charsAllowedInName = "+,-./:=@\\^_";
+
+int
+file_nameIsDangerous(fn)
+ char *fn;
+{
+ for (; *fn; fn++)
+ if (!isalnum(*fn) &&
!strchr(file_charsAllowedInName, *fn))
+ return(1);
+ return(0);
+}
+
+/*############################################################*/
/* file_pdfname2psname */
/* If the file ends in .pdf, change this to .ps.*/
/* Return pointer to temp copy if changed, else to
input string. */
diff -ur gv-3.5.8.orig/source/file.h gv-3.5.8/source/file.h
--- gv-3.5.8.orig/source/file.h 1997-04-26
00:00:00.000000000 +0200
+++ gv-3.5.8/source/file.h 2002-09-26
23:28:38.000000000 +0200
@@ -70,6 +70,14 @@
#endif
);
+extern char *file_charsAllowedInName;
+
+extern int file_nameIsDangerous (
+#if NeedFunctionPrototypes
+ char *
+#endif
+);
+
extern char* file_pdfname2psname (
#if NeedFunctionPrototypes
char * /* name */
diff -ur gv-3.5.8.orig/source/ps.c gv-3.5.8/source/ps.c
--- gv-3.5.8.orig/source/ps.c 1997-06-07
00:00:00.000000000 +0200
+++ gv-3.5.8/source/ps.c 2002-09-27
00:29:35.000000000 +0200
@@ -420,6 +420,16 @@
char cmd[512];
char s[512];
filename_unc=file_getTmpFilename(NULL,filename_raw);
+ if (file_nameIsDangerous(filename))
+ {
+ INFMESSAGE(the filename is dangerous)
+ sprintf(s, "The filename \"%s\" is dangerous:
only alphanumeric "
+ "characters and \"%s\" are allowed.\n",
+ filename, file_charsAllowedInName);
+ NotePopupShowMessage(s);
+ ENDMESSAGE(psscan)
+ return(NULL);
+ }
sprintf(cmd,cmd_uncompress,filename,filename_unc);
INFMESSAGE(is compressed)
INFSMESSAGE(uncompress command,cmd)
@@ -491,6 +501,16 @@
char cmd[512];
char s[512];
filename_dsc=file_getTmpFilename(NULL,filename_raw);
+ if (file_nameIsDangerous(filename))
+ {
+ INFMESSAGE(the filename is dangerous)
+ sprintf(s, "The filename \"%s\" is dangerous:
only alphanumeric "
+ "characters and \"%s\" are allowed.\n",
+ filename, file_charsAllowedInName);
+ NotePopupShowMessage(s);
+ ENDMESSAGE(psscan)
+ return(NULL);
+ }
sprintf(cmd,cmd_scan_pdf,filename,filename_dsc);
INFMESSAGE(is PDF)
INFSMESSAGE(scan command,cmd)
---8<------------------ asa-0000.gv-3.5.8.patch
TUCoPS is optimized to look best in Firefox® on a widescreen monitor (1440x900 or better).
Site design & layout copyright © 1986-2025 AOH