November, 2008


4
Nov 08

Script kiddies have awesome tools

About 10 years ago a friend of mine showed me an exploit. It was written in C and it tried to spawn a shell at a remote host. It seemed pretty cool. I did not understand the code but the mere idea that almost anybody equipped with a script like that could deface a webpage seemed scary.

You did have to compile the c file, have the right devel packages installed and use the correct flags. And then you had to figure out how to use it. A 14yr old could do it.

Today I spent many hours grepping logs, checking the filesystem for new/changed files to figure out how an old WordPress instance was hacked and what had the hacker done there.

Going through the changed files I stumbled upon a php file which had some code prepended. The script had a very long line that started like this:
[PHP]
eval(gzinflate(base64_decode(‘FJ3HcqPsFkUf……..
[/PHP]

Ok, lets check what does the script do. Lets assign the long string to a variable and base64 decode it and inflate the compression.
[PHP]
$script = base64_decode($script);
$script = gzinflate($script);
echo $script;
[/PHP]

The output was not what I expected.
[PHP]
eval(gzinflate(base64_decode(‘FJ3HjqPcGkUf57……..
[/PHP]

The strings looked similar and I was already looking for an error in my code. Nope, code is correct. There is a slight change in the string. It seems it was compressed and encoded couple of times. Wow, it means I can have many evals inside evals. Fun!
[PHP]
do {
// extract the first 28 characters
// the eval(gzinflate(base64_decode part
$start = substr($string, 0, 28);
// remove the first 30 chars, the eval(gzinflate(base64_decode(‘ part
$string = substr($string, 30);
// remove the last )));
$string = substr($string, 0, strlen($string)-4);

$string = base64_decode($string);
$string = gzinflate($string);
echo “Iteration:”.$i++.”\n”;
// iterate as long as we get a eval(gzinflat start
} while ($start == “eval(gzinflate(base64_decode”);
[/PHP]

After 11 iterations I got the code. Kind of reminded me a challenge that was posted to a mailing list and the question was what was the output of the program. That time it was more difficult: base64 encoded perl, that outputted base64 encoded bytecode, that outputted Java source file with a byte array that was byte code for the class file of the solution.

Anyways the 11 iterations gave me this (shot is made from my home computer).
Wow!

Lets see the functionality that it has to offer:

  • Full blown file manager
  • Quick menu for
    • Finding all suid files
    • Finding all sgid files
    • Finding all htaccess files
    • Finding all writeable folders
  • Interface for the UNIX tool find
  • Input field for executing commands as webserver user
  • Tools for installing a backdoor
    • Perl/C flavoured programs that are downloaded from a Singapore server
    • Compiled/Interpreted – depending what is available
  • Processes viewer
  • FTP brute force cracker using users from /etc/passwd
  • System info (CPU, Memory, installed binaries, passwd file, configuration files)
  • SQL dump utility
  • Interface for executing PHP code
  • Self removal
  • Adding a password for the script
  • Fancy design!

I’m just amazed. This is way too eazy. So this is how it works:

  • Lets scan the internet for WordPress installation (automated)
  • Look for vulnerable versions (automated)
  • Exploit (in this case themes were filled with hidden links – semi automated)
  • PROFIT! (automated)

How to avoid being hacked:

  • Keep an eye on your WordPress installations
  • Subscribe to WordPress release emails/RSS and upgrade when needed
  • Monitor for changed files (for example fcheck)
  • Run Apache in chroot to minimize the available software for the Apache user
  • Any other ideas?

PS. The script is 2500 lines of code, supports Windows and Linux and looks great :)


3
Nov 08

When protected isn’t protected

For all those spec believers out there: what would you think if I told you that all of the JVM implementations consistently violate the spec for at least one particular instance?

Our story begins on a cold and lonely evening when I discover a bug in JavaRebel in conjunction with Xerces XMLEntityManager. The problem was with the following method:
[java]
public String[] getRecognizedProperties() {
return (String[])(RPROPERTIES.clone());
}
[/java]
However when I looked at the class bytecode I saw a different picture:
[java]
{
GETSTATIC XMLEntityManager.RPROPERTIES : String[]
INVOKEVIRTUAL Object.clone() : Object[]
CHECKCAST String[]
ARETURN
}
[/java]
For those of you who do not spend hours staring at the Java bytecode, it does the following:

  1. Retrieve the RPROPERTIES static field value (which is of type String[]) and put it on the top of the stack.
  2. Call Object.clone() using the top of the stack as target object (in our case the array). The target is popped off the stack and the result is placed on top of the stack instead of it.
  3. Cast the top of the stack to a String[]
  4. Return the top of the stack as method result.

Whooph. Now that is all fine except for one tiny thing. This is not legal. Object.clone() is a protected method and the JVM spec (see 2.7.4, INVOKEVIRTUAL) allows calls to protected method only if the following is true:

  1. The accessing class is a subclass of the target class or is the same class (check, XMLEntityManager is a subclass of Object, so’s everything else).
  2. The class of the target object (the actual runtime class of the object, not the target class we use in the signature) is either a subclass of the accessing class or is the same class.

The second check may sound crazy, but it restricts the calls to protected methods only to the classes inheriting from the target class, as you would expect. It can also only be enforced during runtime and is the cause of the IllegalAccessError you may see once in a while.

And obviously in our case String[] that is the actual type of the target object is in no way a subclass of the XMLEntityManager. This call should have cause an error in the JVM, but for some inexplicable reason it doesn’t. Further tests show that this is only limited (AFAIK) to the Object.clone() call, which is public as far as JVM cares.

A little googling turned up two JVM bugs that were discussing the same issue (bug 1, bug 2). Turns out the Sun javac compiler has been emitting wrong code at least until 1.4.2 and the JVMs have accommodated accordingly right until today.

Does this have any practical importance? Not for most of you, but if you handle Java bytecode in any way be prepared to handle this exception as well. To me it proves that there is more to Java than just the spec.