4

This may be a duplicate post, BUT I've not seen any answer that correctly resolves this.

I'm trying to find a php script that can correctly determine the state of a TCP or UDP port.

I've tried several of the ones I've found online and they all return the wrong results. EG: On my local network I have ports 5000 UDP & 5060 TCP/UDP open and routing correctly.

If I run a test via http://www.ipfingerprints.com/portscan.php or GRC Shields Up then the correct results are returned, but all of the PHP Scripts I've tried fail and show the ports as closed.

I'm running the php script via my hosted account and trying to scan and test my own network.

This is one of the scripts I've tried:

    <html>
<head>
<?php echo "<title>Port Scanning " . $_GET['host'] . "</title>"; ?>
</head>
<body>
<?php
ini_set('display_errors', 0);

if(isset($_GET['host']) == true) 
    $host = $_GET['host'];
else
{
    echo "You didn't set the host parameter";
    die();
}

if(isset($_GET['sport']) == true) 
    $sport = $_GET['sport'];
else
{
    echo "You didn't set the sport parameter";
    die();
}

if(isset($_GET['eport']) == true) 
    $eport = $_GET['eport'];
else
{
    echo "You didn't set the eport parameter";
    die();
}

if($sport > $eport)
{
    $sport = $eport;
}

$scanned = 0;
$openports = 0;
$maxports = 1;
$totalports = ($eport - $sport) + 1;
$mins = floor(($totalports / 10) / 60);
$secs = ($totalports / 10) - $mins * 60;

echo "<font color=\"blue\">Scanning " . $totalports . " ports on " . $host . ", this should take around " . $mins . " minute(s) and " . $secs . " second(s), probably more depending on local website load, hardware, and other factors.<br/><br/></font>";
flush();

do
{
    if($scanned >= $maxports && $maxports != 0)
    {
        echo "<font color=\"darkgreen\" size=\"4\">Scan limit of " . $maxports . " ports reached, scanning stopped.</font><br/><br/><font color=\"darkred\" size=\"4\">Scanner written by Samo502</font>";
        flush();
        die();
    }
    if(fsockopen($host, $sport, $errorno, $errorstr, 0.1))
    {
        echo "<font color=\"darkgreen\">Port " . $sport . " is open on " . $host . "</font><br/>";
        $openports++;
        flush();
    }
    else
    {
        echo "<font color=\"red\">Port " . $sport . " is not open on " . $host . "</font><br/>";
        flush();
    }
    $scanned++;
    $sport++;
} while($sport <= $eport);

echo "<br/><font color=\"blue\">Done, " . $openports . " out of " . $totalports . " ports are open.</font><br/><br/><br/><font color=\"darkred\" size=\"4\">Scanner written by Samo502</font>";
die();
?>
</body>
</html>

Does anyone know of a way to do this correctly ?

Thanks

**UPDATE** I've found this which seems to work a bit better, but it's still not detecting that port 21 is currently open on my network..

http://resources.infosecinstitute.com/php-build-your-own-mini-port-scanner-2/

Any help gratefully received. Thanks

Rocket
  • 1,065
  • 2
  • 21
  • 44
  • Are you sure there's not something on your host preventing you from making outbound connections? Some hosting will prevent PHP making connections, or require the use of a proxy. Does a (limited!) version of your script work on your local machine to tell you if, say, Google has port 80 open? Also, a tenth of a second for a timeout may be a little low—what happens if you increase the connection timeout? – Matt Gibson Jun 18 '14 at 08:09
  • Looks like my host does block unless asked to open them. I'm trying the new script and that seems to work better, but still not 100% – Rocket Jun 18 '14 at 13:32

3 Answers3

2

The best solution is to write a wrapper in PHP for nmap - seriously, you can't recode a better portscan than nmap.

If you really want to do it, you should not simply open TCP port and check wether it does connect, you should start from a lower level of sockets, raw sockets.

$mysocket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

This allows you to investigate SYN, ACK handshake flags and do stealth or simply faster scans.

You can create (non-blocking) sockets in parallel and check their buffer/connection using socket_select();, which is the fastest and most reliable way to handle several sockets in PHP. I'd probably use forks or threads or dispatch parts of the code to run a full portscan within the same time as a single port scan.

Other functions you'd like to use are socket_set_timeout() and socket_set_blocking().

shell_exec not working with nmap command

https://unix.stackexchange.com/questions/28732/fastest-way-to-port-scan-nmap

http://phpnmap.sourceforge.net/

Probably the best solution, a PEAR package nmap wrapper: http://pear.php.net/package/Net_Nmap/

Community
  • 1
  • 1
Daniel W.
  • 31,164
  • 13
  • 93
  • 151
  • Thanks for the advice. This is not something I've looked at before. Do you have any links or examples that could help ? – Rocket Jun 18 '14 at 09:04
  • 1
    @user214292 You might want to look at php.net for the description and examples of the functions and then play arround with them. I've put useful links in the answer. – Daniel W. Jun 18 '14 at 09:09
  • Updated original post with an example that works, but not 100% – Rocket Jun 18 '14 at 13:32
0

Instead of

if(fsockopen($host, $sport, $errorno, $errorstr, 0.1))

Try

$connection = @fsockopen($host, $sport);
if (is_resource($connection)){
  // OK
}
ydoow
  • 2,969
  • 4
  • 24
  • 40
0

I tried the same thing on my shared hosting account and it did not work. I was able to install the PEAR packages necessary for port scan and it seemed to work for internet websites like "yahoo.com" but not for any of the ports I wanted. I ended up setting up a separate Virtual machine with APACHE and PEAR packages installed and now the code works just fine. Here you can try it for yourself:

www.admin-toolkit.com/port_scan.html (dead link)

Here is the code for that. First, assign a value to $scanhost, $port and $timeout (in seconds), then:

$status = Net_Portscan::checkPort($scanhost, $port, $timeout);

$servicename = Net_Portscan::getService($port);

if ($status == NET_PORTSCAN_SERVICE_FOUND) {
    if($servicename == null)
        echo $port.": OPEN ".PHP_EOL;
   else
        echo $port." (".$servicename .") : OPEN ".PHP_EOL;
   }
else{
   if($servicename == null)
      echo $port.": CLOSED".PHP_EOL;
   else
      echo $port." (".$servicename ."): CLOSED".PHP_EOL;
}
ashleedawg
  • 20,365
  • 9
  • 72
  • 105
ajiratech
  • 11
  • 1