lunedì 6 febbraio 2012

Port Knocking via web, Web Knocking!

Port knocking is an ingenious practice used when you want open firewall port through a predefined sequence of SYN packets to closed port. However listen to SYN packages to close port can be a weight process, specially if your system already expose a web server.

What I made is to translate the concept behind port knocking to web, instead of knocking a sequence of pre-shared port number, I send an HTTP POST with a MD5 hash of a pre-shared password plus a timestamp. A flow diagram can make my idea more clearly.




First, I have created a script to make the POST request, open-firewall.sh:

 #!/bin/sh  
 KEY=`echo SharedKey$(date +%Y%m%d%H%M) | md5sum | awk '{print $1}'`  
 wget --post-data="key=$KEY" http://SERVER/webknocking.php --delete-after  

This file contains the per-shared password (MyKey in this case) and a wget to system.

On server side, I have a file named webknocking.php that catch the key and request's source IP  and pass them to a script for verify and open firewall:

 <?php  
 $key = $_POST['key'];  
 $ip = $_SERVER['REMOTE_ADDR'];  
 $cmd = 'sudo /var/dev.zonablog.net/openfirewall-300min.sh '.$key.' '.$ip.' >> /var/log/knock.log &';  
 shell_exec($cmd);  
 ?>  
 Request forwarded.  

Notice that I call the bash script with sudo because the user that run the PHP is apache, that doesn't have rigth to change firewall configuration (iptables).
Insert into sudoers the row:

 apache     ALL=      NOPASSWD: /var/dev.zonablog.net/openfirewall-300min.sh  

to give the rigth to apache to run the script below as root. The content of openfirewall-300min.sh is:

 #!/bin/bash  
 echo " "  
 echo $(date) "Verifico Ip "$2", Key "$1  
 KEY=`echo SharedKey$(date +%Y%m%d%H%M) | md5sum | awk '{print $1}'`  
 KEY_1m=`echo SharedKey$(date --date='1 minute ago' +%Y%m%d%H%M) | md5sum | awk '{print $1}'`  
 if [ $1 != $KEY -a $1 != $KEY_1m ]  
  then  
   echo $(date) "Respingo Ip "$2", Key "$1  
   exit 1  
 fi  


 # open firewall  
 echo $(date) "Ok, apro per 5 ore"  
 /sbin/iptables -I INPUT -j ACCEPT -i eth0 -p tcp -s $2  
 sleep 180000  


 # deny incoming packets  
 echo $(date) "Chiudo a Ip "$2", Key "$1  
 /sbin/iptables -D INPUT -j ACCEPT -i eth0 -p tcp -s $2  

This file check the key of request and if it is valid, open firewall to that ip for 5 hours. The log of this operation are put in /var/log/knock.log, create this file and change the owner to apache:

 # touch /var/log/knock.log  
 # chown apache.apache /var/log/knock.log  

This is it, folks!