Trend Micro OfficeScan – A chain of bugs

Author: b

Analyzing the security of security software is one of my favorite research areas: it is always ironic to see software originally meant to protect your systems open a gaping door for the attackers. Earlier this year I stumbled upon the OfficeScan security suite by Trend Micro, a probably lesser known host protection solution (AV) still used at some interesting networks. Since this software looked quite complex (big attack surface) I decided to take a closer look at it. After installing a trial version (10.6 SP1) I could already tell that this software will worth the effort:

  • The server component (that provides centralized management for the clients that actually implement the host protection functionality) is mostly implemented through binary CGIs (.EXE and .DLL files)
  • The server updates itself through HTTP
  • The clients install ActiveX controls into Internet Explorer

And there are possibly many other fragile parts of the system. Now I would like to share a series of little issues which can be chained together to achieve remote code execution. The issues are logic and/or cryptographic flaws, not standard memory corruption issues. As such, they are not trivial to fix or even decide if they are in fact vulnerabilities. This publication comes after months of discussion with the vendor in accordance with the disclosure policy of the HP Zero Day Initiative.

(more…)


Plesk panel decryption

Author: pz

After I read the description of the Plesk vulnerability CVE-2012-1557 I decided to investigate the application a bit deeper. You can download a fully installed VMware image from the internet so you can skip the install and save some time. The PHP files which belong to the PLESK application are encrypted:

[root@localhost tmp]# cat /usr/local/psa/admin/htdocs/index.php
die(“The file {$_SERVER[‘SCRIPT_FILENAME’]} is part of Plesk 9 distribution. It cannot be run outside of Plesk 9 environment.\n”);
__sw_loader_pragma__(‘P’);
?>
1^:??Zl??9??W??RK?3??^Om??n.#’?N”??64?Z??W?[>?p?vW???`J?1?R?y?E?i38???

First of all I investigated the /usr/local/psa/bin/sw-engine-pleskrun executable which is a modified PHP interpreter:

[root@localhost ~]# /usr/local/psa/bin/sw-engine-pleskrun –help
Usage: sw-engine [options] [-f] [–] [args…]
sw-engine [options] -r [–] [args…]
sw-engine [options] [-B <begin_code>] -R [-E <end_code>] [–] [args…]
sw-engine [options] [-B <begin_code>] -F [-E <end_code>] [–] [args…]
sw-engine [options] — [args…]
sw-engine [options] -a

-a Run interactively
-c | Look for php.ini file in this directory
-n No php.ini file will be used
-d foo[=bar] Define INI entry foo with value ‘bar’
-e Generate extended information for debugger/profiler
-f Parse and execute .
-h This help
-i PHP information
-l Syntax check only (lint)
-m Show compiled in modules
-r Run PHP without using script tags
-B <begin_code> Run PHP <begin_code> before processing input lines
-R Run PHP for every input line
-F Parse and execute for every input line
-E <end_code> Run PHP <end_code> after processing all input lines
-H Hide any passed arguments from external tools.
-s Output HTML syntax highlighted source Output source with stripped comments and whitespace.
-z Load Zend extension .

args… Arguments passed to script. Use — args when first argument
starts with – or script is read from stdin

–ini Show configuration file names

–rf Show information about function .
–rc Show information about class .
–re Show information about extension .
–ri Show configuration for extension .

I tried to inspect the syscalls of the Plesk binary:

[root@localhost tmp]# strace ./sw-engine-pleskrun ../admin/htdocs/index.php
execve(“./sw-engine-pleskrun”, [“./sw-engine-pleskrun”, “../admin/htdocs/index.php”], [/* 23 vars */]) = 0
brk(0) = 0x8dc9000
.
.
.
getppid() = 17921
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0xb77967e8) = 17923
waitpid(17923, DEBUGGER DETECTED… Bye!
Killed

I did a quick search for the error message in the binary:

[root@localhost tmp]# strings /usr/local/psa/bin/sw-engine-pleskrun | grep “DEBUGGER DETECTED”
[root@localhost tmp]#

Found nothing, so it seems that the sw-engine-pleskrun binary is just a framework executable and another one does the actual PHP processing. Let’s see which files are accessed by the binary:

[root@localhost tmp]# strings /usr/local/psa/bin/sw-engine-pleskrun | grep -i “/usr”
/usr/bin/sw-engine
/usr/sbin/rblsmtpd
/usr/local/psa/bin/php-cli
/usr/share/awstats
/usr/share/tomcat6
/usr/lib/mailman
/usr/bin
/usr/bin/webalizer
/usr/local/psa

The sw-engine and the php-cli binaries seem to be good targets from the list above. When I ran the php-cli application I got the following message:

[root@localhost tmp]# /usr/local/psa/bin/php-cli /usr/local/psa/admin/htdocs/index.php
Failed loading /usr/lib/php/modules/ioncube_loader_lin_5.3.so: /usr/lib/php/modules/ioncube_loader_lin_5.3.so: cannot open shared object file: No such file or directory
The file /usr/local/psa/admin/htdocs/index.php is part of Plesk 9 distribution. It cannot be run outside of Plesk 9 environment.

Let’s see what our first contestant says when we ask it to parse an encrypted PHP file:

[root@localhost tmp]# /usr/bin/sw-engine /usr/local/psa/admin/htdocs/index.php

Fatal error: Call to undefined function get_gpc() in /usr/local/psa/admin/htdocs/index.php on line 2

Sounds good! Fire up the IDA Pro Disassembler and collect some starting information: Look for the plain strings from the encrypted PHP files in the binary (like “__sw_loader_pragma__(‘P’);”):

ida1

Let see which function references this string:

ida2

By deeper investigating the open_file_for_scanning() function you will see that the BF_decrypt() function constructs the executable PHP code:

ida3

For the quick and effective result – bypass the ptrace, debug the decrypt function, collect the crypto key, etc… – I used the following method:
The open_file_for_scanning() function uses memcpy() to construct the unencrypted PHP code. I created a shared library which redeclares the memcpy function, I used it with the LD_PRELOAD technique and voila, readable source code:

#include
#include

int i=0;

void *memcpy(void *dst,const void *src,size_t len){
  if((strstr(src,”);”) > 0) && (i==0)){
  printf(“%s\n”,src);
  i=1;
}
register char *src_c, *dst_c;
src_c = (char *)src;
dst_c = (char *)dst;

while (len– > 0)
  *dst_c++ = *src_c++;
return dst;
}

 Compile the shared library with the following commands:

[root@localhost ~]# gcc -fPIC -c ld.c -o ld.o
[root@localhost ~]# gcc -shared -o ld.so ld.o

Set up the LD_PRELOAD environment variable and get the PHP source code:

[root@localhost ~]# LD_PRELOAD=/tmp/ld.so /usr/bin/sw-engine /usr/local/psa/admin/htdocs/login_up.php3
require_once(’cmd_loginup.php’);
require_once(‘sso/RelyingParty.php’);

$login_name = rtrim(get_gpc(‘login_name’));
$passwd = get_gpc(‘passwd’);

if ($session->getType() != IS_UNDEFINED && !($login_name && $passwd))
go_to(‘/logout.php3’);

if (!headers_sent())
header(‘X-Plesk: PSA-Key/’ . getKeyProp(‘plesk_key_id’));

$session_created = false;
$ssoAuthentication = null;
….

This method is far from perfect but it is easy, quick and the result is the plain source code. Happy bug hunting! ☺