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: