Getting WordPress Up and Going

Setting up WordPress server there were a couple of minor wrinkles to sort out. I’ve run a blog before before and that fell by the wayside when I started using a personal wiki instead. But this seems like a good opportunity to see how one of the very popular blogging platforms works and what’s involved in keeping that running under the hood.

I work primarily with Debian systems, so that was a natural place to start. The wordpress package makes it very easy to get the base dependencies going with a known supported version, so if you’re running a recent release of Debian that seems like a reasonable place to start as well. That said, this of course means that the package is reconfigured along Debian guidelines and I found that I needed to spend a little time working out how this was done before it made sense.

Directory Structure – Symlinks and the Filesystem Hierarchy Standard

Probably the most important thing to know is the way the content directories have been set up to adhere to the Debian Filesystem Hierarchy Standard – that is:

/srv/www/wp-content/<blog hostname>/

  • This directory contains all per-blog custom changes to the global WordPress installation. Symlinks are used to bring in content from /var/lib/wordpress/wp-content (and then in turn from /usr/share/wordpress).
  • Shared resources are symlinked from: /var/lib/wordpress/wp-content/

/var/lib/wordpress/wp-content/

  • Server-specific server-wide customization
  • Base level files/configuration are symlinked from: /usr/share/wordpress/

/usr/share/wordpress/

  • System-level files – treat as read only. These files are managed by the Debian package.
  • This is the Apache DocumentRoot of all WordPress instances on the server, the only content hosted from the previous two directories are under the wp-content sub-path of the blogs.
  • Note that .htaccess is symlinked to /etc/wordpress/htaccess (again to allow local customization without breaking the standard filesystem hierarchy).

There’s also some useful documentation at the Debian Wiki: WordPress

configuration Script – setup-mysql

The Debian package comes with a helper script to create the base database, configuration files and expected directory structure – this is /usr/share/doc/wordpress/examples/setup-mysql. Once used the apache configuration still needs to be manually updated, but the first step in setting up a new blog looks like:

sudo bash /usr/share/doc/wordpress/examples/setup-mysql -n brad_wordpress blog.bjdean.id.au

Apache configuration

To activate the blog instance(s) create an apache config file along the lines of:

### The default virtual host should not point to wordpress
<VirtualHost *:80>
  ServerAdmin webmaster@localhost
  ErrorLog ${APACHE_LOG_DIR}/error.log
  CustomLog ${APACHE_LOG_DIR}/access.log combined
  UseCanonicalName Off
  VirtualDocumentRoot
  /var/www/html
  Options All
</VirtualHost>

# For this configuration to work you'll also need to have mod_rewrite #and mod_vhost_alias loaded and working in Apache.
# To enable these modules run
# # a2enmod rewrite && a2enmod vhost_alias && /etc/init.d/apache2 restart

# Allow wordpress overrides in shared .htaccess
<Directory /usr/share/wordpress>
  AllowOverride All
</Directory>

# Config for wordpress
<Directory /srv/>
  Options FollowSymLinks
  AllowOverride None
  Require all granted
</Directory>
<Directory /var/lib/wordpress/>
  Options FollowSymLinks
  AllowOverride None
  Require all granted
</Directory>

# To add new WordPress blog copy and adjust this template:
#<VirtualHost *:80>
#  ServerAdmin XXXBlogHostNameXXX@example.org
#  ServerName XXXBlogHostNameXXX
#  ErrorLog ${APACHE_LOG_DIR}/XXXBlogHostNameXXX-error_log
#  TransferLog ${APACHE_LOG_DIR}/XXXBlogHostNameXXX-access_log
#
#  # Shared WordPress docroot
#  DocumentRoot /usr/share/wordpress
#
#  # wp-content in /srv/www/wp-content/$0
#  RewriteEngine On
#  RewriteRule ^/wp-content/(.*)$ /srv/www/wp-content/%{HTTP_HOST}/$1
#</VirtualHost>

