Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <20230920132642.GA4325@openwall.com>
Date: Wed, 20 Sep 2023 15:26:42 +0200
From: Solar Designer <solar@...nwall.com>
To: oss-security@...ts.openwall.com
Cc: Zdenek Dohnal <zdohnal@...hat.com>
Subject: Re: CVE-2023-4504 cups, libppd: Postscript parsing heap-based buffer overflow

Hi,

"Snippet of the vulnerable code" got badly misformatted in the
text/plain version of Zdenek's message.  I include a properly formatted
snippet below, extracted from the text/html version.

Alexander

On Wed, Sep 20, 2023 at 02:56:51PM +0200, Zdenek Dohnal wrote:
> there is the same vulnerability in CUPS and libppd projects.
> 
> The original CUPS report:
> 
> 
>  CVE-2023-4504: OpenPrinting CUPS Postscript Parsing Heap Overflow
> 
> AHA! <https://takeonme.org/> has discovered an issue with CUPS from 
> OpenPrinting, and is publishing
> this disclosure in accordance with AHA!'s standard disclosure policy 
> <https://takeonme.org/cve.html> today,
> on $DATE. CVE-2023-4504 <https://takeonme.org/cves/CVE-2023-4504.html> 
> has been assigned to this issue.
> 
> Any questions about this disclosure should be directed to
> *cve@...eonme.org*.
> 
> 
>  Executive Summary
> 
> Due to failure in validating the length provided by an attacker-crafted 
> CUPS document, CUPS version v2.5b1 and prior, by default, is susceptible 
> to a heap-based buffer overflow, and possibly code execution. 
> CVE-2023-4504 <https://takeonme.org/cves/CVE-2023-4504.html> appears to 
> be an instance of CWE-122 
> <https://cwe.mitre.org/data/definitions/122.html>, a heap-based buffer 
> overflow.
> 
> 
>  Technical Details
> 
> The |scan_ps| function in the CUPS codebase provides functionality that 
> scans through a string looking for the next Postscript object. When 
> iterating through a string which contains an open parenthesis and ends 
> with a single backslash (0x5c) character, the code incorrectly iterates 
> forward a character without properly checking the bounds of the string 
> resulting in a 1 byte read beyond the allocated heap buffer.
> 
> Snippet of the vulnerable code:
> 
> cups/cups/raster-interpret.c

 1039 static _cups_ps_obj_t   *               /* O  - New object or NULL on EOF */
 1040 scan_ps(_cups_ps_stack_t *st,           /* I  - Stack */
 1041         char             **ptr)         /* IO - String pointer */
 1042 {
 ...
 1085   switch (*cur)
 1086   {
 1087     case '(' :                          /* (string) */
 1088         obj.type = CUPS_PS_STRING;
 1089         start    = cur;
 1090
 1091         for (cur ++, parens = 1, valptr = obj.value.string,
 1092                  valend = obj.value.string + sizeof(obj.value.string) - 1;
 1093              *cur;
 1094              cur ++)
 1095         {
 1096           if (*cur == ')' && parens == 1)
 1097             break;
 1098
 1099           if (*cur == '(')
 1100             parens ++;
 1101           else if (*cur == ')')
 1102             parens --;
 1103
 1104           if (valptr >= valend)
 1105           {
 1106             *ptr = start;
 1107
 1108             return (NULL);
 1109           }
 1110
 1111           if (*cur == '\\')
 1112           {
 1113            /*
 1114             * Decode escaped character...
 1115             */
 1116
 1117             cur ++;
 1118
 1119             if (*cur == 'b')
 1120               *valptr++ = '\b';
 1121             else if (*cur == 'f')
 1122               *valptr++ = '\f';
 1123             else if (*cur == 'n')
 1124               *valptr++ = '\n';
 1125             else if (*cur == 'r')
 1126               *valptr++ = '\r';
 1127             else if (*cur == 't')
 1128               *valptr++ = '\t';
 1129             else if (*cur >= '0' && *cur <= '7')
 1130             {
 1131               int ch = *cur - '0';
 1132
 1133               if (cur[1] >= '0' && cur[1] <= '7')
 1134               {
 1135                 cur ++;
 1136                 ch = (ch << 3) + *cur - '0';
 1137               }
 1138
 1139               if (cur[1] >= '0' && cur[1] <= '7')
 1140               {
 1141                 cur ++;
 1142                 ch = (ch << 3) + *cur - '0';
 1143               }
 1144
 1145               *valptr++ = (char)ch;
 1146             }
 1147             else if (*cur == '\r')
 1148             {
 1149               if (cur[1] == '\n')
 1150                 cur ++;
 1151             }
 1152             else if (*cur != '\n')
 1153               *valptr++ = *cur;
 1154           }
 1155           else
 1156             *valptr++ = *cur;
 1157         }

> Line 1085 contains the case statement which provides the logic used to 
> iterate through the given string.
> 
> On line 1091, the for loop within the case statement is used to iterate 
> through each character after encountering an open paranthesis character 
> (0x28), storing the pointer to the current character in |cur|.
> 
> On line 1111, the code checks if the current character is a backslash 
> and finally, in line 1117, the character index is incremented without 
> checking the length, now pointing to the null byte terminating the string.
> 
> Upon the next iteration of the loop, on line 1094, the loop now begins 
> iterating through unallocated memory resulting in undefined behaviour.
> 
> A Base64 encoded blob of an example PostScript document that can trigger 
> the issue is below.
> 
> |L///KFwAY3V1ZQ== |
> 
> 
>  Attacker Value
> 
> By providing this malformed PostScript document, an attacker could 
> compromise the machine running the software. Once compromised, this can 
> provide an attacker a unique, privileged position in the targeted network.
> 
> 
>  Credit
> 
> This issue is being disclosed through the AHA! CNA and is credited to: 
> zenofex <https://mastodon.social/@zenofex> and WanderingGlitch 
> <https://infosec.exchange/@WanderingGlitch>
> 
> CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:N/I:N/A:N
> 
> ========================================================================================
> 
> *Notes:*
> 
> - I've tried to reproduce the issue with any filter and PPD using the 
> code, but I didn't get crash nor valgrind report - maybe ASAN could show 
> the vulnerability, but I haven't tried this.
> 
> - the vulnerability should show up when you send the postscript string 
> above to a printer which requires cups-raster format (the vulnerable 
> code is in path when you convert postscript to raster), which is not 
> common these days - nor sending postscript or producing cups-raster.
> 
> *Updated Notes:*
> 
> I found out the vulnerability should happen only if malformed PostScript 
> sequence is in PPD file, not if the sequence is sent for printing 
> (vulnerable code was in library function used for reading PS sequence 
> which are in PPDs).
> 
> *Commits fixing the issue:*
> 
> cups: https://github.com/OpenPrinting/cups/commit/2431caddb7e6
> 
> libppd: https://github.com/OpenPrinting/libppd/commit/262c909ac5
> 
> 
> Have a nice day,
> 
> 
> Zdenek Dohnal
> 
> CUPS 2.4.x release manager
> 
> 
> -- 
> Zdenek Dohnal
> Senior Software Engineer
> Red Hat, BRQ-TPBC

Powered by blists - more mailing lists

Please check out the Open Source Software Security Wiki, which is counterpart to this mailing list.

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.