How To Install PHP SSH2 Extension for WordPress updates.

If you are running WordPress on Ubuntu 16.04 or above you will need this to allow you to update securely over SSH. If you are not yet running on php7.0 then skip installing php7.0-cli  as it will probably break your install, but SSH should still work on the older version with nothing else added.

It’s pretty simple, all you need to do is update apt repositories.

sudo apt-get update

then

sudo apt-get install php7.0-cli -y

and

sudo apt-get install libssh2-1 php-ssh2 -y

And that’s it.

For a guide on setting up your ssh keys go here for instructions on that.

Change WordPress url from mysql

I made a mistake when configuring a WordPress url and could no longer access the site to rectify the issue!

If you are as dumb as I was and need to change the url when you can’t access the WordPress admin panel you can follow these instructions if you have access to the database.

Login over ssh or access the Terminal and login to mysql using your username and password.

mysql -u dbuser -p

Enter password when prompted then select your wordpress database by name. (Yours may be named differently)

mysql> use wordpress;

You can then show all the tables if you wish.

mysql> show tables;

We need to select the 2 url entries from the database and change them to what we want.

if you know the value that is currently being used you can search for that value. (Change the url for yours)

mysql> select * from wp_options where option_value = 'http://wrongvalue.co.uk';

If not you can search by LIKE

mysql> select * from wp_options where option_value LIKE 'http://wrongvalue.co.uk';

Here you can make sure this is the correct entry you wish to change.

Then use the option id of the column you need to change like this.

mysql> update wp_options set option_value = 'http://correctvalue.co.uk' where option_id = 1;

Make sure you do this for both entries and you’re all done.

New HTTP Header “Referrer Policy”

Another blog by @Scott_Helme here on a new http header we need to be setting so our users info is not leaked to third parties when using a link to another site from our own.

It’s pretty simple, and we are using WordPress on nginx for this example.

First we go to our config file.

sudo nano /etc/nginx/sites-available/default

Then below our existing headers we simply add

add_header Referrer-Policy "strict-origin-when-cross-origin";

then restart nginx and we’re done.

sudo systemctl restart nginx

There are several different options and if you are unsure you should check out the previously mentioned article for a thorough explanation.

How to generate and install SSL certificate in nginx running WordPress

You’ve got your site running on https with a self-signed certificate but it’s time to get one signed by a Certificate authority. If you haven’t already configured your server for https then follow the guide here.

The first thing we need to do is create the private key and csr file. The private key stays on the server, and the csr file is sent to the certificate authority for signing.

First let’s make our directory for the certificates.

sudo mkdir /etc/nginx/certificates/{ssl.key,ssl.crt}

And cd to the new certificates dir

cd /etc/nginx/certificates

Then we run (install openssl if you haven’t already got it)

sudo openssl req -nodes -newkey rsa:2048 -keyout yoursite.key -out yoursite.csr

You will need to answer the questions, and for most of them the answer doesn’t matter. The real important one is “Common Name”. This has to be the name of your website. For example: yoursite.com

If this doesn’t match the name of your site then when anyone goes to your site they will receive a warning that the certificate name doesn’t match the site name.

Now you need to go to where are getting the Certificate from and request a certificate. You will then need to cut and paste all the text from the .csr file into the request. This includes –BEGIN CERTIFICATE– and –END CERTIFICATE–

Once the request is complete you need to download your new certificate as a .crt file and you will probably also have to download the intermediate certificate also as a .crt or .pem.

If there is an intermediate cert you will need to merge them with the following command, or simply copy and paste the text from the intermediate certificate into your site cert.

sudo cat intermediate.pem >> yoursite.crt

Then you need to copy yoursite.key to /etc/nginx/certificates/ssl.crt and yoursite.crt /etc/nginx/certificates/ssl.crt by going to the directory you have the files saved and running

sudo cp yoursite.crt /etc/nginx/certificates/ssl.crt

sudo cp yoursite.key /etc/nginx/certificates/ssl.key

Then in your config file you reference the se locations so the server knows which key and crt file to use.

For example

sudo nano /etc/nginx/sites-available/default

Then add the locations in the SSL Server tags as below

ssl on;

