Nothing new under the Sun – Discovering and exploiting a CDE bug chain

“What has been will be again,
what has been done will be done again;
there is nothing new under the Sun.”
— Ecclesiastes 1:9

TL;DR

We have identified multiple security vulnerabilities that are exploitable via the the setuid-root dtprintinfo binary from the Common Desktop Environment (CDE) distributed with Oracle Solaris 10:

  • A bug in the parser of the lpstat external command invoked by dtprintinfo to list the names of available printers allows low-privileged local users to inject arbitrary printer names.
  • This printer name injection allows low-privileged local users to manipulate the control flow of the target program and disclose memory contents.
  • The ability to inject arbitrary printer names opens other attack vectors: as an example, we discovered multiple icon parsing bugs in the Motif library libXm that cause memory corruption.

We demonstrated the possibility to chain together the printer name injection bug and a stack-based buffer overflow in libXm to achieve local privilege escalation to root on a fully-patched Solaris 10 system.

Our detailed advisory is available here: https://github.com/hnsecurity/vulns/blob/main/HNS-2022-01-dtprintinfo.txt

Our proof-of-concept exploit is here: https://github.com/0xdea/exploits/blob/master/solaris/raptor_dtprintlibXmas.c

Discovery

Following our last CDE vulnerability disclosures, Oracle kindly shared with us a copy of their then current Solaris 10 security patch set (CPU January 2021), so that we could install it in our lab and verify the fixes for the bugs we had reported.

In addition to verifying these fixes, we decided to take a closer look at the dtprintinfo program distributed with CDE, because of its complexity and its impressive historical record of high-impact vulnerabilities.

After fruitlessly spending a few days reversing and auditing the patched version of dtprintinfo, we came up with the idea of using the poor man’s fuzzer below to quickly check for the presence of flaws in the parsing of the $HOME/.printers file:

$ cat /dev/urandom > ~/.printers
^C

Indeed, this led to immediate results. It turns out that it is possible to inject fake printers to be displayed by dtprintinfo. In addition, by manipulating the injected printer names, we were able to trigger an out-of-bound read and disclose partial heap memory contents of our target setuid-root binary. Check out the advisory for a detailed analysis of these two bugs.

Being able to inject arbitrary printer names is significant also because it opens other attack vectors that otherwise would not be available on systems without configured printers. One such vector we thought that was worth exploring is the parsing of printer icons in the XPM format. A low-privileged local user can supply his or her own icons for dtprintinfo to show by placing them in the $HOME/.dt/icons directory and selecting them in the X11 GUI. A bug in the XPM parser could easily lead to memory corruption and privilege escalation. To prove our point, we built a rudimentary mutation fuzzer written in Python and we unearthed a few icon parsing bugs in the libXm library used by CDE, originally part of the Motif toolkit. Check out the advisory for additional details.

After our brief but intense artisanal fuzzing experience, it was time to go back to static analysis for a short while, specifically targeting the apparently weak libXm library parser. We fired up our Rhabdomancer Ghidra script to quickly find locations in the library where dangerous API functions are called, using them as starting points for our binary audit. Among some interesting candidate points, the following one stood up, in the familiar ParseColors() function that we had already encountered while analyzing the crashes produced by our XPM fuzzer:

int ParseColors(int *data, uint ncolors, uint cpp, undefined4
        *colorTablePtr, undefined4 hashtable)
{
    ...
    char local_83c[1024];
    char local_43c[1024];
    ...
    local_c = _XmxpmNextWord(local_34, local_83c, 0x400);
    ...
    local_83c[local_c] = '\0';
    strcat(local_43c, local_83c); /* VULN */
}

A perfect specimen of stack-based buffer overflow, caused by the reckless use of the insecure API function strcat(). This vulnerability can be triggered via a specially crafted XPM icon with long color strings.

Exploitation

We have created a proof-of-concept exploit that chains together the printer name injection bug and the stack-based buffer overflow we have identified in libXm. It allows a low-privileged local user to escalate his or her privileges to those of the root user on Intel-based Solaris 10 systems with the latest patches installed (tested on CPU January 2021).

The exploit code is extensively commented and should be self-explanatory. Here it is in action.

Disclosure and Fix

The disclosure timeline spans exactly one year:

  • 2022-01-18: Oracle was notified via <secalert_us@oracle.com>.
  • 2022-01-19: Oracle acknowledged our vulnerability reports.
  • 2022-04-20: Asked Oracle to provide an update on the patch release date.
  • 2022-04-21: Oracle replied they could not comment on the patch release date.
  • 2022-09-03: Asked Oracle for an update and informed them of our plan to publish a detailed advisory and a blog post before the end of 2022.
  • 2022-09-12: Oracle replied they are working on the bugs and will be able to give an update closer to the next CPU, scheduled for October.
  • 2022-10-18: Oracle informed us that the vulnerabilities will be fixed in their CPU of January 2023.
  • 2022-12-20: With a surprise move, Oracle informed us that Solaris 10 desktop components have reached EOL and are no longer supported. Therefore, Oracle will not be releasing patches for bugs affecting Solaris 10. They will work with X.Org to get a fix and an advisory released upstream for the first crash we identified in libXm, which also affects X.Org libXpm. This denial of service bug will be fixed in Solaris 11.4. As a final note, it appears that the buffer overflows we discovered in ParsePixels() and ParseColors() were already reported by Chris Evans in 2004 and tracked as CVE-2004-0687. Due to an incomplete fix, they were not patched in Solaris 10 and have survived in the code for 19 years! Since no patches for Solaris 10 will be released, these issues have officially become #ForeverDay bugs.
  • 2023-01-17: X.Org released libXpm 3.5.15, which fixes CVE-2022-46285 (infinite loop on unclosed comments in X.Org libXpm). Oracle published their CPU January 2023, which unfortunately does not include fixes for our bugs that affect Solaris 10.
  • 2023-01-18: Oracle informed us that Solaris 10 desktop components have reached EOL at the end of 2019. EOL is documented in support note 1400676.1, behind the paywall for Oracle’s customers with current support contracts. HN Security published this advisory and a local privilege escalation exploit.
  • 2023-01-20: Mitre has assigned CVE-2023-24039 to the buffer overflow in libXm and CVE-2023-24040 to the printer name injection and heap memory disclosure bugs.

See the advisory for remediation advice, including a partial workaround.