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! ☺

 


Hello world!

Author: admin

Welcome to the technical blog of the Silent Signal crew! We are a Hungarian IT-security company focused mainly on penetration testing. As strong believers of the original hacker philosophy we’ve always supported the boundless flow of thoughts and information that we’ve also been benefiting very much from. 

After years spent as determining members of the local community we decided to start giving back for the international scene also by sharing our experiences from our testing and research projects.

For starters we will post about topics which are short for a decent paper or presentation but are still worth reading for some tips, tricks or even laughs.

We already have some nice reads on stock, here is the countdown until the first one gets posted:

To stay updated you can subscribe to our syndication feed and you can follow us on Twitter