Sunday 27 December 2009

Writing a Port Scanner In PHP

How to write a Port Scanner in PHP

I am pretty new to PHP but one of the things I like about PHP as opposed to other server side scripting languages such as ASP Classic (JavaScript or VBScript) is the amount of functionality that is built into the language. 

With ASP Classic if you want to do anything remotely sexy you have to write a COM component and then register the DLL on the web server which most tech support teams hate to do when they know its a custom COM component so it can be quite a pain to do anything on a socket level, Reverse DNS checks, Whois checks and other functions that are easy to do in PHP.

One of the things I liked about PHP was its socket functionality and I stumbled across a couple of Port Scanner tools on the web however they seemed to give incorrect results when running them against sites where I knew the open ports.

Whether this was due to the firewall running on their webserver preventing access to certain ports I do not know. However to validate whether your port scan results are correct you should run the following test on the server you want to scan to list out all the public ports that are currently listening:

C:\DOCUME~1\me>netstat -a

Active Connections

Proto  Local Address          Foreign Address        State
TCP    somecomputer:http       somecomputer.steel.mydomain.co.uk:0  LISTENING
TCP    somecomputer:epmap      somecomputer.steel.mydomain.co.uk:0  LISTENING
TCP    somecomputer:microsoft-ds  somecomputer.steel.mydomain.co.uk:0  LISTENING
TCP    somecomputer:1032       somecomputer.steel.mydomain.co.uk:0  LISTENING
TCP    somecomputer:1110       somecomputer.steel.mydomain.co.uk:0  LISTENING
TCP    somecomputer:pptp       somecomputer.steel.mydomain.co.uk:0  LISTENING
TCP    somecomputer:2869       somecomputer.steel.mydomain.co.uk:0  LISTENING
TCP    somecomputer:3306       somecomputer.steel.mydomain.co.uk:0  LISTENING
TCP    somecomputer:6670       somecomputer.steel.mydomain.co.uk:0  LISTENING
TCP    somecomputer:netbios-ssn  somecomputer.steel.mydomain.co.uk:0  LISTENING
TCP    somecomputer:1161       10.0.7.168:3389        ESTABLISHED
TCP    somecomputer:1036       somecomputer.steel.mydomain.co.uk:0  LISTENING
TCP    somecomputer:1110       localhost:4809         ESTABLISHED
TCP    somecomputer:1110       localhost:4857         TIME_WAIT
TCP    somecomputer:1110       localhost:4863         TIME_WAIT


This is just a snapshot of the full output you would expect to get. However for those ports on the server you are checking that appear as LISTENING and who don't have a foreign address that ends in port number of zero then a port scanner tool with full access should be able to find them.

The tool you need to use in PHP for this exercise is the fsockopen function which allows you to open a socket to a port. You can then read in any default response which certain ports will give you whereas for others you will not get any response unless you send a valid request first in a similar way to a Telnet conversation.

You can also check whether a port on a server should respond to a port scan by running a Telnet session on the command prompt e.g

C:\DOCUME~1\me>telnet www.google.com 80

If you do not get a timeout response then you have an open port.

The PHP port scanner script I wrote can be downloaded here: portscanner.php
To get the best out of it and not be blocked by your public webservers firewall run it from your localhost e.g:

http://127.0.0.1/portscanner.php
or
http://localhost/portscanner.php

Enter in the domain or IP you are wanting to port scan and then hit run.
For example port scanning one of my sites with this tool returns the following results (I am only showing a few of the results).

The Port is shown in the left hand side column and the right hand side will show either Closed and the error message if the port could not be accessed or Open and any response from the Port or "none" if none was returned.
PortStatus
20 - FTP-Data Closed - Timeout
21 - FTP Closed - Timeout
22 - SSH Open - SSH-2.0-OpenSSH_5.1p1 Debian-5
23 - Telnet Closed - Timeout
25 - SMTP Open - 220 aero.mysite.com ESMTP Postfix (Debian/GNU)
37 - Time Closed - Timeout
53 - DNS Open - none

The main bit of code is here:
// open the port on the required host and set a timeout to 1 second.
$fp = fsockopen($url, $port, $errno, $errstr, 1);

// check whether object is a valid resource
if (is_resource($fp)){

// check for a response back from the port
$response = trim(fread($fp,4096)); 

Let me know of any problems with it and don't go using it for nefarious means.

Remember hacking is illegal and is actually now considered as terrorism in certain countries. So if you don't want to end up in an orange jump suit being water boarded then don't go off port scanning US military installation networks or you will end up like Gary McKinnon!

No comments: