Using Phpseclib Instead of Disallowed PHP exec

Many web hosts disable a handful of built-in PHP functions like exec for security sake. And for good reason. If your website would ever run harmful PHP code, having access to exec would be quite dangerous. As a developer, being able to use exec would open up many possibilities. I mean literally any command line application could be directly accessed from PHP without needing an external server. So the big question, is there a way to safely run command line applications from PHP?

Well… maybe. 🤔

Creating a SSH tunnel to localhost with Phpseclib

I previously explained how you can use Phpseclib to run code on a remote SSH server. Phpseclib is a PHP library which works as a fully functional SSH client. Well today I’m taking a new twist and will be utilizing Phpseclib to create a secured SSH tunnel to localhost. Kinsta is my host provider, so the steps to get this working may vary with other host providers. This also requires SSH capabilities which not all web hosts support.

Start by creating a new empty directory within the private folder. It can be named whatever you want, I’ll use phpseclib/. Then use composer to load in the Phpseclib library.

mkdir private/phpseclib
cd private/phpseclib
composer require phpseclib/phpseclib:~2.0

Next create a new PHP file phpseclib.php loaded with SSH username and password. The port number isn’t required as this SSH request will be coming from inside the server itself, not an outside request.

<?php
require __DIR__ . '/vendor/autoload.php';
use phpseclib\Net\SSH2;
$ssh = new SSH2( '127.0.0.1' );
if ( !$ssh->login( 'username', 'password' ) ) {
   exit( 'Login Failed' );
}
echo $ssh->exec( "pwd" );

Now try this out using WP-CLI and it should return the results of pwd from the command line.

cd ~/public/
wp eval-file ~/private/phpseclib/phpseclib.php

Rclone concept powered by local SSH requests.

The above example simple ran pwd to return the current path. Not very useful and not very smart leaving credentials lying around in files. Let’s take a look at something a bit more powerful like Rclone, my favorite command line application.

First we need to prepare Rclone by downloading and configuring an empty rclone.conf file. We won’t actually be installing Rclone. Instead we will be referencing the binary directly. The empty config file will simply trick Rclone in being okay with with the fact that it’s not installed in the default place.

cd ~/private
wget https://downloads.rclone.org/rclone-current-linux-amd64.zip
unzip rclone-current-linux-amd64.zip
cd private/rclone-v*/
touch rclone.conf

Now the fun part, let’s build out this functionality within a WordPress plugin.

cd ~/public
wp scaffold plugin rclone-concept --plugin_name="Rclone Concept"
cd wp-content/plugins/rclone-concept/
composer require phpseclib/phpseclib:~2.0

Then update the file wp-content/plugins/rclone-concept/rclone-concept.php to this code: https://gist.github.com/austinginder/783802bd617fb9d18fd0ac0c716304ea. This will add a new page on the WordPress backend where you can enter an Rclone subcommand, SSH username, SSH password and then see the response.

Rclone is crazy powerful. Long running commands are going to have issues running via Phpseclib however, those could be handled as a background process. Also dealing with too much output can get tricky. That said, this truly opens up WordPress to a world of possibilities.

Is this a good idea? Is this safe?

This approach is not a good solution for the majority of use cases. You need a really specific reason to even consider using your own SSH credentials in order to run a command line application. It is safer than the PHP’s exec command, however it comes with a few warnings.

SSH credentials are best not stored anywhere in the database or the file system. If your website were ever to run harmful PHP code, then your SSH credentials could be comprised. My workaround is to manually enter SSH credentials which are passed along using a secured HTTPS web request. They are never stored.

This method has one safety feature built in. The SSH request never leaves the server. So at least that part of the process is completely safe. Just be careful using your SSH credentials and enjoy! 🎉