Summary:   Printing a file can cause a system compromise

Date: 12 Nov. 2001
Updated: Sat Feb  2 08:27:14 PST 2002

Reason:    Some Versions of GhostScript can open and read files on system
(-dSAFER may not disable file open, and -dPARANOIDSAFER may not be implemented)

*******************
UPDATE:

This problem has been fixed on some later versions of GhostScript
and other PostScript converters.  The fix described in here may
need to be modified for the specific version of GhostScript you are
using.  See the notes below.  The -dPARANOIDSAFER flag should solve
this problem.

Do NOT repeat NOT make the suggested changes if the problem
described below does not exist.

*******************
 

Systems Impacted:  just about everything that uses GhostScript (or
some other PostScript interpreters) for PostScript document
conversion. This includes the various MagicFilters, Transcript,
LPRng's ifhp, RedHats rh-printfilter.  These are running on Linux,
BSD, System V, possibly Sun Microsystems, HP, etc., etc., etc.
Note: it is possible that the same problem exists on Microsoft
systems as well if they are using a PostScript interpreter.

Detailed Explanation:

GhostScript is used to convert PostScript files to formats compatible
with printers and other devices.  It is used as a utility by a
large number of 'print filters', including MagicFilters, format
converters, LPRng's IFHP filter, RedHat's rh-printfilter, Transcript,
etc., etc.

The PostScript 'file' operator opens a file which can then be
read and printed.  Here is a sample of how this could be done:

Save these lines to 'testpr':

%!
% Code extracts from PostScript Language Tutorial and Cookbook
%  Copyright 1986, Adobe Systems.

% set up printing
/finr /Helvetica findfont 10 scalefont def
/shwr {moveto finr setfont show} def
% do the dirty work here
(/etc/passwd) (r) file
% read a single line
100 string readline pop 45 292 shwr showpage

Now run this using GhostScript:

#> gs testpr

If you see the first line of the /etc/passwd file displayed then
you have a possible compromise.  If GhostScript is used to convert
PostScript to PCL or some other non-PostScript format then you can
print copies of the various files of interest.

Now try this with -dSAFER -dPARANOIDSAFER

#> gs -dSAFER -dPARANOIDSAFER testpr

If you see the same output, then the -dSAFER -DPARANOIDSAFER is
not preventing file access.

MORE BAD NEWS:

Now, you might think this is the worst that can happen...
Nope.  I just discovered the following:

a)  GhostScript can open files for writing as well as reading.
b)  Some vendors run their print filters as ROOT.
c)  Some do not have -dSAFER enabled.

You might want to think about:

  (/etc/shadow) (w) file (root:::::) writeline

There... did your blood run cold?  Or are you rushing out to
try this on your local system to see if the Sysadmin has fixed
this?  (Note for sysadmin: there is no 'writeline' primitive,
but they will whip one up REAL SOON NOW, so get moving.)

AND A POSSIBLE ADDITIONAL EXPLOIT:

In addition to the 'file' command,  there is also the 'run' command
that will open a file and execute its contents.  I can't think of
any use for this, but better to be safe than sorry.  Since most
students^H^H^H^H^H^H users are smarter than me,  they will most
likely think of one.

IMMEDIATE STEPS TO TAKE:

Step 1:  TURN OFF PRINTING NOW!  Kill the LPD print spooler
   server or the lpsched print spooling server:

    pkill lpd
      OR
    killall lpd
      OR
    ps -e |grep lpd;   find the PID of the lpd process
                       and do:  kill PID

    ps -e |grep lpsched;   find the PID of the lpsched process
       and do:  kill PID

Step 2: Update to the latest version of GhostScript that has
   -dSAFER implemented.  Rerun this test.  If the test
    succeeds (i.e. - bad things happens, then proceed to
    step 3).

Step 3: Modify the gs_init.ps file.  It is usually in:

/usr/share/ghostscript/XXX/lib/gs_init.ps

where XXX is the version of GhostScript.  See the notes below
for your verion of GhostScript.

Step 4: return the tests described above.  They should now
  fail.  If not,  then consult a GhostScript Wizard.  (Actually,
  you need to consult a GhostScript Medium or even GhostScript
  Small, but I digress.)

Step 5: Check all of your applications that are executable by
 root (including GhostView (gv) and other) to make sure that they
 have the -dSAFER defined.  Note that this might need to include
 PostScript to PDF converters, and PDF to PostScript converters.

----------- AFPL Ghostscript 6.50 (and possibly others) -------------

1. open the gs_init.ps file.
2. Look for the following lines and add the lines
   with - in front of them.

  % If we want a "safer" system, disable some obvious ways to cause havoc.
  SAFER not { (%END SAFER) .skipeof } if
  /file
   { dup (r) eq 2 index (%pipe*) .stringmatch not and
     2 index (%std*) .stringmatch or
      { file }
      { /invalidfileaccess signalerror }
     ifelse
   } .bind odef
- /file { /invalidfileaccess signalerror } odef
- /run { /invalidfileaccess signalerror } odef
  /renamefile { /invalidfileaccess signalerror } odef
  /deletefile { /invalidfileaccess signalerror } odef
  /putdeviceprops

3. Rerun the tests and make sure that they now faile.

-------------------------------------------------------------


------------- AFPL Ghostscript 7.03  (and possibly others) --
 
From: Carl Riches <riches@ms.washington.edu>
I have just installed AFPL Ghostscript 7.03, and found that I had to
replace part of the file:
 
  gs_init.ps
 
with this code:
 
% If we want a "safer" system, disable some obvious ways to cause havoc.
SAFER not { (%END SAFER) .skipeof } if
 
.currentglobal true .setglobal
/SAFETY 2 dict
  dup /safe DELAYSAFER not put
  dup /tempfiles 10 dict put
readonly def
.setglobal
 
/.setsafe
  { //SAFETY /safe //true .forceput % overrides readonly
  } .bind executeonly odef
 
/file
 { //SAFETY /safe get {
     dup (r) eq
     2 index (%pipe*) .stringmatch not and
     3 index (%std*)  .stringmatch not and
     or or
       { file }
       { /invalidfileaccess //signalerror exec }
     ifelse
   } {
     file
   } ifelse
 } .bind executeonly odef

 
Here are the actual SCCS diffs of the file:
 
------- gs_init.ps -------
1567,1568c1567,1570
<      dup (r) eq 2 index (%pipe*) .stringmatch not and
<      2 index (%std*) .stringmatch or
---
>      dup (r) eq
>      2 index (%pipe*) .stringmatch not and
>      3 index (%std*)  .stringmatch not and
>      or or

------------------------------------------------------------

Patrick Powell                 Astart Technologies
papowell@astart.com            6741 Convoy Court
Network and System             San Diego, CA 92111
  Consulting                   858-874-6543 FAX 858-751-2435
LPRng - Print Spooler (http://www.lprng.com)