ssl_certificate /etc/nginx/certificates/ssl.crt/yoursite.crt; ssl_certificate_key /etc/nginx/certificates/ssl.key/yoursite.key;

Save the changes then retsrat the webserver service

sudo systemctl restart nginx

Now browse to your site over https.

Moving WordPress to https

It’s time to move your sites over to https. Again for this example we will be using a LEMP stack on Ubuntu 16.04.2.

First thing is to open the firewall to allow traffic on port 443. (Here I’m using ufw)

sudo ufw allow https

Then we can check to ensure the port is open with the following.

sudo ufw status

Once we’ve done that we add the following to our config file.

For nginx this is /etc/nginx/sites-available

To open the file

sudo nano yoursite

SSL configuration
server {
access_log off;
log_not_found off;
error_log  logs/yoursite.com-error_log warn;

        listen 443 ssl;
        server_name  yoursite.com; 

 ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
 ssl_prefer_server_ciphers On;
 ssl_ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:
DH+AES256:
ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:
RSA+AES:
RSA+3DES:!aNULL:!MD5:!DSS;
ssl_certificate /etc/nginx/cert/crt/yoursite.crt;
ssl_certificate_key /etc/nginx/cert/key/yoursite.key;

The “ssl_certificate” and “ssl_certificate_key” entries are the key and certificate that you have generated on the server and had signed by a certificate authority. If you don’t have these then you can check out our guide on how to do this here.

Now you will be able to access the site over both http and https.

How to update WordPress over SSH

You should definitely be updating over an encrypted connection, so with that in mind, let’s proceed.

Run the following command, and answer all the questions.

sudo adduser wp-admin

Next we need to change ownership of the directory, so we run

cd /var/www/html

sudo chown -R wp-admin:wp-admin /var/www/html

Now we create the SSH keys, while logged in as the new user

sudo su - wp-admin

ssh-keygen -t rsa -b 4096

Save them on the server, for example

sudo /home/wp-admin/wp_rsa

Then go back to your normal account with the following

exit

Then we lock down the permissions

sudo chown wp-user:www-data /home/wp-user/wp_rsa*

sudo chmod 0640 /home/wp-user/wp_rsa*

Now we create a new directory, and set permissions for storing the keys to allow remote login

sudo mkdir /home/wp-user/.ssh

sudo chown wp-user:wp-user /home/wp-user/.ssh/

sudo chmod 0700 /home/wp-user/.ssh/

Then we copy the keys over to the new directory

sudo cp /home/wp-user/wp_rsa.pub /home/wp-user/.ssh/authorized_keys

Then we lock down the new files

sudo chown wp-user:wp-user /home/wp-user/.ssh/authorized_keys
sudo chmod 0644 /home/wp-user/.ssh/authorized_keys

Then we lock down to local login only

sudo nano /home/wp-user/.ssh/authorized_keys

Put the following at the top of the file

 from="127.0.0.1"

Now we update the wp-config file, open with the following

sudo nano /var/www/html/wp-config.php

Then add these lines to the file

define('FTP_PUBKEY','/home/wp-user/wp_rsa.pub');

define('FTP_PRIKEY','/home/wp-user/wp_rsa');

define('FTP_USER','wp-user');

define('FTP_PASS','');

define('FTP_HOST','127.0.0.1:22');

Then restart nginx

sudo systemctl restart nginx

Then next time you need to update select ssh enter your new wp-admin user details and you should be good to go.

Before we finish more thing.

As we have locked down the permissions quite tightly you may need to change ownership of the html folder temporarily while running updates, and then reinstate the locked down permissions and you do this by running the following.

Before updating run.

sudo chown -R www-data /var/www/html

Then once your done

sudo chown -R wp-admin /var/www/html

Protect WordPress Login page and admin panel

If you run a WordPress site and have any knid of network monitoring you’ll see endless brute force attempts on your login page.

A strong password will only do so much, so really you want the login page to only be available to legitimate IP adresses.

This is easy to achieve and offers great protection as if someone requests the login page but they are not connecting from a listed IP the page will not show.

First we need to go to our active config file. On LEMP running wordpress we go to.

sudo nano /etc/nginx/sites-enabled/wordpress

Then we add the following to our server block in its own location container. (Replace 11.11.11.111 with your own IP)

location ~ ^/(wp-admin|wp-login.php){

allow 11.11.11.111;

deny all;}

And that’s it. You can access your login page and admin panel, but it’s not vailable to the rest of the internet. If your site is not using https then you should seriously consider setting up a VPN to login and administer your site.

 

 

Custom HTTP Headers (nginx, WordPress)

If you have a website and you are not implementing some custom headers you may want to look into it. These are not set by default and can help in protecting your site from all types of attacks.

To start with go to https://securityheaders.io/ and scan your site. If you have none of these headers implemented your site will score very poorly. Don’t forget with these headers we aren’y only protecting our site, but also our site visitors as well.

The ones we are going to look at are for protecting against Cross-Site-Scripting, malicious content, drive-by downloads, and stop your site being viewed in an iframe.  We will also stop the site advertising Server and software details, for example the Server build, and php version. The reason for this is not covered here but if you are intersted you can go here and read this brilliant  article by @Scott_Helme.

For today we will be concetrating on WordPress installed on LEMP stack. Firstly we need to backup our config, and then go to our active config file. (yours may be different depending on your setup). Also note that the Strict Transport Security header is for https sites only.

sudo nano /etc/nginx/sites-enabled/wordpress

Then in our http server block we add the following. ( if using https on your site then put the headers in both blocks.

add_header X-Frame-Options "SAMEORIGIN";

add_header Content-Security-Policy "default-src yoursite.com";

add_header X-Xss-Protection "1; mode=block";

add_header X-Content-Type-Options "nosniff";

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

server_tokens off;

You can see the layout in the screenshot.

We save the changes then run the following to test for typo’s.

sudo nginx -t

Then

sudo service nginx restart

Finally we go change a setting in the php.ini file for our version to disable version broadcast.

sudo nano /etc/php5/fpm/php.ini

We need to change

expose_php = on

To

expose_php = off

Save and close the file and restart php

sudo service php5-fpm restart

To check all this is working correctly go back to Security Headers and check your site again. Your sites rating should be significantly better.

More WordPress Issues

It seems barely a week goes by without having to resolve a WordPress Issue. I needed to update to version 4.8, so I went to my update panel ready to use the “one click” update, but instead of opening up the update page informing me that the site is in update mode it opened to a blank page. After refreshing and returning to the update panel, I disabled all pluggins and tried again, now whenever clicking the update button I was greeted with a message telling me an update was in progress, I therefore it left it expecting that it would just eventually complete. However 12 hours later and WordPress was still not updated and clicking the update buttomn gave the same message that an update was already in process! Restarted the server no change, a bit of googling led me to https://wordpress.stackexchange.com/questions/224989/get-rid-of-another-update-is-currently-in-progress  I therefore installed wp-cli using this guide https://www.sitepoint.com/wp-cli/ and tried in vain to carry out these steps. However I was continually told by wp-cli that wp-config.php did not exist! I checked and this was not the case, so another brick wall! I had already wasted an hour by this point on what should have been a ten minute job. Therefore I simply downloaded the latest WordPress version by running

wget http://wordpress.org/latest.tar.gz

then (from the same dir)

tar xzvf latest.tar.gz

then

sudo rsync -avP ~/wordpress/ /var/www/html/

As I had manually created an uploads directory I had to reassign group ownership to allow me to upload content to that directory using the following.

sudo chown -R :www-data /var/www/html/wp-content/uploads

Hey presto! we are now running on the latest version, with all existing pluggins and content still working. (I double-checked by running wpscan from my kali box just to be sure I was on the latest version) Hope this helps someone else out. Don’t forget to backup before running these steps.

 

 

Issues Migrating WordPress Sites

I recently had to change the internal IP range of my network and that included my WordPress hosting server. I thought that I could just update the database and config file and the site would work, wrong!! The home page would display but every page and link was broken and there was no formatting and the uploaded content no longer displayed. Also when trying to login the site was still trying to access the old url as I was accessing the site by IP as it was only a testing site. I never did manage to fix the error despite an hour of my time, in the end I just had to create the a new site on the new IP and then copy the content over.If anyone else has come across this and knows how to resolve it please let me know!