WordPress Plugin : PHP Port Scanner

In my last post, I wrote about creating a basic WordPress Plugin that executes a reverse shell.  Neither particularly impressive about the plugin or the method I used for executing the shell but creating a plugin was new to me and I was working on something completely different when that idea just popped into my head.  After wrapping that up, another idea popped into my head -- what would it take to create a port scanner using PHP?  I did some hunting around and I found a few different ideas and then I started to cobble those ideas together.  

I iterated through different versions until I came up with the following:





Initially, I used an array based on something I saw on the interwebs but then I moved to a range because I didn't want to have to list out all of the ports.  Instead, I can simply just give it the entire port list.  I also had the output printing to the screen but then opted to push it to a file and then call that file from a redirect.  

Iterating through my various versions was fairly educational, to be honest.  My PHP game is pretty weak and this was beneficial to me in many ways.  Anyway...

When we hit our script:





The wheels spin around as it scans through all 65535 ports and then:





Not knowing exactly where I'm writing into the file system, the ?v=30 allows us to redirect to the root of the current folder.  

To keep from repeating myself, I will direct you to the previous post where I build the plugin for the steps I'm skipping.

I add the header information:




I uploaded it to the server and when it executes:





It fails because the plugin is written into the /wp-content/plugins folder and the root of the current folder is /wp-admin.  I didn't see that coming.

Because I'm lazy, I solved the directory problem by explicitly calling the location but each time I run the script, it would append the results to the output.php file which created duplicates from the previous scans.  I then went for creating a unique filename by hashing the date.  I guess technically there could be a collision but I don't think I'm going to re-run this so many times that I'd encounter that issue.  And if I did, it wouldn't be life altering.

And while not necessarily an issue per se, the scanner runs when the plugin is activated so I thought it would be cool to deactivate the plugin when the scan finishes. 

The finished product looks like this:




<?php

/**
* Plugin Name: PHP Port Scanner Plugin
* Plugin URI:
* Description: PHP Port Scanner Plugin
* Version: 1.0
* Author: Vince Matteo
* Author URI: http://www.sevenlayers.com
*/

ini_set('max_execution_time', 0);
ini_set('memory_limit', -1);
$host = 'localhost';
$ports = range(1,65535);
$filename = md5(date('Y-m-d H:i:s:u')) . ".php";

foreach ($ports as $port)
{
    $connection = @fsockopen($host, $port, $errno, $errstr, 2);
    if (is_resource($connection))
    {
        echo file_put_contents(__DIR__. '/' . $filename, '<mark>' . $host . ':' . $port . ' ' .
        '(' . getservbyport($port, 'tcp') . ') is open.</mark>' . '<p></p>', FILE_APPEND | LOCK_EX);

    fclose($connection);
  }
}

function toggle_plugin() {

    $wordpress_path = '/';
    $plugin_path = $wordpress_path.'wp-content/plugins/';
    $my_plugin = $plugin_path.'scanner/scanner.php';
    if(is_plugin_active($my_plugin)) {
    deactivate_plugins($my_plugin);
    }
}

header("Location: ../wp-content/plugins/scanner/" . $filename);

die();
?>


When we activate the plugin:





We redirect to our hashed filename. 

And when we look at the plugins:





We see that it was automatically deactivated.  

It's hard not to take this a step further but I do try to limit the amount of time I spend on these little diversions.  If I were to make a change to this, I would most definitely point this toward the network instead of just pointing it at itself. 

You could easily change the host address to an IP on the network.  It would also be fairly simple to use a host range like with the ports but I think I'd want to handle the scanning a little different in order to keep the browser from getting hung up for too long.  With a small number of hosts, it might hang for a few minutes but with a large number of hosts, I can see that being a problem.  

For now, this is a solid stopping point for me.