Wordpress exploits and hardening on the server side

Discussion in 'Server Operation' started by ispcomm, Aug 3, 2021.

  1. ispcomm

    ispcomm Member

    I'd like to open a discussion about wordpress sites and their security on the recent wave of mulitiple site attacks and compromises I have to deal with.
    As it stands, more and more customers (including their "web agencies") are using wordpress without proper knowledge, using free plugins and themes of dubious quality and ultimately forgetting to update and secure their sites after the initial setup. Things like default wp-admin directory, loose permissions, writable upload directoires are common weak points.
    The result is that the sites get compromised after a few months/years and the customer starts to blame the host for not being secure enough.
    I've been struggling to find a way to secure the sites on the ispconfig server-side to try to avoid as much of the damage that is caused and hopefully be able to prevent as much damage as possible.
    Perhaps we could apply a custom server config to wordpress sites that can mitigate the damage?
    I've been looking at this article: https://wordpress.org/support/article/hardening-wordpress/ and it looks like a good starting point.
    However, several things seem hard to implement under ispconfig in a transparent to the customer way.
    There must be a way as even some cheap hosts seem more immune to "libertine" wordpress installations as we are.
    Where do we start?
  2. till

    till Super Moderator Staff Member ISPConfig Developer

    The most important thing when it comes to WordPress security is to have correct permissions for all PHP files that contain passwords like the database password, e.g. the wp-config.php file should be set to 0600 permissions. Do not give group read permissions or other read permissions to such a file!

    Regarding website rules mentioned in the guide, ISPConfig has the website directive snippets for that, you can create such a snippet for WordPress sites and the user can select it then in the website options.

    Besides that, ISPConfig runs each website's PHP process under a separate user anyway when suexec is active and all files uploaded by FTP are owned by that user, so there you are on the safe side with the default setup already.

    When it comes to FTP, you can configure pure-ftpd to allow encrypted connections only. I don't see any reason to allow just sftp (which would require a shell user account) as FTPS (FTP over SSL) is secure as well.
    foxhunter and ahrasis like this.
  3. ispcomm

    ispcomm Member

    Hi Till,
    Yes, we look like covered on most fronts, yet compromises keep happening. Hackers are very creative and determined.
    With respect to permissions, the official wp guide seems to concentrate on having the php process and the web process as separate users. But running under fpm/fcgi we actually share the user. This is good for server stability and site isolation. But wordpress insists on updating itself (good thing) and hence needs write permissions to it's own directories (dangerous). It would be better if only the FTP user could update the files on disk and wordpress could only write into selected directories, where you cannot actually execute code (I'm dreaming, users would hate this feature and not being able to click on update in the browser). Some of the attack vectors were php files uploaded in the wp-content/uploads which are then called directly as php files. these could be images with a fake extension. I'm not sure if we have protection against loading .<image-extension> files in the php interpreter (pls. confirm).
    Now, the wp-config.php is readable by the php process even with 0600 permissions, so when the php base is compromised and the hacker can execute its own script, the file-level security is out. So, all php files can be downloaded via a rough shell script uploaded by the hacker.
    In the hope of helping others, I created the apache snipped following that guide (note the missing uploads folder).
    <files wp-config.php>
      order allow,deny
      deny from all
    <IfModule mod_rewrite.c>
      <Directory {DOCROOT}>
        RewriteEngine On
        RewriteBase /
        RewriteRule ^wp-admin/includes/ - [F,L]
        RewriteRule !^wp-includes/ - [S=3]
        RewriteRule ^wp-includes/[^/]+\.php$ - [F,L]
        RewriteRule ^wp-includes/js/tinymce/langs/.+\.php - [F,L]
        RewriteRule ^wp-includes/theme-compat/ - [F,L]
    Still I think the snippet is a good way to go.
    I found something that looks promising and is called "wordpress 6g firewall" with extended rules (just google it).
    What do you think about it?
  4. till

    till Super Moderator Staff Member ISPConfig Developer

    That's exactly what ISPConfig is doing. The web process runs as www-data, the PHP process as web[X] user. That's why I mentioned that wp-config.php needs 0600 permissions and not be world readable or group readable as this would expose it to attacks.

    That's not the case on ISPConfig systems that are installed according to our install instructions plus you must have suexec enabled, which is on by default. on ISPConfig, each website runs as a separate Linux user and the webserver process has it's own user as well.

    Disabling WordPress updates is a really bad thing in my opinion and you should not consider that. Users would simply abandon your hosting if they can't install and use plugins or themes or can't install WordPress updates.

    You can't load image extensions as PHP files.

    The wp-config.php file must be readable by the PHP process, otherwise, it would be completely useless as WordPress will not work if it can't read its own config file.
    Gwyneth Llewelyn and ahrasis like this.
  5. ispcomm

    ispcomm Member

    Thanks for the quick reply, Till.
    Yes, there's separation between "apache" and "php-cgi". Unfortunately, the problems come from broken php code. The apache part (static content) is quite locked down, thankfully. So, wp-config.php would be always passed on to php and never to apache itself, and this is the reason we use .php and not .inc anymore for include files ;). And broken php code will always have access to it, unfortunately. I'm trying to mitigate the attack vectors before they can upload anything malicious. Thanks for confirming that image extensions are not interpreted as php.

    I am playing now with this 6g/7g firewall and incidentally discovered an issue. I can copy/past most of that mod_rewrite blob directly in the apache options on a site. It seems to work (at least does not break wordpress). However if I try to save a snippet for customer usage, the below code will generate a "possible attack attempt" error message in ispconfig and the snippet is not saved.
       RedirectMatch 403 (?i)(=\\\'|=\\%27|/\\\'/?)\.
       RedirectMatch 403 (?i)/(\$(\&)?|\*|\"|\.|,|&|&?)/?$
       RedirectMatch 403 (?i)(\{0\}|\(/\(|\.\.\.|\+\+\+|\\\"\\\")
       RedirectMatch 403 (?i)(~|`|</|>|:|;|,|%|\\|\{|\}|\[|\]|\|)
    This also happens on some other parts. I understand why it's intercepted, yet we would need a way to put it as a snipped anyway ;)
  6. till

    till Super Moderator Staff Member ISPConfig Developer

    You can disable IDS checks for a specific user type or all users for this input field. See /usr/local/ispconfig/security/ids.whitelist
    ahrasis and ispcomm like this.
  7. Jesse Norell

    Jesse Norell ISPConfig Developer Staff Member ISPConfig Developer

    The customers whos sites have been compromised blame you? Or other customers, for bad ip reputation? For the former you can/should disable their sites and "blame" them for not running a secure website configuration. For the latter, perhaps you can use multiple server ip's, and put the "good" sites (which presumably keep updated and don't get hacked often) on a different address than the "bad" or at least "non-good" sites. Maybe you can even think of financial incentives to help one way or the other (discount for sites demonstrably taking reasonable security efforts, or penalty for sites known insecure and/or hacked).

    Look at what server-side scanning you can put in place, some home-brew like file permissions/ownership, and others like maldet, ispprotect, etc. Wordfence is the best scanner for wordpress that I'm aware of, but I don't know of a way to run it as the webhost (they need a "hoster" edition modified for that purpose); I have wondered how well it would do if you setup a functioning wordpress install with wordfence scanning, then bind-mount the website root of each website (either one at a time, or multiple at a time) underneath that installation's web/ path - would it identify those as wp instances and scan them correctly? If so, that would be quite useful to at least email you a (long?) list of problems.

    As @till said, file permissions on wp-config.php, and check for world write permissions (users often don't have a clue what permissions mean and frequently set things world-writable) is a start. You can almost always have more strict permissions than that hardening-wordpress guide shows (in ISPConfig servers, at least), eg. start with removing read/write/execute permissions for "other" on each website directory (ie. normally "/web" except for vhost subdomain/aliasdomains).

    I've set some sites up with actual wp-config settings in a file in /private (/private/some-random/path-name.php) then throw a quick require_once() in /etc/wp-config.php to use it (security through obscurity, but it does catch some of the common automated hacks).

    You can block execution (ie. "after the fact") within uploads (and expect a very few number of poorly written plugins/themes to have an issue there - maybe let them fail, and good riddance?). As for stopping them before they upload, that requires not having vulnerabilities present, or catching the exploits while they happen - look at using mod_security for that (the core rule set has quite a few wordpress rules). In your home-brew scanning, you can certainly search for files with ".php" in the name, and run file(1) to catch common script/executable formats, and search for at least the string '<?php' in image files. You can run that type of scan periodically from a cron job, but it's also pretty easy to convert the script to run via the inotify interface, so it gets run immediately upon file upload/change. (Note maldet can scan via inotify too, which is useful with a good clamav/maldet signature database.)

    mod_security has it's own learning curve and takes a lot of initial tuning, plus some ongoing tuning - but is a perfect fit for what you want (ie. you as the hoster catching/stopping attacks). Look at log monitoring, eg. using ossec (I've not set that up yet, but it's on my "wish I had time" list). Harden your php setup as much as you can, eg. always use open_basedir, disable some of the often exploited functions, and start using chroot mode php (ensure you set validate_root option) for new sites.
    ahrasis and till like this.
  8. ispcomm

    ispcomm Member

    Jesse, I'm usually not blamed for site hacks. I'm usually asked for help after the fact, or I have to stop a site and notify the customer when I become aware, usually due to high load or sometimes straight legal talk.
    But in short, I'm trying to protect the stability of the "low profile" sites, as much as possible and my mental health. Less problems is good for business.
    You're giving some very good pointers. Thank you. Food for thought.
    Ispconfig is doing a good job isolating sites and I'm happy with that.
    I used mod_security in the past. I stopped a few years ago because it was breaking some popular CMS at the time (Jooma) and never had enough resources to implement it properly (i.e. time). If things have changed recently, I'll give it another try.
    The maldet suggestion is interesting. I'll have a look at that. Looks promising and I could probably contribute a few signatures.
  9. Jesse Norell

    Jesse Norell ISPConfig Developer Staff Member ISPConfig Developer

    Anecdotally, maldet does find things once in a while, but it's not great, surely due to the signatures. I think most clamav signatures are geared towards email, not websites. If you're writing your own, be sure to contribute them somewhere that others could use, and help us all out. :)
  10. nhybgtvfr

    nhybgtvfr Well-Known Member HowtoForge Supporter

    the biggest issue with wordpress sites is not usually the hosting server config / security, it's sites having loads of shit / abandoned / vulnerable / malicious plugins / themes installed, or nothing ever getting updated, so old code / exploits keep getting used.
    i know wordpress is now moving towards having everything self-update, purely to avoid the issue of old, unpatched vulnerabilities, personally, i don't like that. it's one of the first things i would disable.
    that's because it can update something without any notice or warning of any kind, and any single update to any single theme/plugin, or even the core, can completely break a site, and who would know?
    unless you're checking the logs of every customer site, or testing every customer site daily, you won't know a site is broken until someone tells you. yes, you could run uptime / ping tests, but they may only show that the site exists / is reachable, not that the site doesn't actually work properly.

    you can use wp-cli and cron scripts to update sites on a schedule, or use something like infinite-wp, you can update all your wordpress sites with just a couple of mouse clicks.... not only will you know exactly when a change occurred, you can also keep track of what the changes were, make troubleshooting much easier.
    so maybe that should be your thinking going forward.... rather than leaving it up to the customer, if you know they're not keeping their wordpress site up-to-date, tell them that you can keep their site updated for them, for an additional small monthly fee. turn the problem into another source of income.. ;) and avoid having customers whinging to you about their site not working in the early hours of a saturday/sunday morning. :mad:
  11. GraceFisher

    GraceFisher New Member

    Thank you for saving me a lot of time !
  12. I'd second @nhybgtvfr on his suggestion: just run wp-cli from cron or something like that to keep everything updated. You can pass parameters to wp-cli to run as different users for greater safety.
    Have you also considered making a WP security plugin mandatory? (i.e. placing it directly under mu-plugins, adding a few snippets of code to the ISPConfig website creation template).
    While I'm not familiar with many security systems myself, I've used BulletProof Security in the past (when I used Apache), which was tricky to configure but did its job well; since switching to nginx, though, I've been using Wordfence Security. One of the many useful things that Wordfence does, even on the free version, is to constantly check all files on disk to see if any of those are suspicious; in particular, it even checks all WP core files and all plugins & themes that are on the WordPress Library to see if the files match exactly — it immediately flags any file that has been tampered with, deliberately (say, a user who wanted to tweak some plugin to do something else) or not (a hacker which managed somehow to replace a valid WP file by a hacked one). It has a gazillion more options, including nice things like Two-Factor Authentication (all available for free) or a rule-based Web firewall, but it's not that heavy-weight (Jetpack is far worse, and I use it on all the websites I host...). The only disadvantage for me is that Wordfence logs everything in the MySQL database... IMHO a terrible idea, but it's one of those long-standing pet peeves that most Wordfence users have with their plugin which they deliberately ignore... the reason is simple: if allowed, they use some of those logs to identify new patterns of possible attack vectors, which are then sent to a central server, which, in turn, will update everybody's malware database... thus, an attack made on one site will be (almost) immediately blocked on millions of sites. It's not perfect, though — but it goes a long way to prevent at least script kiddies to play havoc with your installations (and yes, it will email people when their plugins or templates are out of date, as well as when someone is trying to log in with wrong credentials...).
    Anyway, as said, there are many more solutions out there (even Jetpack provides a certain degree of protection!), paid and free (or at least freemium), so that could go a long way to prevent many of the most common attacks...

Share This Page