2015-11 Web Applications (Snort Report 1.3.4, Zen Cart 1.3.9f, Joomla 2.5.19)
The importance of securing web applications cannot be overstated. In this week, we will start by setting up a few simple PHP based web applications- Snort Report, Zen Cart, and Joomla.
For simplicity, all of these will be set up on the same web server. We will separate these applications through directory aliasing, but we could just as simply configure the system with multiple IP addresses and set up virtual hosts for each application.
We start with a base CentOS 6.2 install; you can simply grab one from the labshare. Start with the basics
- Configure the IP address (10.0.2.26 in this example)
- Configure the host name (pollux.cosc.tu in this example)
- Ensure that Apache (httpd) is set to start on boot
- Ensure that
mod_sslhas been installed
- Update the file
/etc/httpd/conf/httpd.confwith the ServerName (line 276; pollux.cosc.tu in this example)
- Open the firewall (TCP/80, TCP/443)
- For simplicity, you will also want to disable selinux
We assume we have a functioning DNS system (acheron.cosc.tu at 10.0.2.100) and a functioning database (juno.cosc.tu at 10.0.2.19).
With this as background, let’s start by installing PHP and its dependencies on our system. Make sure the DVD is pointed at an installation disc, and run the command
[root@pollux html]# yum --disablerepo=\* --enablerepo=c6-media install php php-mysql
This will install PHP and its MySQL libraries; it will also install three other packages as dependencies.
Once that is complete, restart Apache. You can check that everything is working as it ought by creating a simple PHP test page, say
/vaw/www/html/index.php with the content
<html> <?php phpinfo(); ?> </html>
With our web server up and serving PHP web pages correctly, let’s start with a simple web application- say Joomla. For those that don’t know, Joomla is an open source content management system that allows users to craft their own web sites. Though not as popular as systems like WordPress, Joomla is used by roughly 3% of all websites.
Joomla also comes with a number of extensions, some open source and some commercial.
To get it installed, start by downloading the required package, either from the labshare or online. Note that older versions of Joomla are cleared from the official web site, and so this link is likely to be stale soon enough. Older versions of Joomla are available at JoomlaCode.
Unpack the result in an appropriate directory. I recommend creating the directory
/usr/local/joomla and unpacking the archive there.
[root@pollux ~]# mkdir /usr/local/joomla [root@pollux ~]# cd /usr/local/joomla/ [root@pollux joomla]# tar -xzvf /home/zathras/Desktop/Joomla_2.5.19-Stable -Full_Package.tar.gz
One interesting feature I encountered was the fact that, if the uncompression was performed by root, it would assign the UID 501 and GID 80 to all of the files. This was particularly perplexing, as my system does not have a user with UID 501 or a group with GID 80. Uncompressing as the non-root user zathras, I found that the files were owned by user zathras of group zathras. Shrug.
Either way, we are going to start by setting the files to be owned by user apache and group apache.
[root@pollux joomla]# chown -R apache:apache /usr/local/joomla/
Now we want Apache to serve these files, but they are not in the usual spot (
/var/www/html). The solution is simple enough- create an alias. Create the file
/etc/httpd/conf.d/joomla.conf with the single line
Alias /joomla "/usr/local/joomla"
Then accessing the web server at
http://pollux.cosc.tu/joomla will serve pages from the directory
/usr/loca/joomla where we placed our web application.
Be sure to reload Apache
[root@pollux joomla]# service httpd reload Reloading httpd:
Then, if you visit the page
http://pollux.cosc.tu/joomla/installation/index.php from this or another system, then you should be presented with the installation page
Before we go further and work through the installation process, we want to go back to the database, and get it set up. Log into that database as a root user. Once there, create a database named
joomla. Create a user with full privileges on that database from the web server.
[zathras@juno ~]$ mysql -u root -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 19 Server version: 5.1.52 Source distribution Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. This software comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to modify and redistribute it under the GPL v2 license Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> create database joomla; Query OK, 1 row affected (0.00 sec) mysql> grant all on joomla.* to firstname.lastname@example.org identified by "password1!"; Query OK, 0 rows affected (0.00 sec) mysql> \q Bye
We will use this information later in the installation.
Go ahead an continue with the installation. All of the required entries in the pre-intallation check should validate. Joomla prefers output buffering to be off, while the default PHP setting for CentOS is a 4096 byte buffer. You can change that (if you wish) by commenting out line 264 in
/etc/php.ini where it is being set.
If you cannot figure out why
configuration.php is not writable, well, the answer is simply SELinux.
When you get to the database configuration, specify MySQL as the database type, and enter the information you selected earlier. The Table Prefix is there to make blind SQL injection attacks on the back end database that much more difficult.
Since you have direct access to the server, there is no need to set up FTP.
Choose a site name (I chose JoomlaTest), and email address (you can use the email address for exercise 3 here) and an admin password. A good one!
You also will want to install some sample data; I chose the Default English (GB) Sample Data set.
When all is finished, you will remove the
installation folder. This will simply delete the folder
Zen Cart is a common PHP based web application for e-commerce sites. Like Joomla, it is a traditional LAMP stack product, meaning it can be run with the combination Linux, Apache, MySQL, and PHP. It also can be installed with a demonstration shop filled with sample products; we will use this feature as well.
We are using an older version of Zen Cart; version 1.3.9f was released in August 2010, and was quickly followed by 1.3.9g, roughly a month later; the current version is 1.5.1. Why use the older version? Two reasons- its release time is contemporaneous with many of the tools we are using. It is also the case that some older versions of Zen Cart have some interesting vulnerabilities. Real web applications all have vulnerabilities, and real systems need to be configured to minimize them. By working with a web application that we know to be vulnerable in class, we all pay close attention to mitigation methods.
We will install the web site on the same system (
pollux.cosc.tu) as our Joomla installation, and we will use the same database server (
You can grab a copy of Zen Cart 1.3.9f online or on the lab share.
We already have set up the web server and PHP. There is one additional change we need to make in this case. The PHP time zone must be correctly set; this can be done by editing
/etc/php.ini, line 946 and make the change:
[Date] ; Defines the default timezone used by the date functions ; http://www.php.net/manual/en/datetime.configuration.php#ini.date.timezone date.timezone = America/New_York
As before, you will need to reload the apache configuration for this change to take effect.
Copy the ZenCart archive to your system, and uncompress it. In this example, we’ll uncompress it to
[root@pollux ~]# cd /usr/local/ [root@pollux local]# unzip /home/zathras/Desktop/zen-cart-v1.3.9f-full- fileset-08142010.zip ... Output Deleted .... [root@pollux local]# mv zen-cart-v1.3.9f-full-fileset-08142010/ zen-cart-v1.3.9f [root@pollux local]# chown apache:apache -R /usr/local/zencart/
Next we create an appropriate alias; we create the file
/etc/httpd/conf.d/zencart.conf with the content
Alias /zencart "/usr/local/zencart"
Again, we could also have set up a virtual host running on a different IP address instead of simply aliasing a directory.
We are going to use the web site to guide our installation of the completed shop; however before we can do so, we need to create some starter files. In particular, we need to create
./admin/includes/configure.php from provided templates. We simply copy them and set the ownership as we want:
[root@pollux zen-cart-v1.3.9f]# cp /usr/local/zen-cart-v1.3.9f/includes/dist- configure.php /usr/local/zen-cart-v1.3.9f/includes/configure.php [root@pollux zen-cart-v1.3.9f]# chown apache:apache /usr/local/zen-cart- v1.3.9f/includes/configure.php [root@pollux zen-cart-v1.3.9f]# cp /usr/local/zen-cart-v1.3.9f/admin/includes/ dist-configure.php /usr/local/zen-cart-v1.3.9f/admin/includes/configure.php [root@pollux zen-cart-v1.3.9f]# chown apache:apache /usr/local/zen-cart- v1.3.9f/admin/includes/configure.php
To handle the warning, we need to install the appropriate
gd packages on our web server. To do so, mount the first installation
.iso and use
yum to add the needed package along with its dependencies.
[root@pollux ~]# yum --disablerepo=\* --enablerepo=c6-media install php-gd
When this completes, restart the web server;
[root@pollux zen-cart-v1.3.9f]# service httpd restart Stopping httpd: [ OK ] Starting httpd: [ OK ]
At this point, we are just about ready to install. All we need to do is to make sure that the database is ready for us.
As we did before, we create a database; this one we’ll call zencart. We then create a user (named zencart) and give it full permissions on that one database.
[zathras@juno ~]$ mysql -u root -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 83 Server version: 5.1.52 Source distribution Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. This software comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to modify and redistribute it under the GPL v2 license Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> create database zencart; Query OK, 1 row affected (0.00 sec) mysql> grant all on zencart.* to email@example.com identified by "password1!"; Query OK, 0 rows affected (0.00 sec)
Be sure you take the time to verify that you can connect to the database from the web server with your credentials.
[root@pollux ~]# mysql -u zencart -h juno.cosc.tu -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 84 Server version: 5.1.52 Source distribution Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. This software comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to modify and redistribute it under the GPL v2 license Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> use zencart; Database changed
Once you accept these values, the installation script will create the required tables in the database.
By the way- if you get hung up here with errors indicating that you can’t connect to the database (at all) even though you can do so from the
mysql client and end up seeing error code (13), I can tell you the source of the problem. SELinux. (Again). It only took me six hours to debug that one out. Error messages people- they are your friend, except when they come (or actually, don’t) from SELinux.
Now we would like to protect our website with SSL, after all it is an e-commerce site. Proceedings as we did in notes 2014-06, first generate a server key:
[root@pollux ~]# openssl genrsa -out /etc/pki/tls/private/pollux.key 4096 Generating RSA private key, 4096 bit long modulus .....................................++ ............................................................................................................................++ e is 65537 (0x10001)
Next, we generate the certificate signing request:
[root@pollux ~]# openssl req -new -key /etc/pki/tls/private/pollux.key -out /etc/pki/tls/misc/pollux.csr 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) [XX]:US State or Province Name (full name) :Maryland Locality Name (eg, city) [Default City]:Towson Organization Name (eg, company) [Default Company Ltd]:Towson University Organizational Unit Name (eg, section) :Security Laboratory Common Name (eg, your name or your server's hostname) :pollux.cosc.tu Email Address : Please enter the following 'extra' attributes to be sent with your certificate request A challenge password : An optional company name :
Now back in notes 2014-06, we set up a CA, which we named
furies.cosc.tu. Copy the
pollux.csr) back to the CA, sign it, and then copy it back.
[root@furies ~]# openssl x509 -req -days 365 -in /etc/pki/CA/pollux.csr -CA /etc/pki/CA/certs/ca.crt -CAkey /etc/pki/CA/private/ca.key -set_serial 04 -out /etc/pki/CA/newcerts/pollux.crt Signature ok subject=/C=US/ST=Maryland/L=Towson/O=Towson University/OU=Security Laboratory/CN=pollux.cosc.tu Getting CA Private Key Enter pass phrase for /etc/pki/CA/private/ca.key: [root@furies ~]# scp /etc/pki/CA/newcerts/pollux.crt firstname.lastname@example.org:/home/zathras/Desktop/pollux.crt
Move the signed certificate
pollux.crt to the expected place
/etc/pki/tls/certs/pollux.crt. Tell Apache to use this certificate and key in the usual way updating the
<VirtualHost> directive of the
/etc/httpd/conf.d/ssl.conf file modify the following lines:
SSLCertificateFile /etc/pki/tls/certs/pollux.crt SSLCertificateKeyFile /etc/pki/tls/private/pollux.key
Restart Apache in the usual fashion.
You will be able to continue the ZenCart installation from where you left off.
The remaining configuration elements are standard. I strongly recommend using the Demo store; either the demo or something of your own creation will be required in Exercise #3.
Don’t forget to set good solid passwords for your administrator account. You can give it any name you wish; for simplicity I am using "zathras". There is no need to check for Zen Cart upgrades- we know they exist, and we won’t be on a public network anyway.
Now we no longer need to update the files
admin/includes/configure.php, so let’s remove that.
[root@pollux ~]# chmod 444 /usr/local/zen-cart-v1.3.9f/includes/configure.php [root@pollux ~]# chmod 444 /usr/local/zen-cart-v1.3.9f/admin/includes/configure.php
Delete the directory
php [root@pollux ~]# rm -rf /usr/local/zen-cart-v1.3.9f/zc_install/
Finally, we want to change the location of the admin directory; this will make it more difficult for attackers to try to brute-force the administrator password. Lacking a certain degree of cleverness, in this example let’s just rename the
admin folder to
secretadmin. [Who would guess that?]
[root@pollux ~]# mv /usr/local/zen-cart-v1.3.9f/admin/ /usr/local/zen-cart-v1.3.9f/secretadmin
Next we update the directives in the file
/usr/local/zen-cart-v1.3.9f/secretadmin/includes/configure.php with the new information. Update lines 42-45 with the new folder location
define('DIR_WS_ADMIN', '/zencart/secretadmin/'); define('DIR_WS_CATALOG', '/zencart/'); define('DIR_WS_HTTPS_ADMIN', '/zencart/secretadmin/'); define('DIR_WS_HTTPS_CATALOG', '/zencart/');
Also update lines 61-62 in the same fashion
define('DIR_FS_ADMIN', '/usr/local/zen-cart-v1.3.9f/secretadmin/'); define('DIR_FS_CATALOG', '/usr/local/zen-cart-v1.3.9f/');
Take the time to verify that SSL is working as it ought.
Snort Report is a graphical interface to the alerts generated by a Snort intrusion detection system and stored in a database.
These notes presuppose that you have successfully installed Snort as we did in 2014-08, and that you have successfully configured MySQL and Barnyard2 to store the results of Snort as per 2014-09.
Like Zen Cart, Snort Report depends on
php-gd, so install this if necessary.
There are different versions of JpGraph appropriate for different versions of PHP. Despite the fact that we are running PHP 5, the preferred version of JpGraph for SnortReport is the older version 1.27.1.
Unzip the JpGraph package in the PHP include path,
/usr/share/php/ to create
[root@pollux ~]# cd /usr/share/php/ [root@pollux php]# tar -xzvf /home/zathras/Desktop/jpgraph-1.27.1.tar.gz
For simplicity going forward, create a symbolic link from jpgraph to the
src subdirectory in the form
jpgraph-1.27.1/QPL.txt [root@pollux php]# ln -s /usr/share/php/jpgraph-1.27.1/src /usr/share/php/jpgraph
This will enable PHP scripts that require JpGraph to simply use lines like
To test the installation, first copy the
jpgraph directory over to a test subdirectory in the web server’s document root:
[root@pollux php]# cp -r /usr/share/php/jpgraph-1.27.1/src/ /var/www/html/test
There is a more complete and thorough testing suite available; just visit
http://pollux.cosc.tu/test/Examples/testsuit.php. Be prepared to wait a few moments for all of the graphs to render. This page will generate some errors, primarily though not exclusively font errors. The JpGraph suite allows the writer to specify the fonts used, and in many examples they specify a particular Windows font from
C:\Windows\Fonts. By default on our system, JpGraph will look for the fonts in
/usr/share/fonts/truetype and if the correct font is placed there, the images will render correctly. If not, well, then whining ensues. Shrug.
Once testing is complete, the
test directory should be removed from DocumentRoot- there is no reason to continue serving those pages.
With JpGraph running, next grab a copy of Snort Report, either online or from the labshare. In this example, we will be using the latest version, 1.3.4.
Unzip the package directly into the usual place,
/usr/local. For convenience so that we do not have to remember the version number in the URL, create a symlink to the proper directory
[root@pollux local]# cd /usr/local/ [root@pollux local]# tar -xzvf /home/zathras/Desktop/snortreport-1.3.4.tar.gz
Once again, we set up an alias. Create the file
/etc/httpd/conf.d/snortreport.conf with the content
Alias /snortreport "/usr/local/snortreport-1.3.4"
Don’t forget to reload the Apache configuration after making the change.
Some modifications then need to be made to the structure of PHP. First, the time zone must be correctly set as we did for Zen Cart.
More significantly, we need to tell PHP to recognize short opening tags. This is not the preferred way to write PHP, but it is the way that the authors of SnortReport chose, so we modify line 229 of
; This directive determines whether or not PHP will recognize code between ; <? and ?> tags as PHP source which should be processed as such. It's been ; recommended for several years that you not use the short tag "short cut" and ; instead to use the full <?php and ?> tag combination. With the wide spread use ; of XML and use of these tags by other languages, the server can become easily ; confused and end up parsing the wrong code in the wrong context. But because ; this short cut has been a feature for such a long time, it's currently still ; supported for backwards compatibility, but we recommend you don't use them. ; Default Value: On ; Development Value: Off ; Production Value: Off ; http://www.php.net/manual/en/ini.core.php#ini.short-open-tag short_open_tag = On
With the changes made to
/etc/php.ini, the web server needs to be restarted to take the changes into account:
[root@pollux html]# service httpd restart Stopping httpd: [ OK ] Starting httpd: [ OK ]
Next, we need to create an account on the database server for the connection by SnortReport. Recall, in 2014-08 we deployed a Snort sensor on the host hydra.cosc.tu. In Notes #9, we set up a database on the separate host juno.cosc.tu to store the data generated by that sensor. In this example, we will assume that the web application host is separate from either the sensor or the database with the name pollux.cosc.tu. Of course, this is not necessary; any two, or even all three of these hosts can be the same.
Now we already set up an account for the snort database, but that was for the sensor. Since the web server is on a different system, we need a new account for the webserver system that can access the database. This is simply done however:
mysql> grant all on snort.* to email@example.com identified by "password1!"; Query OK, 0 rows affected (0.00 sec)
Verify that it worked by logging into the database system directly from the web application server:
[root@pollux local]# mysql -u snort -h juno.cosc.tu -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 102 Server version: 5.1.52 Source distribution Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. This software comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to modify and redistribute it under the GPL v2 license Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> use snort; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> select * from event limit 10; +-----+-----+-----------+---------------------+ | sid | cid | signature | timestamp | +-----+-----+-----------+---------------------+ | 1 | 1 | 501 | 2014-04-06 11:49:21 | | 1 | 2 | 501 | 2014-04-06 11:49:21 | | 1 | 3 | 501 | 2014-04-06 11:49:21 | | 1 | 4 | 501 | 2014-04-06 11:49:21 | | 1 | 5 | 501 | 2014-04-06 11:49:21 | | 1 | 6 | 501 | 2014-04-06 11:49:21 | | 1 | 7 | 501 | 2014-04-06 11:49:21 | | 1 | 8 | 501 | 2014-04-06 11:49:21 | | 1 | 9 | 501 | 2014-04-06 11:49:21 | | 1 | 10 | 501 | 2014-04-06 11:49:21 | +-----+-----+-----------+---------------------+ 10 rows in set (0.00 sec)
Next, SnortReport itself must be configured; this is done by editing the file
/var/www/html/snortreport/srconf.php. Update the snort database variables in lines 28-32 with the values just chosen:
// Put your snort database login credentials in this section $server = "juno.cosc.tu"; $user = "snort"; $pass = "password1!"; $dbname = "snort";
Finally, the location of JpGraph needs to be selected; modify line 44 to read
Do you think that this might be easier than looking through Splunk logs of snort alerts?