# Current Blogs
<VirtualHost *:80>
  ServerAdmin admin@example.org
  ServerName blog.bjdean.id.au
  ErrorLog ${APACHE_LOG_DIR}/blog.bjdean.id.au-error_log
  TransferLog ${APACHE_LOG_DIR}/blog.bjdean.id.au-access_log

  # Shared WordPress docroot
  DocumentRoot /usr/share/wordpress

  # wp-content in /srv/www/wp-content/$0
  RewriteEngine On
  RewriteRule ^/wp-content/(.*)$ /srv/www/wp-content/%{HTTP_HOST}/$1
</VirtualHost>

What About Multi-Site?

WordPress introduced multi-site hosting within a single instance in version 3.0 but there is manual work to set up independent blog hostnames (ie blogs that are not in a subdirectory or subdomain) and for the purposes of setting updown this blog server I was more interested in keeping the blogs separate to give more flexibility down the track.

User-Friendly URLs

To support user-friendly URLs (a switch in the configuration of each blog instance) the /etc/wordpress/htaccess file needs to be updated (uncomment the first <IfModule block).

Protecting Joomla : User-Registration Spam Relay

The Problem: A Default Setting

By default user registration is enabled.

It’s important to realise that even though links to the user registration page may not have been included in the design of a Joomla site the components are still present and they will be regularly targetted by automatic spiders searching for vulnerable sites. Check access logs  for requests to paths like:

  • /index.php/shop-login
  • /index.php/shop-login?view=registration&layout=complete
  • /index.php/component/users/?view=registration
  • /index.php/component/user/?task=register
  • /index.php?option=com_user&view=register

With user registration enabled scripts can use a Joomla site as an open mail relay by registering users with target email addresses and inserting spam/attack payload into the user details. The Joomla site will send a confirmation email to the target email address, and any email tracing of the source of the email will lead directly to the weakened Joomla server.

Disable User Registration

The method varies depending on the version of Joomla, in later versions it is done as follows:

“Navigate to Users  User Manager then click on User Manager. Once in User Manager Screen, click on ‘Options’ Toolbar button to show the pop up window, as in image above. Click to fill bubble next to Allow user registration, then click save.”

Reference : Joomla Documentation: Disabling User Registration

If a site has had to be disabled due to this problem the Joomla Control Panel will not be available so the above steps are not useful. It is possible to disable user registration manually by updating the chvnp_extensions table – for name=’com_users’ (updating the JSON in the params column).

User Registration Is Still Possible

Site administrator can still add new accounts using the Joomla Control Panel under /administrator/.

Restrict Access To /adminstrator/

Speaking of Control Panel, /adminstrator/ is a known target on every Joomla website. There is no need for anyone without administrative access to have any access to that directory so at the very least add basic authentication to that directory.

Better yet, protect accesses to that directory with HTTPS to encrypt both your authentication credentials and your administrative traffic.

Site Cleanup

Once the attack vector is blocked the site will still have the new accounts left over from the attacks. Depending on how long the attack has been going on there may be many (hundreds of thousands, perhaps more) of these accounts.

Unfortunately the Joomla Control Panel does not handle a large number of accounts (read more than a couple of hundred) at all well. The default maximum number of accounts  listed “per page” is 100 and while this can be manually overridden by editing the site URL (eg. “&list[limit]=2000”) this doesn’t get you far with hundreds of thousands of accounts.

Also the process of deleting a user from a Joomla site is relatively involved with rows being deleted from a number of tables with a couple of different foreign keys in play, so just deleting the user manually is not an easy approach either.

Fortunately it’s quite easy to write a script to interact with the Control Panel (I used WWW::Mechanize) – select the user IDs that you don’t want to delete and then write a script which will remove all the others!

I’ve attached the perl script I used here: delete_joomla_users.txt

Site Modules Are Known Targets

As a footnote, and one which I’ve yet to fully explore – modules are known targets. This is not a Joomla-specific problem – once an attacker can identify the underlying system which provides a website (in particular content management systems which allow dynamic updates to content and so have more attack vectors than a static website) then known vulnerabilities can be targeted.

Other than keeping site software up to date, applying security updates and configuring the site such that it is not vulnerable (as described in this article) it’s important to keep auditing both the public contents (eg. web page contents, images, hidden embedded scripting) and private contents (eg. extra users registered).